/* iCalc.y - YACC grammar file for a simple cmd-line integer calculator. * * See the corresponding calc.l file for the specification of the tokens. * * See Makefile.bison or Makefile.yacc to build the icalc executable using * flex/bison or lex/yacc. * * Written by: Dr. Lavender */ %{ /* put C definitions here that are needed for the actions * associated with the grammar rules. */ #include #include %} /* define the tokens returned by the lexer specified in icalc.l */ %token LPAREN RPAREN PLUS MINUS MULT DIV NUM /* the grammar "start" symbol */ %start repl %% /* begin grammar rules section */ /* grammar rules have the form rule: alt-1 { alt-1 actions } | alt-2 { alt-2 actions } | ... ... | alt-n { alt-n actions } ; $$n vars are POSITIONAL variables that can be used in actions to obtain the value associated with the result of evaluating a rule. So if a rule is of the form expr: expr PLUS term { $$ = $1 + $3; } The rule expr can be thought of as a procedure that 'invokes the rhs of the rule, which when evaluated the action $$ = $1 + $3 is like executing return val(expr) + val(term) */ /* repl is the start symbol which yyparse (see below) "calls" to * start the execution of the parser, but it doesn't parse anything, * it just issues a prompt (the Read part of the REPL) and then transfers * control to the 'input' rule which EVALualtes an expression, Prints the * answer, and issues another prompt (the LOOP) until EOF is reached. */ repl: /* empty */ { printf("iCalc# "); } | repl input '\n' | repl error '\n' { yyerrok; printf("iCalc# "); } ; input: expr { printf("%d\niCalc# ", $1); } ; expr: expr PLUS term { $$ = $1 + $3; } | expr MINUS term { $$ = $1 - $3; } | term ; term: term MULT factor { $$ = $1 * $3; } | term DIV factor { $$ = $1 / $3; } | factor ; factor: LPAREN expr RPAREN { $$ = $2; } | NUM { $$ = $1; } ; %% /* end grammar rules */ /* yacc helper functions: * * yyerror - called by yyparse when a parser error is encountered * * yywrap - called by yyparse when end-of-file is reached. * It must return a non-zero value to cause yyparse to exit. */ int yyerror (char* msg) { fprintf(stderr, "%s\n", msg); } int yywrap () { fprintf(stderr, "exiting...\n"); return (1); } /* main function that invokes the generated parser by calling yyparse. * yyparse is a Yacc function that that automatically calls the * lexical analyzer generated by Lex to fetch tokens for the parser. */ int main () { printf("Welcome to iCalc 1.0. Copyright 2007. Use to exit.\n"); /* call the yacc generated parser entry point for this grammar */ yyparse(); /* call the start rule to begin parsing and evaluating exprs */ }