/******************************************************** * Here is a simple int calculator based on bison, with * a hand-coded scanner. It is based explicity on the * finite automaton pictured in simple.ps. ********************************************************/ %{ #include <iostream> #include <string> #include <cstdlib> //-- I need this for atoi using namespace std; //-- Lexer prototype required by bison, aka getNextToken() int yylex(); int yyerror(const char *p) { cerr << "Error!" << endl; } %} //-- GRAMMAR SYMBOL DECLARATIONS %union { int val; char sym; }; %token <val> NUM %token <sym> OPA OPM LP RP STOP %type <val> exp term sfactor factor res //-- GRAMMAR RULES %% res: exp STOP { cout << $1 << endl; } exp: exp OPA term { $$ = ($2 == '+' ? $1 + $3 : $1 - $3); } | term { $$ = $1; } term: term OPM factor { $$ = ($2 == '*' ? $1 * $3 : $1 / $3); } | sfactor { $$ = $1; } sfactor: OPA factor { $$ = ($1 == '+' ? $2 : -$2); } | factor { $$ = $1; } factor: NUM { $$ = $1; } | LP exp RP { $$ = $2; } %% //-- FUNCTION DEFINITIONS int main() { while(1) yyparse(); return 0; } // This is the scanner int yylex() { bool found = false; int state = 0; string val = ""; while(!found) { char c = cin.get(); switch(state) { case 0: switch(c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val += c; state = 1; break; case '+': case '-': val += c; state = 2; break; case '*': case '/': val += c; state = 3; break; case ';': val += c; state = 4; break; case '(': val += c; state = 5; break; case ')': val += c; state = 6; break; case ' ': case '\t': case '\n': break; case EOF: exit(0); break; default: found = true; } break; case 1: switch(c) { case '0':case '1':case '2':case '3':case '4': case '5':case '6':case '7':case '8': case '9': val += c; state = 1; break; default: cin.putback(c); found = true; } break; case 2: case 3: case 4: case 5: case 6: cin.putback(c); found = true; break; } } switch(state) { case 0: return 0; // EOF case 1: yylval.val = atoi(val.c_str()); return NUM; case 2: yylval.sym = val[0]; return OPA; case 3: yylval.sym = val[0]; return OPM; case 4: return STOP; case 5: return LP; case 6: return RP; } }