from ply import *
import basiclex
tokens = basiclex.tokens
precedence = (
('left', 'PLUS', 'MINUS'),
('left', 'TIMES', 'DIVIDE'),
('left', 'POWER'),
('right', 'UMINUS')
)
def p_program(p):
if len(p) == 2 and p[1]:
p[0] = {}
line, stat = p[1]
p[0][line] = stat
elif len(p) == 3:
p[0] = p[1]
if not p[0]:
p[0] = {}
if p[2]:
line, stat = p[2]
p[0][line] = stat
def p_program_error(p):
p[0] = None
p.parser.error = 1
def p_statement(p):
if isinstance(p[2], str):
print("%s %s %s" % (p[2], "AT LINE", p[1]))
p[0] = None
p.parser.error = 1
else:
lineno = int(p[1])
p[0] = (lineno, p[2])
def p_statement_interactive(p):
p[0] = (0, (p[1], 0))
def p_statement_blank(p):
p[0] = (0, ('BLANK', int(p[1])))
def p_statement_bad(p):
print("MALFORMED STATEMENT AT LINE %s" % p[1])
p[0] = None
p.parser.error = 1
def p_statement_newline(p):
p[0] = None
def p_command_let(p):
p[0] = ('LET', p[2], p[4])
def p_command_let_bad(p):
p[0] = "BAD EXPRESSION IN LET"
def p_command_read(p):
p[0] = ('READ', p[2])
def p_command_read_bad(p):
p[0] = "MALFORMED VARIABLE LIST IN READ"
def p_command_data(p):
p[0] = ('DATA', p[2])
def p_command_data_bad(p):
p[0] = "MALFORMED NUMBER LIST IN DATA"
def p_command_print(p):
p[0] = ('PRINT', p[2], p[3])
def p_command_print_bad(p):
p[0] = "MALFORMED PRINT STATEMENT"
def p_optend(p):
if len(p) == 2:
p[0] = p[1]
else:
p[0] = None
def p_command_print_empty(p):
p[0] = ('PRINT', [], None)
def p_command_goto(p):
p[0] = ('GOTO', int(p[2]))
def p_command_goto_bad(p):
p[0] = "INVALID LINE NUMBER IN GOTO"
def p_command_if(p):
p[0] = ('IF', p[2], int(p[4]))
def p_command_if_bad(p):
p[0] = "BAD RELATIONAL EXPRESSION"
def p_command_if_bad2(p):
p[0] = "INVALID LINE NUMBER IN THEN"
def p_command_for(p):
p[0] = ('FOR', p[2], p[4], p[6], p[7])
def p_command_for_bad_initial(p):
p[0] = "BAD INITIAL VALUE IN FOR STATEMENT"
def p_command_for_bad_final(p):
p[0] = "BAD FINAL VALUE IN FOR STATEMENT"
def p_command_for_bad_step(p):
p[0] = "MALFORMED STEP IN FOR STATEMENT"
def p_optstep(p):
if len(p) == 3:
p[0] = p[2]
else:
p[0] = None
def p_command_next(p):
p[0] = ('NEXT', p[2])
def p_command_next_bad(p):
p[0] = "MALFORMED NEXT"
def p_command_end(p):
p[0] = ('END',)
def p_command_rem(p):
p[0] = ('REM', p[1])
def p_command_stop(p):
p[0] = ('STOP',)
def p_command_def(p):
p[0] = ('FUNC', p[2], p[4], p[7])
def p_command_def_bad_rhs(p):
p[0] = "BAD EXPRESSION IN DEF STATEMENT"
def p_command_def_bad_arg(p):
p[0] = "BAD ARGUMENT IN DEF STATEMENT"
def p_command_gosub(p):
p[0] = ('GOSUB', int(p[2]))
def p_command_gosub_bad(p):
p[0] = "INVALID LINE NUMBER IN GOSUB"
def p_command_return(p):
p[0] = ('RETURN',)
def p_command_dim(p):
p[0] = ('DIM', p[2])
def p_command_dim_bad(p):
p[0] = "MALFORMED VARIABLE LIST IN DIM"
def p_dimlist(p):
if len(p) == 4:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = [p[1]]
def p_dimitem_single(p):
p[0] = (p[1], eval(p[3]), 0)
def p_dimitem_double(p):
p[0] = (p[1], eval(p[3]), eval(p[5]))
def p_expr_binary(p):
p[0] = ('BINOP', p[2], p[1], p[3])
def p_expr_number(p):
p[0] = ('NUM', eval(p[1]))
def p_expr_variable(p):
p[0] = ('VAR', p[1])
def p_expr_group(p):
p[0] = ('GROUP', p[2])
def p_expr_unary(p):
p[0] = ('UNARY', '-', p[2])
def p_relexpr(p):
p[0] = ('RELOP', p[2], p[1], p[3])
def p_variable(p):
if len(p) == 2:
p[0] = (p[1], None, None)
elif len(p) == 5:
p[0] = (p[1], p[3], None)
else:
p[0] = (p[1], p[3], p[5])
def p_varlist(p):
if len(p) > 2:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = [p[1]]
def p_numlist(p):
if len(p) > 2:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = [p[1]]
def p_number(p):
p[0] = eval(p[1])
def p_number_signed(p):
p[0] = eval("-" + p[2])
def p_plist(p):
if len(p) > 3:
p[0] = p[1]
p[0].append(p[3])
else:
p[0] = [p[1]]
def p_item_string(p):
p[0] = (p[1][1:-1], None)
def p_item_string_expr(p):
p[0] = (p[1][1:-1], p[2])
def p_item_expr(p):
p[0] = ("", p[1])
def p_empty(p):
def p_error(p):
if not p:
print("SYNTAX ERROR AT EOF")
bparser = yacc.yacc()
def parse(data, debug=0):
bparser.error = 0
p = bparser.parse(data, debug=debug)
if bparser.error:
return None
return p