/* 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;
}