/****************************************
Table-driven top-down parser for a simple
language.
Grammar for simple arithmetic. Notice
the odd form of exp and term rules: We
had to write them without "left-recursion"
so that we could parse top-down:
stmt -> exp STOP
exp -> term exptail
exptail -> OPA term exptail| e
term -> sfactor termtail
termtail -> OPM factor termtail | e
sfactor -> OPA factor | factor
factor -> NUM | LP exp RP
*****************************************/
#include "calc.h"
#include <iostream>
#include <cstdlib>
#include <string>
#include <stack>
using namespace std;
/**************************************
* Non-terminals are
* numbered consecutively from startSym
* up, where startSym is some number
* greater than any token number.
**************************************/
enum NonTerminal {
stmt=10,
exp,
exptail,
term,
termtail,
sfactor,
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)
{ sfactor, termtail, -1 }, // Rule 4 (term)
{ OPM, factor, termtail, -1 }, // Rule 5 (termtail)
{ -1 }, // Rule 6 (termtail)
{ OPA, factor, -1 }, // Rule 7 (sfactor)
{ factor, -1 }, // Rule 8 (sfactor)
{ NUM, -1 }, // Rule 9 (factor)
{ LP, exp, RP, -1 } // Rule 10 (factor)
};
//-- parseTable[symbol][token-1] = 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 },
/* sfactor */ { 8, 7, -1, 8, -1, -1 },
/* factor */ { 9, -1, -1, 10, -1, -1 }
};
static string toString(int a) {
switch(a) {
case NUM: return "NUM";
case OPA: return "OPA";
case OPM: return "OPM";
case LP: return "LP";
case RP: return "RP";
case STOP: return "STOP"; }
}
int next = -1;
//-- Helper functions
void pperror(string msg = "Parse error!") { cerr << msg << endl; exit(1); }
int peek() { if (next == -1) next = yylex(); return next; }
void match(int tok) {
if (tok == peek()) next = -1;
else pperror(string("Error! Expected ") + toString(tok)
+ " found " + toString(peek()));
}
//-- 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()-1];
if (action == error) pperror("Parse error!");
int k = 0; while(rule[action][k] != -1) ++k;
while(--k >= 0) S.push(rule[action][k]);
}
}
}
int main() { while(peek()) parse(); }