%{ // // Expression Interpreter, Parser Portion /* This interpreter evaluates arithmetic expressions and assigns them to the specified variable names. The grammar is: pgm -> stmt* stmt -> id = exp exp -> exp + exp | exp - exp | exp * exp | exp / exp | ( exp ) | id | number */ #include #include #include #include using namespace std; // our hash table for variable names map idTable; // for keeping track of line numbers in the program we are parsing int line_num = 1; // function prototypes, we need the yylex return prototype so C++ won't complain int yylex(); void yyerror(char * s); %} %start program %union { float num; char *id; } %error-verbose %token NUMBER %token ID %token NEWLINE %token EQUALS PRINT %left PLUS MINUS %left TIMES DIVIDE %left LPAREN RPAREN %nonassoc UMINUS %type exp %type stmt %% program : stmtlist ; stmtlist : stmtlist NEWLINE /* empty line */ | stmtlist stmt NEWLINE | stmtlist error NEWLINE { cout << ">>> "; yyclearin; } | /* empty string */ ; stmt: ID EQUALS exp { idTable[$1] = $3; cout << $3 << endl; cout << ">>> "; $$ = $3; } | PRINT ID { cout << idTable[$2] << endl; cout << ">>> "; $$ = idTable[$2]; } ; exp: MINUS exp %prec UMINUS { $$ = -$2; } | exp PLUS exp { $$ = $1 + $3; } | exp MINUS exp { $$ = $1 - $3; } | exp TIMES exp { $$ = $1 * $3; } | exp DIVIDE exp { $$ = $1 / $3; } | LPAREN exp RPAREN { $$ = $2; } | NUMBER { $$ = yylval.num; } | ID { $$ = idTable[$1]; } ; %% main() { // yydebug = 1; cout << ">>> "; yyparse(); } void yyerror(char * s) { fprintf(stderr, "line %d: %s\n", line_num, s); }