using namespace std;
#include <iostream>
#include "Envs.h"
#include "Tokens.h"
#include "Basics.h"

typedef CharSet TokenTypeSet; 

Token  t;   
CharSet  ES; // empty set

// check -- true iff the current token (t) is contained in the TokenTypeSet s
int check(TokenTypeSet s)
{
  return s.contains(t.type());
}

// verify -- if current token (t) is in in the set TokenTypeSet s, 
//           then get the next token
//           else error message and halt the program
void verify(TokenTypeSet s)
{
   TokenType    c,d;
   entering("verify");
   if (check(s)){
      t.get();
   }
   else {
      cout << "Error: verify: looking for:";
      c = assignSym; //  first in TokenType
      while (! s.contains(c))
            c =  succ(c);
      cout << tokenTypeStr(c) << endl;
      if (c != varSym) {  // loop for commas 
         c = succ(c);
         for ( d = c ; d <= varSym; d=succ(d)) {
             if (s.contains(d))
               cout << "," << tokenTypeStr(c) 
                           << endl;
         }
      }
      exit(-1);
   }
   leaving("verify");
}

// assignUnit -- parse <assign> statements
void assignUnit()
/*   <assign> ::= <var> <- <const> */
/*   <assign> ::= <var> <- <var> */
/*   <assign> ::= <var> <- <var>  + 1 */
/*   <assign> ::= <var> <- <var>  - 1 */
{
  verify(ES+varSym);
  verify(ES+assignSym);
  if (check(ES+constSym))
     verify(ES+constSym);
  else if (check(ES+varSym)){
     verify(ES+varSym);
     if (check(ES+plusSym+minusSym)){
        verify(ES+plusSym+minusSym);
        if (check(ES+constSym)){
           if (strcmp(t.val(), "1") == 0)
              verify(ES+constSym);
           else {
             cout <<"assign: Expected 1," <<
                   " found " << t.val() << endl;
             exit(-1);
            }
         }
      }
   }
};

//  stmtUnit -- parse <stmt>
void stmtUnit()
/*   <stmt>       ::= <assign> */
{
  entering("stmtUnit");
  Token   tok;
  if (check(ES+varSym))
    assignUnit();
}


//  stmtUnit -- parse <stmtList> (a list of statements)
void stmtListUnit()
/*   <stmtList>  := <stmt> */
/*   <stmtList>  := <stmt> <stmtList> */
{
   stmtUnit();
   if (check(ES+varSym))
      stmtListUnit();
}

// programUnit -- parse a complete <program> (ends in a '.')
void programUnit()
/*   <program>   ::= <stmtList> . */
{
   stmtListUnit();
   if (! check(ES+periodSym)){
     cout << "Missing final period" << endl;
     exit(-1);
   }
}
int main()
{
   setTokenSource(""); // set input to kbd
   t.init(initSym);
   t.get();
   programUnit(); 
   return 0;
}

