/* SI 413 Fall 2021
* This is a table-driven top-down parser for the calculator language.
*
* Here is the grammar:
stmt -> exp STOP
exp -> term exptail
exptail -> OPA term exptail| e
term -> factor termtail
termtail -> OPM factor termtail | e
factor -> NUM | LP exp RP
*/
#include <iostream>
#include <cstdlib>
#include <string>
#include <stack>
#include "bisoncalc.tab.hpp"
using std::cout;
using std::cerr;
using std::endl;
using std::flush;
using std::stack;
/**************************************
* Non-terminals are
* numbered consecutively from startSym
* up, where startSym is some number
* greater than any token number.
**************************************/
enum NonTerminal {
stmt=500,
exp,
exptail,
term,
termtail,
factor
};
const NonTerminal startSym = stmt;
const int error = -1;
//-- These are the grammar rules. -----------------//
const int rule[][10] = {
{ exp, STOP, -1 }, // Rule 0 (stmt)
{ term, exptail, -1 }, // Rule 1 (exp)
{ OPA, term, exptail, -1 }, // Rule 2 (exptail)
{ -1 }, // Rule 3 (exptail)
{ factor, termtail, -1 }, // Rule 4 (term)
{ OPM, factor, termtail, -1 }, // Rule 5 (termtail)
{ -1 }, // Rule 6 (termtail)
{ NUM, -1 }, // Rule 7 (factor)
{ LP, exp, RP, -1 } // Rule 8 (factor)
};
//-- parseTable[symbol][token] = predicted rule. --//
const int parseTable[][10] = {
/* NUM OPA OPM LP RP STOP */
/* stmt */ { 0, 0, -1, 0, -1, -1 },
/* exp */ { 1, 1, -1, 1, -1, -1 },
/* exptail */ { -1, 2, -1, -1, 3, 3 },
/* term */ { 4, 4, -1, 4, -1, -1 },
/* termtail */ { -1, 6, 5, -1, 6, 6 },
/* factor */ { 7, -1, -1, 8, -1, -1 }
};
int next = -1;
//-- Helper functions
int yylex();
void perror(const char* msg) {
cerr << "Parse error: " << msg << endl;
exit(1);
}
int peek() {
if (next == -1)
next = yylex();
return next;
}
void match(int tok) {
if (tok == peek())
next = -1;
else
perror("match");
}
//-- Table-driven parser ... pretty darn simple
void parse() {
stack<int> S;
S.push(startSym);
while(true)
{
int sym = S.top();
S.pop();
if (sym < startSym)
{
match(sym);
if (sym == STOP) return;
}
else
{
int action = parseTable[sym - startSym][peek()-NUM];
if (action == error) perror("Non-terminal expansion");
int k = 0;
while(rule[action][k] != -1) ++k;
while(--k >= 0) S.push(rule[action][k]);
}
}
}
int main() {
while (true) {
cout << "> " << flush;
if (peek() == 0) break;
parse();
}
cout << endl;
return 0;
}