/* icalc2.y - Yacc grammar file for a simple integer calculator with 26 registers a-z. * * See the corresponding calc.l file for the specification of the lexemes. * * To compile into a program icalc2, use the following commands: * you can use lex+yacc or flex+bixon * * % flex icalc2.l * % bison -d -o icalc2.c icalc2.y * % gcc lex.yy.c icalc2.c -o icalc2 * * Try using the -v flag to yacc and look at the generated y.output file */ %{ #include #include #include /* array of integer registers a-z intialized * to zero by static declaration. */ static int reg[26]; static int error; static int maxint = 2147483647; static int minint = -2147483648; static int swap(int* a, int* b) { int t = *a; *a = *b; *b = t; return 0; } %} /* define the tokens returned by the lexer */ %token REG DIGIT MAXINT MININT %token LPAREN RPAREN COMMA /* define the precedence and associativity of operators * the first ones defined have the lowest precedence */ %right ASSIGN PASSGN SASSGN TASSGN DASSGN MASSGN %right THEN ELSE %left OR %left AND %left LT LE GT GE %left EQ NE %left PLUS MINUS %left MULT DIV MOD %right POW %right ABS MIN MAX SWAP %right INCR DECR %nonassoc UNARY /* define the grammar "start" non-terminal symbol */ %start prompt %% /* beginning of grammar rules section */ prompt: /* empty */ { printf("icalc> "); } | prompt input '\n' { printf("icalc> "); } | prompt error '\n' { yyerrok; error = 0; printf("\nicalc> "); } ; input: /* empty */ | expr { if (error == 0) printf("%d\n", $1); } | assign { if (error == 0) printf("%d\n", $1); } ; assign: REG ASSIGN assign { $$ = reg[$1] = $3; } | REG ASSIGN expr { $$ = reg[$1] = $3; } | REG PASSGN expr { $$ = (reg[$1] += $3); } | REG SASSGN expr { $$ = (reg[$1] -= $3); } | REG TASSGN expr { $$ = (reg[$1] *= $3); } | REG DASSGN expr { $$ = (reg[$1] /= $3); } | REG MASSGN expr { $$ = (reg[$1] %= $3); } | REG ASSIGN expr error { error = -1; } ; expr: MINUS expr %prec UNARY { $$ = -$2; } | PLUS expr %prec UNARY { $$ = +$2; } | expr OR expr { $$ = $1 || $3; } | expr AND expr { $$ = $1 && $3; } | expr PLUS expr { $$ = $1 + $3; } | expr MINUS expr { $$ = $1 - $3; } | expr MULT expr { $$ = $1 * $3; } | expr DIV expr { $$ = $1 / $3; } | expr MOD expr { $$ = $1 % $3; } | expr POW expr { int x = pow($1, $3); $$ = (x == minint) ? maxint : x; } | expr EQ expr { $$ = ($1 == $3) ? 1 : 0; } | expr NE expr { $$ = ($1 != $3) ? 1 : 0; } | expr LT expr { $$ = ($1 < $3) ? 1 : 0; } | expr LE expr { $$ = ($1 <= $3) ? 1 : 0; } | expr GT expr { $$ = ($1 > $3) ? 1 : 0; } | expr GE expr { $$ = ($1 >= $3) ? 1 : 0; } | LPAREN expr RPAREN { $$ = $2; } | LPAREN expr RPAREN THEN expr ELSE expr { $$ = ($2) ? $5 : $7; } | INCR REG { $$ = ++reg[$2]; } | REG INCR { $$ = reg[$1]++; } | DECR REG { $$ = --reg[$2]; } | REG DECR { $$ = reg[$1]--; } | REG { $$ = reg[$1]; } | MAXINT { $$ = maxint; } | MININT { $$ = minint; } | DIGIT { $$ = $1; } | fun ; fun: ABS LPAREN expr RPAREN { $$ = ($3 < 0) ? -$3 : $3; } | MIN LPAREN expr COMMA expr RPAREN { $$ = ($3 < $5) ? $3 : $5; } | MAX LPAREN expr COMMA expr RPAREN { $$ = ($3 > $5) ? $3 : $5; } | SWAP LPAREN REG COMMA REG RPAREN { $$ = swap(®[$3], ®[$5]); } ; %% /* 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, "quitting...\n"); return (1); } /* main function that invokes the generated parser, yyparse, that automatically calls the lexer */ int main () { int rc; printf("icalc 2.0. Registers 'a-z' initialized to zero. Use to quit.\n"); rc = yyparse(); exit(rc); }