PoPL/02_syntax/main.py

187 lines
5.2 KiB
Python

#!/bin/env python3
import argparse
import ply.lex as lex
import ply.yacc as yacc
import lexer
# Simple debuggin function to call from syntax rules
symbolnum = 0
def debug_print(p):
global symbolnum
symbolnum += 1
p[0] = symbolnum
msg = ''
for i, s in enumerate(p.slice):
if s is not None:
if type(s) is lex.LexToken:
msg += str(s.type) + '<' + str(s.value) + '> '
else:
msg += str(s) + '(' + str(p[i]) + ') '
else:
msg += '?? '
if i == 0:
msg += ':: '
print(msg)
tokens = lexer.tokens
def p_program(p):
'''program : statement_list
| definitions program'''
debug_print(p)
def p_statement_list(p):
'''statement_list : statement
| statement COMMA statement_list'''
debug_print(p)
def p_definitions(p):
'''definitions : function_definition
| procedure_definition
| variable_definition'''
debug_print(p)
def p_variable_definition(p):
'''variable_definition : VAR IDENT EQ expression'''
debug_print(p)
def p_empty(p):
'''empty :'''
debug_print(p)
def p_opt_formals(p):
'''opt_formals : empty
| formals'''
debug_print(p)
def p_opt_variable_defitions(p):
'''opt_variable_definitions : empty
| variable_definition opt_variable_definitions'''
debug_print(p)
def p_function_definition(p):
'''function_definition : FUNCTION FUNC_IDENT LCURLY opt_formals RCURLY RETURN IDENT opt_variable_definitions IS rvalue END FUNCTION'''
debug_print(p)
def p_procedure_definition(p):
'''procedure_definition : PROCEDURE PROC_IDENT LCURLY opt_formals RCURLY opt_variable_definitions IS statement_list END PROCEDURE
| PROCEDURE PROC_IDENT LCURLY opt_formals RCURLY RETURN IDENT opt_variable_definitions IS statement_list END PROCEDURE'''
debug_print(p)
def p_formals(p):
'''formals : formal_arg
| formal_arg COMMA formals'''
debug_print(p)
def p_formal_arg(p):
'''formal_arg : IDENT LSQUARE IDENT RSQUARE'''
debug_print(p)
def p_procedure_call(p):
'''procedure_call : PROC_IDENT LPAREN RPAREN
| PROC_IDENT LPAREN arguments RPAREN'''
debug_print(p)
def p_arguments(p):
'''arguments : expression
| expression COMMA arguments'''
debug_print(p)
def p_assignment(p):
'''assignment : lvalue EQ rvalue'''
debug_print(p)
def p_lvalue(p):
'''lvalue : IDENT
| IDENT DOT IDENT'''
debug_print(p)
def p_rvalue(p):
'''rvalue : expression
| unless_expression'''
debug_print(p)
def p_print_statement(p):
'''print_statement : PRINT print_item
| print_statement AMPERSAND print_item'''
debug_print(p)
def p_print_item(p):
'''print_item : STRING
| expression'''
debug_print(p)
def p_statement(p):
'''statement : procedure_call
| assignment
| print_statement
| DO statement_list UNTIL expression
| DO statement_list UNLESS expression DONE
| DO statement_list UNLESS expression OTHERWISE statement_list DONE
| RETURN expression'''
debug_print(p)
def p_expression(p):
'''expression : simple_expr
| expression EQ simple_expr
| expression LT simple_expr'''
debug_print(p)
def p_simple_expr(p):
'''simple_expr : term
| simple_expr PLUS term
| simple_expr MINUS term
term : factor
| term MULT factor
| term DIV factor
factor : atom
| MINUS atom
| PLUS atom
atom : IDENT
| IDENT APOSTROPHE IDENT
| INT_LITERAL
| DATE_LITERAL
| function_call
| procedure_call
| LPAREN expression RPAREN'''
debug_print(p)
def p_function_call(p):
'''function_call : FUNC_IDENT LPAREN RPAREN
| FUNC_IDENT LPAREN arguments RPAREN'''
debug_print(p)
def p_unless_expression(p):
'''unless_expression : DO expression UNLESS expression OTHERWISE expression DONE'''
debug_print(p)
def p_error(p):
if p is not None:
print(f"{{{p.lineno}}}:Syntax Error (token:'{p.value}')")
else:
print('Syntax Error at the end of file')
raise SystemExit
def syntax_check_file(file_path: str, debug: bool):
parser = yacc.yacc()
with open(file_path, 'r', encoding='utf-8') as file:
parser.parse(file.read(), lexer=lexer.lexer, debug=debug)
print('syntax OK')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debug', action='store_true', help='debug?')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--who', action='store_true', help='print out student IDs and NAMEs of authors')
group.add_argument('-f', '--file', help='filename to process')
args = parser.parse_args()
if args.who:
print('Author')
print(' Student ID: 150189237')
print(' Name: Oskari Alaranta')
else:
syntax_check_file(args.file, args.debug)