/////////////
// Compile
/////////////

bison -d field.y
flex field.l
g++ field.tab.c lex.yy.c -ll 

/////////////
// field.y
/////////////

%{                                                                                                                                            
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
 
int yylex(void);
void yyerror(const char *s);
vector<string> inv;
%}
 
%union {
   char *s; 
}
 
%token LOOK TAKE QUIT TREE DOOR KEY EOL 
%token <s> WORD
%type <s> item
 
%%
 
input:
        /* empty string / epsilon */
        | input command EOL
        ;
     
command:
      LOOK command { 
                      cout << "You see a tree. Your Inventory:" << endl;
                      for (int i = 0; i < inv.size(); i++){
                          cout << inv[i] << endl;
                      }   
                   }   
    | TAKE item command { //This line causes a shift/reduce warning! Bison will shift by default.
                      cout << "You took the " << $2 << "." << endl;
                      free($2); //Free the strdup (malloc) or we will eventually run out of memory!
                   }   
    | QUIT command {
                      printf("Goodbye.\n");
                      YYACCEPT;
                   }   
    | TREE command {
                      cout << "The tree is hiding a key." << endl;
                   }   
    | DOOR command { 
                      cout << "This is the door of the shack." << endl;
                      if (find(inv.begin(), inv.end(), "Key") != inv.end()) {
                         cout << "The door opens with the key. You win!" << endl;
                         YYACCEPT;
                      } else {
                         cout << "The door is locked." << endl;
                      }   
                   }   
    | WORD command {
                      cout << "You can imagine a " << $1 << "." << endl;
                   }   
    | /* empty string / epsilon */
    ;
 
item: 
    WORD  {
              inv.push_back($1); //$1 is the value of WORD
              $$ = $1; 
          }   
    | KEY {
              inv.push_back("Key");
              $$ = strdup("Key");
          }   
    |     { printf("Take what?\n"); }
 
%%
 
int main(void) {
    cout << "You wake up in a field in Oakland (uh oh). You see a shack with a door, and a tree." << endl;
    yyparse();
    return 0;
}
 
void yyerror(const char *s) {
    fprintf(stderr, "Error: %s\n", s); 
}

////////////
// field.l
////////////

%{                                                                                                                                            
#include "field.tab.h"
%}
 
%%
 
"look"          { return LOOK; }
"take"          { return TAKE; }
"quit"          { return QUIT; }
"tree"          { return TREE; }
"door"          { return DOOR; }
"key"           { return KEY; }
 
\n              { return EOL; }
[ \t]+          ; //ignore spaces
[a-zA-Z]+       { yylval.s = strdup(yytext); return WORD; }
.               { printf("Not valid.\n"); }
 
%%
 
int yywrap(void){
        return 1;
}