/* SI 413 Fall 2011
 * spl.ypp 
 * Parser for SPL that just shows the parse tree
 * This parser uses a simpler grammar with assoc/prec specifications.
 */

%{
#include <cstdlib>
#include <iostream>
using namespace std;

#include "ast.hpp"

Stmt* tree; // This global will be set to the whole AST.

int yylex(); 
int yyerror(const char *p) { cerr << "Parser: " << p << endl; return 0; }

%}

%union {
  Block* block;
  Stmt* stmt;
  Exp* exp;
  Id* id;
  Oper op;
};

%left<op> BOP
%right<op> NOT
%left<op> COMP
%left<op> OPA
%left<op> OPM
%right POSNEG
%nonassoc LP

%token LC RC RP LAMBDA IF ELSE WHILE READ WRITE NEW ASN STOP
%token<id> ID
%token<exp> NUM BOOL
%type<stmt> stmt stmtlist
%type<block> block
%type<exp> exp

%%
  /*Note: YYACCEPT is a bison macro that just tells it to quit parsing.*/
res: stmt { tree = $1; YYACCEPT; }
|         { tree = NULL; }

block: LC stmtlist RC { $$ = new Block($2); }

stmtlist: stmtlist stmt { $$ = Stmt::append($1,$2); }
|                       { $$ = new NullStmt; }

stmt: NEW ID ASN exp STOP           {$$ = new NewStmt($2,$4);}
|     ID ASN exp STOP               {$$ = new Asn($1,$3);}
|     READ ID STOP                  {$$ = new Read($2);}
|     WRITE exp STOP                {$$ = new Write($2);}
|     IF LP exp RP block            {$$ = new IfStmt($3,$5);}
|     IF LP exp RP block ELSE block {$$ = new IfElse($3,$5,$7);}
|     WHILE LP exp RP block         {$$ = new WhileStmt($3,$5);}
|     block                         {$$ = $1;}

exp: exp BOP exp      {$$ = new BoolOp($1,$2,$3);}
|    NOT exp          {$$ = new NotOp($2);}
|    exp COMP exp     {$$ = new CompOp($1,$2,$3);}
|    exp OPA exp      {$$ = new ArithOp($1,$2,$3);}
|    exp OPM exp      {$$ = new ArithOp($1,$2,$3);}
|    OPA exp %prec POSNEG {$$ = ($1 == ADD ? $2 : new NegOp($2));}
|    LAMBDA ID block  {$$ = new Lambda($2,$3);}
|    exp LP exp RP    {$$ = new Funcall($1,$3);}
|    LP exp RP        {$$ = $2;}
|    ID               {$$ = $1;}
|    NUM              {$$ = $1;}
|    BOOL             {$$ = $1;}

%%
int main()
{
  while(true) {
    tree = NULL;
    yyparse();
    if (tree == NULL) break;
    tree->writeDot("spl.dot");
    system("dot -Tpdf spl.dot > spl.pdf");
    system("evince spl.pdf > /dev/null 2>&1 &");
    tree->exec();
  }
  return 0;
}