1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | /* SI 413 Fall 2012 * 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 namespace std; /************************************** * 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; } |