#include <iostream>
using namespace std;


#include "token_nums.h"
/* This is a nonsense grammar from a programming contest:
  the lowercase words are non-terminals, the uppercase characters
  are the terminals of this language.

  slurpy -> slimp slump
  slimp -> A rest_slimp 
  rest_slimp  -> H
  rest_slimp -> B slimp C
  rest_slimp -> slump C
  slump -> d_or_e F f_string end 
  d_or_e -> D
  d_or_e -> E
  f_string -> F f_string | lambda
  end -> slump
  end -> G 

Some strings in the language: AHDFG, ADFGCDFFFFFG, ABAEFGCCDFEFFFFFFG
Some strings NOT in the lanuage: AHDFGA, DFGAH, ABABCC
*/

int lookahead;


extern int yylex();
void error(char *where) ;
void match(int token); 
void slurpy_lines() ;
void slurpy();
void slimp();
void slump();
void rest();
void d_or_e();
void f_str();
void end();


main() {
  lookahead = yylex();
  slurpy_lines();
  if (lookahead == 0)
     cout<<"String accepted\n";
  else 
     cout<<"String rejected\n";
}

void error(char *where) {
  cout<<"Error found in function ",where , "\n";
  exit(42);
}

void match(int token) {
  if (token == lookahead) lookahead = yylex();
  else error("match");
}

void slurpy_lines() {
  if (lookahead == 0) return;
  if (lookahead == A_TOKEN) {
     slurpy(); match(EOLN);
     slurpy_lines();
  } else error ("slurpy_lines");
}

void slurpy() {
  if (lookahead == A_TOKEN) {
     slimp(); slump();
  } else error("slurpy");
}

void slimp() {
  if (lookahead == A_TOKEN) {
    match(A_TOKEN); rest(); 
  } else error("slimp");
}

void rest() {
  switch (lookahead)  {
    case H_TOKEN: match(H_TOKEN); break;
    case B_TOKEN: match(B_TOKEN); slimp(); match(C_TOKEN); break;
    case D_TOKEN:
    case E_TOKEN: slump(); match(C_TOKEN); break;
    default: error("rest");
  }
}

void slump() {
  if ((lookahead == D_TOKEN) | (lookahead == E_TOKEN)) {
     d_or_e(); match(F_TOKEN); f_str(); end();
  } else error("slump");
}

void d_or_e() {
  if (lookahead == D_TOKEN) match(D_TOKEN);
  else if (lookahead == E_TOKEN) match(E_TOKEN);
  else error("d_or_e");
}

void f_str() {
  switch(lookahead) {
    case F_TOKEN: match(F_TOKEN); f_str(); break;
    case D_TOKEN: case E_TOKEN: case G_TOKEN: break;
    default: error("f_str");
  }
}

void end() {
  switch(lookahead) {
    case G_TOKEN: match(G_TOKEN); break;
    case D_TOKEN: case E_TOKEN: slump(); break;
    default: error("end");
  }
}

