%{ package edu.rit.bja8464.cc.bpl; import java.io.InputStream; import java.io.IOException; public class Parser { public static Stmnt.Block parse(InputStream is) throws IOException { return parse(new Lexer(is)); } public static Stmnt.Block parse(Lexer lexer) throws IOException { return (Stmnt.Block) new Parser().yyparse(lexer); } static class Cons { final Object car; final Cons cdr; Cons(Object car, Cons cdr) { this.car = car; this.cdr = cdr; } static int length(Cons xs) { int len; for(len=0;xs != null;len++,xs=xs.cdr); return len; } static void toArray(Cons xs, Object[] a) { int i; for(i=0;xs != null;i++,xs=xs.cdr) a[i] = xs.car; } } %} // FEATURE: There is 1 reduce/reduce conflict in the grammar // When the parser encounters "{ }" at the statement level it doesn't know // if it should reduce it to an object reference or reduce it to an empty block // It currently picks the empty block because it appears first in the grammar. // Fixing this seems like more work than it is worth %token IDENT INTEGER STRING %token VAR IF ELSE WHILE LAMBDA RETURN NULL %token AND OR LE GE EQ NE %nonassoc IFX %nonassoc ELSE %left ',' %right '=' %left '&' %left AND OR %left '>' '<' LE GE EQ NE %left '+' '-' %left '*' '/' '%' %nonassoc UMINUS UPLUS %left '(' '[' '.' %type program %type stmnt %type blockStmnt %type if %type loop %type blockBody %type expr %type get %type lambda %type object %type keyValue %type call %type IDENT %type STRING %type INTEGER %type blockStmnts %type identList1 %type identList %type exprList1 %type exprList %type keyValues1 %type keyValues %% program: blockBody { $$ = $1; } blockStmnts: { $$ = null; } | blockStmnt blockStmnts; { $$ = new Cons($1,$2); } blockBody: blockStmnts { Stmnt[] a = new Stmnt[Cons.length($1)]; Cons.toArray($1,a); $$ = new Stmnt.Block(a); } stmnt: expr ';' { $$ = new Stmnt.Eval($1); } | if { $$ = $1; } | loop { $$ = $1; } | RETURN expr ';' { $$ = new Stmnt.Return($2); } | '{' blockBody '}' { $$ = $2; } | ';'; { $$ = Stmnt.Null.singleton; } blockStmnt: VAR IDENT ';' { $$ = new Stmnt.VarDecl($2); } | VAR IDENT '=' expr ';' { $$ = new Stmnt.VarDecl($2,$4); } | stmnt { $$ = $1; } get: expr '[' expr ']' { $$ = new Expr.Get($1,$3); } | expr '.' IDENT { $$ = new Expr.Get($1,new Expr.StringLit($3)); } if: IF '(' expr ')' stmnt %prec IFX { $$ = new Stmnt.If($3,$5,null); } | IF '(' expr ')' stmnt ELSE stmnt { $$ = new Stmnt.If($3,$5,$7); }; loop: WHILE '(' expr ')' stmnt { $$ = new Stmnt.While($3,$5); }; // FEATURE: add "binop" nonterminal expr: expr AND expr { $$ = new Expr.BinOp($1,AND,$3); } | expr OR expr { $$ = new Expr.BinOp($1,OR,$3); } | expr '>' expr { $$ = new Expr.BinOp($1,'>',$3); } | expr '<' expr { $$ = new Expr.BinOp($1,'<',$3); } | expr LE expr { $$ = new Expr.BinOp($1,LE,$3); } | expr GE expr { $$ = new Expr.BinOp($1,GE,$3); } | expr EQ expr { $$ = new Expr.BinOp($1,EQ,$3); } | expr NE expr { $$ = new Expr.BinOp($1,NE,$3); } | expr '+' expr { $$ = new Expr.BinOp($1,'+',$3); } | expr '-' expr { $$ = new Expr.BinOp($1,'-',$3); } | expr '*' expr { $$ = new Expr.BinOp($1,'*',$3); } | expr '/' expr { $$ = new Expr.BinOp($1,'/',$3); } | expr '%' expr { $$ = new Expr.BinOp($1,'%',$3); } | expr '&' expr { $$ = new Expr.BinOp($1,'&',$3); } | '-' expr %prec UMINUS { $$ = new Expr.UnaryOp(UMINUS,$2); } | '+' expr %prec UPLUS { $$ = new Expr.UnaryOp(UPLUS,$2); } | '(' expr ')' { $$ = $2; } | INTEGER { $$ = new Expr.IntegerLit($1.intValue()); } | IDENT { $$ = new Expr.Ident($1); } | STRING { $$ = new Expr.StringLit($1); } | NULL { $$ = Expr.NullLit.singleton; } | lambda { $$ = $1; } | call { $$ = $1; } | object { $$ = $1; } | get { $$ = $1; } | IDENT '=' expr { $$ = new Expr.Assign($1,$3); } | get '=' expr { $$ = new Expr.Put($1.target,$1.key,$3); } | expr ',' expr { $$ = new Expr.Seq($1,$3); } identList1: IDENT { $$ = new Cons($1,null); } | IDENT ',' identList1 { $$ = new Cons($1,$3); } identList: { $$ = null; } | identList1 { $$ = $1; } exprList1: expr { $$ = new Cons($1,null); } | expr ',' exprList1 { $$ = new Cons($1,$3); } exprList: { $$ = null; } | exprList1 { $$ = $1; } lambda: LAMBDA '(' identList ')' '{' blockBody '}' { String[] a = new String[Cons.length($3)]; Cons.toArray($3,a); $$ = new Expr.Lambda(a,$6); } call: expr '(' exprList ')' { Expr[] a = new Expr[Cons.length($3)]; Cons.toArray($3,a); $$ = new Expr.Call($1,a); } keyValues1: keyValue { $$ = new Cons($1,null); } | keyValue ',' keyValues1 { $$ = new Cons($1,$3); } keyValues: { $$ = null; } | keyValues1 { $$ = $1; } keyValue: IDENT ':' expr { $$ = new Expr.ObjectLit.Ent($1,$3); } object: '{' keyValues '}' { Expr.ObjectLit.Ent[] a = new Expr.ObjectLit.Ent[Cons.length($2)]; Cons.toArray($2,a); $$ = new Expr.ObjectLit(a); } %% }