(* L1 Compiler * L1 grammar * Author: Kaustuv Chaudhuri * Modified: Frank Pfenning *) structure A = Ast (* for simplicity, we only mark expressions, not statements *) (* mark e with region (left, right) in source file *) fun mark (e, (left, right)) = A.Marked (Mark.mark' (e, ParseState.ext (left, right))) (* create lval from expression; here just an id *) (* generates error if not an identifier *) fun make_lval (A.Var(id)) ext = id | make_lval (A.Marked(marked_exp)) ext = make_lval (Mark.data marked_exp) (Mark.ext marked_exp) | make_lval _ ext = ( ErrorMsg.error ext "not a variable" ; Symbol.bogus ) (* expand_asnop (exp1, "op=", exp2) region = "exp1 = exp1 op exps" * or = "exp1 = exp2" if asnop is "=" * generates error if exp1 is an lval (identifier) * syntactically expands a compound assignment operator *) fun expand_asnop (exp1, NONE, exp2) (left, right) = A.Assign(make_lval exp1 NONE, exp2) | expand_asnop (exp1, SOME(oper), exp2) (left, right) = A.Assign(make_lval exp1 NONE, mark(A.OpExp(oper, [exp1, exp2]), (left, right))) %% %header (functor L1LrValsFn (structure Token : TOKEN)) %term EOF | SEMI | INTNUM of Word32.word | IDENT of Symbol.symbol | RETURN | PLUS | MINUS | STAR | SLASH | PERCENT | ASSIGN | PLUSEQ | MINUSEQ | STAREQ | SLASHEQ | PERCENTEQ | LBRACE | RBRACE | LPAREN | RPAREN | UNARY | ASNOP (* dummy *) %nonterm program of A.program | stms of A.stm list | stm of A.stm | simp of A.stm | return of A.stm | exp of A.exp | asnop of A.oper option %verbose (* print summary of errors *) %pos int (* positions *) %start program %eop EOF %noshift EOF %name L1 %left PLUS MINUS %left STAR SLASH PERCENT %right UNARY %left LPAREN %% program : LBRACE stms return RBRACE (stms@[return]) return : RETURN exp SEMI (A.Return exp) stms : ([]) | stm stms (stm :: stms) stm : simp SEMI (simp) simp : exp asnop exp %prec ASNOP (expand_asnop (exp1, asnop, exp2) (exp1left, exp2right)) exp : LPAREN exp RPAREN (exp) | INTNUM (mark (A.ConstExp(INTNUM),(INTNUMleft,INTNUMright))) | IDENT (mark (A.Var(IDENT), (IDENTleft,IDENTright))) | exp PLUS exp (mark (A.OpExp (A.PLUS, [exp1,exp2]), (exp1left,exp2right))) | exp MINUS exp (mark (A.OpExp (A.MINUS, [exp1,exp2]), (exp1left,exp2right))) | exp STAR exp (mark (A.OpExp (A.TIMES, [exp1,exp2]), (exp1left,exp2right))) | exp SLASH exp (mark (A.OpExp (A.DIVIDEDBY, [exp1,exp2]), (exp1left,exp2right))) | exp PERCENT exp (mark (A.OpExp (A.MODULO, [exp1,exp2]), (exp1left,exp2right))) | MINUS exp %prec UNARY (mark (A.OpExp (A.NEGATIVE, [exp]), (MINUSleft,expright))) asnop : ASSIGN (NONE) | PLUSEQ (SOME(A.PLUS)) | MINUSEQ (SOME(A.MINUS)) | STAREQ (SOME(A.TIMES)) | SLASHEQ (SOME(A.DIVIDEDBY)) | PERCENTEQ (SOME(A.MODULO))