%{
#include <iostream>
#include <map>
#include <string>
using namespace std;

#include "StringExpression.h"
#include "BooleanExpression.h"
#include "Statement.h"
#include "Program.h"

#define YYDEBUG 1

void yyerror(char* s) {
     cerr << s << endl;
}

int yylex();

Program program;
%}

%union {
       Statement* pstatement_atr;
       StringExpression* pstringexpression_atr;
       BooleanExpression* pbooleanexpression_atr;
       int	  int_atr;
       string*	  pstring_atr;
}

%type<pstatement_atr> statement
%type<pstringexpression_atr> string_expression
%type<pbooleanexpression_atr> boolean_expression
%token <int_atr> NUM
%token <pstring_atr> STRING STRINGVAR VAR
%token PRINT INPUT GOTO IF THEN FOR TO NEXT LET RUN LEFT RIGHT

%left '+'

%%

program : lines run
	;

lines : lines NUM statement {
	program.addStatement($2, $3);
      }
      | 
      ;

statement : PRINT string_expression {
       $$ = new PrintStatement($2);
     }
     | GOTO NUM {
       $$ = new GotoStatement($2);
     }
     | INPUT string_expression ';' STRINGVAR {
       $$ = new InputStatement($2, *$4);
       delete $4;
     }
     | IF boolean_expression THEN statement {
       $$ = new IfStatement($2, $4);
     }
     | LET STRINGVAR '=' string_expression {
       $$ = new LetStatement(*$2, $4);
       delete $2;
     }
     | FOR VAR '=' NUM TO NUM {
       $$ = new ForStatement(*$2, $4, $6);
       delete $2;
     }
     | NEXT VAR {
       $$ = new NextStatement(*$2);
       delete $2;
     }
     ;

string_expression : STRING {
		  	$$ = new StringLiteral(*$1);
			delete $1;
		  }
		  | string_expression '+' string_expression {
		    	$$ = new Plus($1, $3);
		  }
		  | STRINGVAR {
		        $$ = new StringVar(*$1);
			delete $1;
		  }
		  | VAR {
			$$ = new IntVar(*$1);	
			delete $1;
		  }
		  | LEFT '(' string_expression ',' NUM ')' {
		        $$ = new Left($3, $5);
		  }
		  | RIGHT '(' string_expression ',' NUM ')' {
		        $$ = new Right($3, $5);
		  }
		  ;

boolean_expression: string_expression '=' string_expression {
		    $$ = new Eq($1, $3);
	    }

run : RUN {
      program.run();
    }
    ;

%%

int main(int argc, char* argv[]) {
    yydebug = 0;

    if (argc < 2) {
       cerr << "Usage: basic filename" << endl;
       return EXIT_FAILURE;
    }
    
    extern FILE* yyin;
    yyin = fopen(argv[1], "r");

    if (yyin == NULL) {
       cerr << "Error opening: " << argv[1] << endl;
       return EXIT_FAILURE;
    }
    
    return yyparse();
}
