/* SI 413 Fall 2021
* Recursive descent parser and interpreter
* for a simple calculator language.
*/
#include <iostream>
#include <cstdlib>
#include "bisoncalc.tab.hpp"
using std::cout;
using std::cerr;
using std::endl;
using std::flush;
//-- Prototypes and globals
int yylex();
void stmt();
int exp(); int exptail(int lhs);
int term(); int termtail(int lhs);
int factor();
int next = -1;
YYSTYPE nextval;
//-- Helper functions
void parse_error(const char* nt) {
cerr << "Parse error in " << nt << endl;
exit(1);
}
int peek() {
if (next == -1) {
next = yylex();
nextval = yylval;
}
return next;
}
// Returns the value of the matched token
YYSTYPE match(int tok) {
if (peek() != tok) parse_error("match");
next = -1;
return nextval;
}
//-- Grammar rule functions
void stmt() {
int result = exp();
match(STOP);
cout << result << endl;
}
int exp() {
int first = term();
return exptail(first);
}
int exptail(int lhs) {
char op;
int next;
switch(peek()) {
case OPA:
op = match(OPA).sym;
next = term();
if (op == '+') return exptail(lhs + next);
else return exptail(lhs - next);
case RP: case STOP:
return lhs; break;
default:
parse_error("exptail"); return -1;
}
}
int term() {
int first = factor();
return termtail(first);
}
int termtail(int lhs) {
char op;
int next;
switch(peek()) {
case OPM:
op = match(OPM).sym;
next = factor();
if (op == '*') return termtail(lhs * next);
else return termtail(lhs / next);
case RP: case STOP: case OPA:
return lhs;
break;
default:
parse_error("term");
return -1;
}
}
int factor() {
int val;
switch(peek()) {
case NUM:
return match(NUM).val; break;
case LP:
match(LP);
val = exp();
match(RP);
return val;
break;
default: parse_error("factor"); return -1;
}
}
int main() {
while(true) {
cout << "> " << flush;
if (peek() == 0) break;
stmt();
}
cout << endl;
return 0;
}