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