Path: blob/main/third_party/ply/example/BASIC/basparse.py
7087 views
# An implementation of Dartmouth BASIC (1964)1#23from ply import *4import basiclex56tokens = basiclex.tokens78precedence = (9('left', 'PLUS','MINUS'),10('left', 'TIMES','DIVIDE'),11('left', 'POWER'),12('right','UMINUS')13)1415#### A BASIC program is a series of statements. We represent the program as a16#### dictionary of tuples indexed by line number.1718def p_program(p):19'''program : program statement20| statement'''2122if len(p) == 2 and p[1]:23p[0] = { }24line,stat = p[1]25p[0][line] = stat26elif len(p) ==3:27p[0] = p[1]28if not p[0]: p[0] = { }29if p[2]:30line,stat = p[2]31p[0][line] = stat3233#### This catch-all rule is used for any catastrophic errors. In this case,34#### we simply return nothing3536def p_program_error(p):37'''program : error'''38p[0] = None39p.parser.error = 14041#### Format of all BASIC statements.4243def p_statement(p):44'''statement : INTEGER command NEWLINE'''45if isinstance(p[2],str):46print("%s %s %s" % (p[2],"AT LINE", p[1]))47p[0] = None48p.parser.error = 149else:50lineno = int(p[1])51p[0] = (lineno,p[2])5253#### Interactive statements.5455def p_statement_interactive(p):56'''statement : RUN NEWLINE57| LIST NEWLINE58| NEW NEWLINE'''59p[0] = (0, (p[1],0))6061#### Blank line number62def p_statement_blank(p):63'''statement : INTEGER NEWLINE'''64p[0] = (0,('BLANK',int(p[1])))6566#### Error handling for malformed statements6768def p_statement_bad(p):69'''statement : INTEGER error NEWLINE'''70print("MALFORMED STATEMENT AT LINE %s" % p[1])71p[0] = None72p.parser.error = 17374#### Blank line7576def p_statement_newline(p):77'''statement : NEWLINE'''78p[0] = None7980#### LET statement8182def p_command_let(p):83'''command : LET variable EQUALS expr'''84p[0] = ('LET',p[2],p[4])8586def p_command_let_bad(p):87'''command : LET variable EQUALS error'''88p[0] = "BAD EXPRESSION IN LET"8990#### READ statement9192def p_command_read(p):93'''command : READ varlist'''94p[0] = ('READ',p[2])9596def p_command_read_bad(p):97'''command : READ error'''98p[0] = "MALFORMED VARIABLE LIST IN READ"99100#### DATA statement101102def p_command_data(p):103'''command : DATA numlist'''104p[0] = ('DATA',p[2])105106def p_command_data_bad(p):107'''command : DATA error'''108p[0] = "MALFORMED NUMBER LIST IN DATA"109110#### PRINT statement111112def p_command_print(p):113'''command : PRINT plist optend'''114p[0] = ('PRINT',p[2],p[3])115116def p_command_print_bad(p):117'''command : PRINT error'''118p[0] = "MALFORMED PRINT STATEMENT"119120#### Optional ending on PRINT. Either a comma (,) or semicolon (;)121122def p_optend(p):123'''optend : COMMA124| SEMI125|'''126if len(p) == 2:127p[0] = p[1]128else:129p[0] = None130131#### PRINT statement with no arguments132133def p_command_print_empty(p):134'''command : PRINT'''135p[0] = ('PRINT',[],None)136137#### GOTO statement138139def p_command_goto(p):140'''command : GOTO INTEGER'''141p[0] = ('GOTO',int(p[2]))142143def p_command_goto_bad(p):144'''command : GOTO error'''145p[0] = "INVALID LINE NUMBER IN GOTO"146147#### IF-THEN statement148149def p_command_if(p):150'''command : IF relexpr THEN INTEGER'''151p[0] = ('IF',p[2],int(p[4]))152153def p_command_if_bad(p):154'''command : IF error THEN INTEGER'''155p[0] = "BAD RELATIONAL EXPRESSION"156157def p_command_if_bad2(p):158'''command : IF relexpr THEN error'''159p[0] = "INVALID LINE NUMBER IN THEN"160161#### FOR statement162163def p_command_for(p):164'''command : FOR ID EQUALS expr TO expr optstep'''165p[0] = ('FOR',p[2],p[4],p[6],p[7])166167def p_command_for_bad_initial(p):168'''command : FOR ID EQUALS error TO expr optstep'''169p[0] = "BAD INITIAL VALUE IN FOR STATEMENT"170171def p_command_for_bad_final(p):172'''command : FOR ID EQUALS expr TO error optstep'''173p[0] = "BAD FINAL VALUE IN FOR STATEMENT"174175def p_command_for_bad_step(p):176'''command : FOR ID EQUALS expr TO expr STEP error'''177p[0] = "MALFORMED STEP IN FOR STATEMENT"178179#### Optional STEP qualifier on FOR statement180181def p_optstep(p):182'''optstep : STEP expr183| empty'''184if len(p) == 3:185p[0] = p[2]186else:187p[0] = None188189#### NEXT statement190191def p_command_next(p):192'''command : NEXT ID'''193194p[0] = ('NEXT',p[2])195196def p_command_next_bad(p):197'''command : NEXT error'''198p[0] = "MALFORMED NEXT"199200#### END statement201202def p_command_end(p):203'''command : END'''204p[0] = ('END',)205206#### REM statement207208def p_command_rem(p):209'''command : REM'''210p[0] = ('REM',p[1])211212#### STOP statement213214def p_command_stop(p):215'''command : STOP'''216p[0] = ('STOP',)217218#### DEF statement219220def p_command_def(p):221'''command : DEF ID LPAREN ID RPAREN EQUALS expr'''222p[0] = ('FUNC',p[2],p[4],p[7])223224def p_command_def_bad_rhs(p):225'''command : DEF ID LPAREN ID RPAREN EQUALS error'''226p[0] = "BAD EXPRESSION IN DEF STATEMENT"227228def p_command_def_bad_arg(p):229'''command : DEF ID LPAREN error RPAREN EQUALS expr'''230p[0] = "BAD ARGUMENT IN DEF STATEMENT"231232#### GOSUB statement233234def p_command_gosub(p):235'''command : GOSUB INTEGER'''236p[0] = ('GOSUB',int(p[2]))237238def p_command_gosub_bad(p):239'''command : GOSUB error'''240p[0] = "INVALID LINE NUMBER IN GOSUB"241242#### RETURN statement243244def p_command_return(p):245'''command : RETURN'''246p[0] = ('RETURN',)247248#### DIM statement249250def p_command_dim(p):251'''command : DIM dimlist'''252p[0] = ('DIM',p[2])253254def p_command_dim_bad(p):255'''command : DIM error'''256p[0] = "MALFORMED VARIABLE LIST IN DIM"257258#### List of variables supplied to DIM statement259260def p_dimlist(p):261'''dimlist : dimlist COMMA dimitem262| dimitem'''263if len(p) == 4:264p[0] = p[1]265p[0].append(p[3])266else:267p[0] = [p[1]]268269#### DIM items270271def p_dimitem_single(p):272'''dimitem : ID LPAREN INTEGER RPAREN'''273p[0] = (p[1],eval(p[3]),0)274275def p_dimitem_double(p):276'''dimitem : ID LPAREN INTEGER COMMA INTEGER RPAREN'''277p[0] = (p[1],eval(p[3]),eval(p[5]))278279#### Arithmetic expressions280281def p_expr_binary(p):282'''expr : expr PLUS expr283| expr MINUS expr284| expr TIMES expr285| expr DIVIDE expr286| expr POWER expr'''287288p[0] = ('BINOP',p[2],p[1],p[3])289290def p_expr_number(p):291'''expr : INTEGER292| FLOAT'''293p[0] = ('NUM',eval(p[1]))294295def p_expr_variable(p):296'''expr : variable'''297p[0] = ('VAR',p[1])298299def p_expr_group(p):300'''expr : LPAREN expr RPAREN'''301p[0] = ('GROUP',p[2])302303def p_expr_unary(p):304'''expr : MINUS expr %prec UMINUS'''305p[0] = ('UNARY','-',p[2])306307#### Relational expressions308309def p_relexpr(p):310'''relexpr : expr LT expr311| expr LE expr312| expr GT expr313| expr GE expr314| expr EQUALS expr315| expr NE expr'''316p[0] = ('RELOP',p[2],p[1],p[3])317318#### Variables319320def p_variable(p):321'''variable : ID322| ID LPAREN expr RPAREN323| ID LPAREN expr COMMA expr RPAREN'''324if len(p) == 2:325p[0] = (p[1],None,None)326elif len(p) == 5:327p[0] = (p[1],p[3],None)328else:329p[0] = (p[1],p[3],p[5])330331#### Builds a list of variable targets as a Python list332333def p_varlist(p):334'''varlist : varlist COMMA variable335| variable'''336if len(p) > 2:337p[0] = p[1]338p[0].append(p[3])339else:340p[0] = [p[1]]341342343#### Builds a list of numbers as a Python list344345def p_numlist(p):346'''numlist : numlist COMMA number347| number'''348349if len(p) > 2:350p[0] = p[1]351p[0].append(p[3])352else:353p[0] = [p[1]]354355#### A number. May be an integer or a float356357def p_number(p):358'''number : INTEGER359| FLOAT'''360p[0] = eval(p[1])361362#### A signed number.363364def p_number_signed(p):365'''number : MINUS INTEGER366| MINUS FLOAT'''367p[0] = eval("-"+p[2])368369#### List of targets for a print statement370#### Returns a list of tuples (label,expr)371372def p_plist(p):373'''plist : plist COMMA pitem374| pitem'''375if len(p) > 3:376p[0] = p[1]377p[0].append(p[3])378else:379p[0] = [p[1]]380381def p_item_string(p):382'''pitem : STRING'''383p[0] = (p[1][1:-1],None)384385def p_item_string_expr(p):386'''pitem : STRING expr'''387p[0] = (p[1][1:-1],p[2])388389def p_item_expr(p):390'''pitem : expr'''391p[0] = ("",p[1])392393#### Empty394395def p_empty(p):396'''empty : '''397398#### Catastrophic error handler399def p_error(p):400if not p:401print("SYNTAX ERROR AT EOF")402403bparser = yacc.yacc()404405def parse(data,debug=0):406bparser.error = 0407p = bparser.parse(data,debug=debug)408if bparser.error: return None409return p410411412413414415416417418419420421422423424425426