/********************************************************
* 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; }
}