/****************************************
SI 413 Fall 2011

Recursive descent parser and interpreter
for a simple calculator language.
*****************************************/
#include <iostream>
#include <cstdlib>
#include "calc.h"
using namespace std;

//-- Prototypes and globals
void stmt(); 
int exp(); int exptail(int lhs); 
int term(); int termtail(int lhs); 
int sfactor(); int factor(); 
int next = -1;
TokenSemantic nextval;

//-- Helper functions
void perror() { cerr << "Parse error!" << endl; exit(1); }

int peek() { 
  if (next == -1) {
    next = yylex(); 
    nextval = yylval;
  }
  return next; 
}

// Returns the value of the matched token
TokenSemantic match(int tok) { 
  if (tok == peek()) {
    next = -1; 
    return nextval;
  }
  else  perror(); 
}

//-- Grammar rule functions
void stmt() { 
  cout << exp() << endl; 
  match(STOP); 
}

int exp() { 
  int first = term();
  return exptail(first); 
}

int exptail(int lhs) {
  switch(peek()) {
    case OPA: 
      if (match(OPA).sym == '+') {
        int next = term(); 
        return exptail(lhs + next);
      }
      else {
        int next = term();
        return exptail(lhs - next); 
      }
      break;
  case RP: case STOP: return lhs; break;
  default: perror(); break;
 }
}

int term() { 
  int first = sfactor(); 
  return termtail(first); 
}

int termtail(int lhs) {
  switch(peek()) {
    case OPM: 
      if (match(OPM).sym == '*') {
        int next = factor(); 
        return termtail(lhs * next); 
      }
      else {
        int next = factor();
        return termtail(lhs / next);
      }
      break;
  case RP: case STOP: case OPA: 
    return lhs; 
    break;
  default: 
    perror(); 
    break;    
  }
}

int sfactor() {
  switch(peek()) {
    case OPA: 
      if( match(OPA).sym == '-' ) {
        return -factor();
        break;
      } 
      // otherwise drop to the next case.
    case NUM: case LP: 
      return factor(); 
      break;
    default: perror(); break;
  }
}
int factor() {
  int val;
  switch(peek()) {
    case NUM: 
      return match(NUM).num; break;
    case LP: 
      match(LP); 
      val = exp(); 
      match(RP); 
      return val;
      break;
    default: perror(); break;
  }
}

int main() { while (peek()) stmt(); }