%{ open Prim open G_ast open Support.Error open Support.Pervasive exception ParseError %} %token INT %token FLOAT %token DOUBLE %token NAME %token STRING %token CHAR %token INTTY %token SHORTTY %token LONGTY %token FLOATTY %token DOUBLETY %token CHARTY %token WCHARTY %token BOOLTY %token VOIDTY %token STRINGTY %token ELIPSES %token UNSIGNED %token SIGNED %token CONST %token NULLPTR %token OPERATOR %token EXISTS %token EXTERN %token ASSIGN %token LPAREN %token RPAREN %token BAR %token LBRACE %token RBRACE %token LBRACK %token RBRACK %token EOL %token EOF %token TRUE %token FALSE %token THIS %token UNPACK %token MUTABLE %token DOT %token TILDE %token BANG %token FUN %token PRIMITIVE %token IS %token COLON %token SEMICOLON %token COMMA %token THROW %token TRY %token CATCH %token STAR %token ARROW %token INTER %token LT %token GT %token OUTPUT %token INPUT %token PLUS %token PLUSASSIGN %token SUB %token NEG %token INC %token DEC %token DIV %token LEQ %token GEQ %token EQ %token NEQ %token OR %token AND %token NOT %token CAST %token AT %token PERCENT %token QMARK %token IF %token ELSE %token WHILE %token DO %token FOR %token RETURN %token AMP %token NEW %token PLACEMENT_NEW %token ARRAY %token HEAP %token GC %token DELETE %token DESTROY %token LET %token MODULE %token PRIVATE %token PUBLIC %token IMPORT %token INCLUDE %token USE %token OPEN %token FROM %token AS %token SIZEOF %token WHERE %token CONCEPT %token MODEL %token REFINES %token REQUIRE %token TYPE %token STRUCT %token UNION %token CLASS %token SWITCH %token CASE %token DEFAULT %left COMMA %left COLON %right ASSIGN %nonassoc QMARK %left OR AND NOT %nonassoc LEQ GEQ LT GT %nonassoc EQ NEQ %left PLUS SUB AT AMP %left PERCENT %left DIV %left STAR %nonassoc THROW CATCH WHERE CONCEPT TYPE IMPORT MODULE MODEL MODELS %nonassoc LBRACE RBRACE BAR %left NEW DELETE %right USTAR USUB UAMP INC DEC %nonassoc LPAREN RPAREN %nonassoc LBRACK RBRACK %left DOT %left ARROW %start main /* the entry point */ %type main %% main: decl_list EOF { $1 } ; type_params: { [] } | LT name_list GT { $2 } ; type_args: { [] } | LT typ_list GT { $2 } ; decl: LET NAME ASSIGN expr SEMICOLON { LetD ($1, VoidT $1, Constant, $2.v, $4) } | EXTERN typ passby NAME SEMICOLON { LetFwdD ($1, $2, snd $3, $4.v) } | STRUCT NAME type_params where_clause SEMICOLON { StructFwdD ($1, $2.v, $3, $4) } | UNION NAME type_params where_clause SEMICOLON { UnionFwdD ($1, $2.v, $3, $4) } | CLASS NAME type_params where_clause SEMICOLON { ClassFwdD ($1, $2.v, $3, $4) } | TYPE NAME ASSIGN typ SEMICOLON { TypedefD ($1, $2.v, $4) } | STRUCT NAME type_params where_clause LBRACE mem_list RBRACE SEMICOLON { StructD ($1, $2.v, $3, $4, $6) } | UNION NAME type_params where_clause LBRACE mem_list RBRACE SEMICOLON { UnionD ($1, $2.v, $3, $4, $6) } | EXTERN STRING LBRACE decl_list RBRACE { ExternScopeD ($1, $2.v, $4) } | CLASS NAME type_params where_clause LBRACE class_mem_list RBRACE SEMICOLON { let mems = $6 in let ms = filter_map (fun m -> match m with Field (i,n,t) -> Some (n,t) | _ -> None) mems in let cs = filter_map (fun m -> match m with Constructor (i,ts,rs,ps,inits,body) -> Some (i,ts,rs,ps,inits,body) | _ -> None) mems in let dest = match (filter_map (fun m -> match m with Destructor (i,body) -> Some body | _ -> None) mems) with [] -> CompoundS ($1, []) | [dest] -> dest | _ -> error $1 "Only one destructor may be defined per class" in ClassD ($1, $2.v, $3, $4, ms, cs, dest) } | CONCEPT NAME LT name_list GT LBRACE concept_mem_list RBRACE SEMICOLON { let mems = $7 in let assocs = filter_map (fun m -> match m with AssocC (i, n) -> Some n | _ -> None) mems in let refs = filter_map (fun m -> match m with RefinesC (i, n, ts) -> Some (n, ts) | _ -> None) mems in let reqs = filter_map (fun m -> match m with RequiresC (i, n, ts) -> Some (n, ts) | _ -> None) mems in let fs = filter_map (fun m -> match m with FunC (i, n, ts, rs, ps, rt, body) -> Some (n, (FunT (i, ts, rs, List.map snd ps, rt), List.map fst ps, body)) | _ -> None) mems in let sames = filter_map (fun m -> match m with SameTypeC (i, t1, t2) -> Some (t1,t2) | _ -> None) mems in ConceptD ($1, $2.v, $4, assocs, refs, reqs, fs, sames) } | model_label MODEL type_params where_clause NAME LT typ_list GT model_open SEMICOLON { ModelFwdD ($2, $9, $3, $4, $5.v, $7, []) } | model_label MODEL type_params where_clause NAME LT typ_list GT model_open LBRACK model_mem_list RBRACK SEMICOLON { let mems = $11 in let assocs = filter_map (fun m -> match m with AssocM (i, n, t) -> Some (n,t) | _ -> None) mems in ModelFwdD ($2, $9, $3, $4, $5.v, $7, assocs) } | model_label MODEL type_params where_clause NAME LT typ_list GT model_open LBRACE model_mem_list RBRACE SEMICOLON { let mems = $11 in let assocs = filter_map (fun m -> match m with AssocM (i, n, t) -> Some (n,t) | _ -> None) mems in let fs = filter_map (fun m -> match m with FunM (i, n, recur, ts, rs, ps, rt, body) -> Some (n, (i, recur, ts, rs, ps, rt, body)) | _ -> None) mems in ModelD ($5.i, $9, $3, $4, $5.v, $7, assocs, fs) } | fun_def { $1 } | sig_decl { $1 } | FUN fun_name PLUSASSIGN expr SEMICOLON { OvldD ($1, $2.v, $4) } | MODULE NAME type_params where_clause LBRACE decl_list RBRACE { ModuleD ($1, $2.v, $3, $4, $6) } | PRIVATE COLON { PrivateD $1 } | PUBLIC COLON { PublicD $1 } | IMPORT import_expr FROM module_path rename SEMICOLON { ImportD ($1, $2, $4, $5) } | INCLUDE STRING SEMICOLON { IncludeD ($1, $2.v) } | USE STRING SEMICOLON { UseD ($1, $2.v) } ; rename: { "" } | AS NAME { $2.v } ; module_ref: NAME { ($1.i, $1.v, []) } | NAME LT typ_list GT { ($1.i, $1.v, $3) } ; module_path: module_ref { [$1] } | module_ref DOT module_path { $1::$3 } ; import_expr: FUN fun_name { FunImportName ($1, $2.v) } | signature { $1 } | CONCEPT NAME { ImportConcept ($1, $2.v) } | TYPE NAME { ImportType ($1, $2.v) } | MODEL NAME LT typ_list GT { ImportModel ($1, $2.v, $4) } | MODEL NAME { ImportNamedModel ($1, $2.v) } ; signature: FUN fun_name type_params where_clause LPAREN param_list RPAREN ARROW typ { FunImport ($1, $2.v, $3, $4, $6, $9) } ; model_open: { false } | OPEN { true } ; model_label: { "" } | NAME COLON { $1.v } ; fun_name: NAME { $1 } | OPERATOR ASSIGN{ {i=$1; v= "__assign"} } | OPERATOR INC { {i=$1; v= "__increment"} } | OPERATOR DEC { {i=$1; v= "__decrement"} } | OPERATOR PLUS { {i=$1; v= "__add"} } | OPERATOR SUB { {i=$1; v= "__sub"} } | OPERATOR STAR { {i=$1; v= "__star"} } | OPERATOR DIV { {i=$1; v= "__div"} } | OPERATOR PERCENT { {i=$1; v= "__mod"} } | OPERATOR EQ { {i=$1; v= "__equal"} } | OPERATOR NEQ { {i=$1; v= "__not_equal"} } | OPERATOR LT { {i=$1; v= "__less_than"} } | OPERATOR GT { {i=$1; v= "__greater_than"} } | OPERATOR OUTPUT { {i=$1; v= "__output"} } | OPERATOR INPUT { {i=$1; v= "__input"} } | OPERATOR LEQ { {i=$1; v= "__less_equal"} } | OPERATOR GEQ { {i=$1; v= "__greater_equal"} } | OPERATOR OR { {i=$1; v= "__or"} } | OPERATOR AND { {i=$1; v= "__and"} } | OPERATOR NOT { {i=$1; v= "__not"} } | OPERATOR AMP { {i=$1; v= "__addr"} } | OPERATOR DOT { {i=$1; v= "__dot"} } | OPERATOR LBRACK RBRACK { {i=$1; v= "__arrayelt"} } ; ret_typ: { (VoidT UNKNOWN, Rvalue, Mutable) } | ARROW typ passby { let (v,m) = $3 in ($2, v, m) } ; fun_def: FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ compound_stmt { let i = $1 in let ps = $6 in let inits = filter_map (fun (n,(t,v,m)) -> (match v with Rvalue -> Some (LetS (i, t, n, NewE (i, Stack, t, [VarE (i, n)]))) | Lvalue -> None)) ps in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) let body = if inits = [] then $9 else CompoundS (i, inits @ [$9]) in FunD ($1, $2.v, true, $3, $4, ps, $8, body) } | FUN fun_name STAR type_params where_clause LPAREN param_list RPAREN ret_typ compound_stmt { let i = $1 in let ps = $7 in let inits = filter_map (fun (n,(t,v,m)) -> (match v with Rvalue -> Some (LetS (i, t, n, NewE (i, Stack, t, [VarE (i, n)]))) | Lvalue -> None)) ps in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) let body = if inits = [] then $10 else CompoundS (i, inits @ [$10]) in FunD ($1, $2.v, false, $4, $5, ps, $9, body) } ; sig_decl: FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ SEMICOLON { let i = $1 in let ps = $6 in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) FunFwdD (i, $2.v, $3, $4, ps, $8) } | EXTERN STRING FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ SEMICOLON { let i = $1 in let ps = $8 in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) ExternFunFwdD (i, $2.v, $4.v, $5, $6, ps, $10) } | PRIMITIVE operator type_params LPAREN param_list RPAREN ret_typ SEMICOLON { PrimD ($1, $2, $3, $5, $7) } ; operator: PLUS { AddP } | OUTPUT { ShiftLeftP } | INPUT { ShiftRightP } | SUB { SubP } | NEG { NegP } | STAR { MultP } | DIV { DivP } | PERCENT { ModP } | DOT STAR { DerefP } | INC { IncP } | DEC { DecP } | AMP { AddrP } | EQ { EqP } | NEQ { NeqP } | LT { LessP } | LEQ { LessEqP } | GT { GreaterP } | GEQ { GreaterEqP } | LBRACK RBRACK { AtP } | AND { AndP } | OR { OrP } | NOT { NotP } | ASSIGN { AssignP } | alloc { NewP $1 } | alloc LBRACK RBRACK { NewArrayP $1 } | PLACEMENT_NEW { PlacementNewP } | DELETE { DeleteP } | DESTROY { DestroyP } | CAST { CastP } | SIZEOF { SizeofP } ; alloc: NEW { Heap } | AT { Stack } | NEW GC { GCHeap } ; where_clause: { ([],[]) } | WHERE LBRACE req_list RBRACE { let reqs = $3 in let creqs = filter_map (fun r -> match r with ModelR (i,cn,targs) -> Some (cn,targs) | _ -> None) reqs in let sames = filter_map (fun r -> match r with SameTypeR (i,s,t) -> Some (s,t) | _ -> None) reqs in (creqs,sames) } ; req: NAME LT typ_list GT { ModelR ($1.i, $1.v, $3) } | typ EQ typ { SameTypeR ($2, $1, $3) } ; req_list: { [] } | req { [$1] } | req COMMA req_list { $1::$3 } ; class_mem: typ NAME SEMICOLON { Field ($2.i, $2.v, $1) } | NAME LPAREN param_list RPAREN member_init_list compound_stmt { Constructor ($2, [], ([],[]), $3, $5, $6) } | type_params where_clause NAME LPAREN param_list RPAREN member_init_list compound_stmt { Constructor ($3.i, $1, $2, $5, $7, $8) } | TILDE NAME LPAREN RPAREN compound_stmt { Destructor ($1, $5) } | fun_def { (match $1 with FunD (i, _, _, _, _, _, _, _) -> error i "Sorry, G is not an object-oriented language. Please define your function outside the class." | _ -> error UNKNOWN "this can't happen") } ; class_mem_list: { [] } | class_mem class_mem_list { $1::$2 } ; concept_mem_list: { [] } | concept_mem concept_mem_list { $1::$2 } ; concept_mem: FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ SEMICOLON { FunC ($1, $2.v, $3, $4, $6, $8, None) } | FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ compound_stmt { FunC ($1, $2.v, $3, $4, $6, $8, Some $9) } | TYPE NAME SEMICOLON { AssocC ($1, $2.v) } | typ EQ typ SEMICOLON { SameTypeC ($2, $1, $3) } | REFINES NAME LT typ_list GT SEMICOLON { RefinesC ($1, $2.v, $4) } | REQUIRE NAME LT typ_list GT SEMICOLON { RequiresC ($1, $2.v, $4) } ; model_mem_list: { [] } | model_mem model_mem_list { $1::$2 } ; model_mem: FUN fun_name type_params where_clause LPAREN param_list RPAREN ret_typ compound_stmt { FunM ($1, $2.v, true, $3, $4, $6, $8, $9) } | FUN fun_name STAR type_params where_clause LPAREN param_list RPAREN ret_typ compound_stmt { FunM ($1, $2.v, false, $4, $5, $7, $9, $10) } | TYPE NAME ASSIGN typ SEMICOLON { AssocM ($1, $2.v, $4) } ; decl_list: decl { [$1] } | decl decl_list { $1::$2 } ; name_list: { [] } | NAME { [$1.v] } | NAME COMMA name_list { $1.v::$3 } ; param_list: { [] } | ELIPSES { [("", (ElipsesT $1, Rvalue, Constant))] } | ELIPSES AT { [("", (ElipsesT $1, Rvalue, Constant))] } | param { [$1] } | param COMMA param_list { $1::$3 } ; refer: { Lvalue } | AMP { Lvalue } ; mut: { Constant } | CONST { Constant } | BANG { Mutable } ; passby: AT { (Rvalue,Mutable) } | mut refer { (Lvalue, $1) } ; param: typ passby NAME { let (v,m) = $2 in ($3.v, ($1, v, m)) } | typ passby { let (v,m) = $2 in (Printf.sprintf "p_%d" (make_id()), ($1, v, m)) } ; struct_mem: typ NAME SEMICOLON { ($2.v,$1) } ; mem_list: { [] } | struct_mem mem_list { $1::$2 } ; stmt: expr SEMICOLON { ExprS ($2, $1) } | UNPACK LT name_list GT expr compound_stmt { CompoundS ($1, []) } | LET NAME ASSIGN expr SEMICOLON { LetS ($1, VoidT $1, $2.v, $4) } | RETURN expr SEMICOLON { ReturnS ($1, Some $2) } | RETURN SEMICOLON { ReturnS ($1, None) } | IMPORT import_expr FROM module_path rename SEMICOLON { ImportS ($1, $2, $4, $5) } | if_stmt { $1 } | while_stmt { $1 } | do_while_stmt { $1 } | for_stmt { $1 } | compound_stmt { $1 } | switch_stmt { $1 } | TYPE NAME ASSIGN typ SEMICOLON { TypedefS ($1, $2.v, $4) } | SEMICOLON { ExprS ($1, NullE $1) } ; if_stmt: IF LPAREN expr RPAREN stmt ELSE stmt { IfS ($1, $3, $5, $7) } | IF LPAREN expr RPAREN stmt { IfS ($1, $3, $5, CompoundS ($1, [])) } ; while_stmt: WHILE LPAREN expr RPAREN stmt { WhileS ($1, $3, $5) } ; do_while_stmt: DO stmt WHILE LPAREN expr RPAREN SEMICOLON { CompoundS ($1, [$2; WhileS ($3, $5, $2)]) } ; for_stmt: FOR LPAREN stmt expr SEMICOLON expr RPAREN stmt { let init = $3 in let cond = $4 in let inc = $6 in let body = [$8] @ [ExprS ($5,inc)] in CompoundS ($1, init::[WhileS ($1, cond, CompoundS ($7, body))]) } ; compound_stmt: LBRACE stmt_list RBRACE { CompoundS ($1, $2) } ; stmt_list: { [] } | stmt stmt_list { $1::$2 } ; switch_stmt: SWITCH LPAREN expr RPAREN LBRACE case_list RBRACE { SwitchS ($1, $3, $6) } ; case: CASE NAME COLON stmt_list { ($2.v, CompoundS ($1, $4)) } | DEFAULT COLON stmt_list { ("default", CompoundS ($1,$3)) } ; case_list: { [] } | case case_list { $1::$2 } ; tyname: NAME { VarT ($1.i, $1.v) } | STRUCT NAME { ClassT ($1, $2.v, []) } | UNION NAME { ClassT ($1, $2.v, []) } | NAME LT typ_list GT { ClassT ($1.i, $1.v, $3) } ; typ: tyname { $1 } | LPAREN typ RPAREN { $2 } | INTTY { IntT $1 } | SHORTTY { ShortT $1 } | LONGTY { LongT $1 } | LONGTY LONGTY { LongLongT $1 } | LONGTY DOUBLETY { LongDoubleT $1 } | VOIDTY { VoidT $1 } | FLOATTY { FloatT $1 } | DOUBLETY { DoubleT $1 } | BOOLTY { BoolT $1 } | STRINGTY { StringT $1 } | CHARTY { CharT $1 } | WCHARTY { WCharT $1 } | UNSIGNED CHARTY { UnsignedT ($1, CharT $1) } | SIGNED CHARTY { SignedT ($1, CharT $1) } | UNSIGNED INTTY { UnsignedT ($1, IntT $1) } | SIGNED INTTY { IntT $1 } | UNSIGNED SHORTTY { UnsignedT ($1, ShortT $1) } | SIGNED SHORTTY { ShortT $1 } | UNSIGNED LONGTY { UnsignedT ($1, LongT $1) } | SIGNED LONGTY { LongT $1 } | UNSIGNED LONGTY LONGTY { UnsignedT ($1, LongLongT $1) } | SIGNED LONGTY LONGTY { LongLongT $1 } | typ STAR %prec USTAR { PtrT ($2, $1) } | typ CONST STAR %prec USTAR { PtrT ($3, ConstT ($2, $1)) } | FUN type_params where_clause LPAREN param_list RPAREN ret_typ { let ps = List.map (fun (n,(t,v,m)) -> (t,v,m)) $5 in FunT ($1, $2, $3, ps, $7) } | tyname DOT NAME { match $1 with ClassT (i, n , ts) -> AssocT ($2, n, ts, $3.v) | _ -> error $2 "parse error" } | EXISTS LT name_list GT where_clause LBRACE typ RBRACE { IntT $1 } ; expr: term { $1 } | expr COMMA expr { SeqE ($2, [$1;$3]) } ; term: fun_name { VarE ($1.i, $1.v) } | NULLPTR { NullE $1 } | INT { IntE ($1.i, $1.v) } | FLOAT { FloatE ($1.i, $1.v) } | DOUBLE { DoubleE ($1.i, $1.v) } | STRING { StringE ($1.i, $1.v) } | CHAR { CharE ($1.i, $1.v) } | TRUE { BoolE ($1, true) } | FALSE { BoolE ($1, false) } | THIS { ThisE $1 } | LPAREN expr RPAREN { $2 } | expr QMARK expr COLON expr { IfE ($2, $1, $3, $5) } | FUN type_params LPAREN param_list RPAREN init_list compound_stmt { let i = $1 in let ps = $4 in let inits = filter_map (fun (n,(t,v,m)) -> (match v with Rvalue -> Some (LetS (i, t, n, NewE (i, Stack, t, [VarE (i, n)]))) | Lvalue -> None)) ps in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) let body = if inits = [] then $7 else CompoundS (i, inits @ [$7]) in FunE ($1, $2, ps, (VoidT $1,Rvalue,Constant), List.map (fun (n,e) -> (n,(e,VoidT $1))) $6, body) } | FUN type_params LPAREN param_list RPAREN init_list COLON expr { let i = $1 in let ps = $4 in let inits = filter_map (fun (n,(t,v,m)) -> (match v with Rvalue -> Some (LetS (i, t, n, NewE (i, Stack, t, [VarE (i, n)]))) | Lvalue -> None)) ps in (* why did I do this? -Jeremy let ps = map (fun (n,(t,v,m)) -> (match v with Rvalue -> (n,(t,Lvalue,Constant)) | Lvalue -> (n,(t,v,m)))) ps in *) let body = if inits = [] then CompoundS ($7, [ReturnS ($7, Some $8)]) else CompoundS (i, inits @ [ReturnS ($7, Some $8)]) in FunE ($1, $2, ps, (VoidT $1,Rvalue,Constant), List.map (fun (n,e) -> (n,(e,VoidT $1))) $6, body) } | expr LPAREN expr_list RPAREN { ApplyE ($2, $1, $3) } | expr LT BAR typ_list BAR GT { InstE ($3, $1, $4) } | MODEL NAME LT typ_list GT DOT fun_name { ModelMemE ($1, $2.v, $4, $7.v) } | CAST LT typ GT LPAREN expr RPAREN { ApplyE ($1, InstE ($1, PrimE ($1, CastP), [$3]), [$6]) } | SIZEOF LPAREN expr RPAREN { ApplyE ($1, PrimE ($1, SizeofP), [$3]) } | SIZEOF LT typ GT { SizeofE ($1, $3) } | expr ASSIGN expr { ApplyE ($2, VarE ($2, "__assign"), [$1;$3]) } | expr ARROW NAME { MemE ($2, ApplyE ($2, VarE ($2, "__star"), [$1]), $3.v) } | expr DOT NAME { MemE ($2, $1, $3.v) } | AMP expr %prec UAMP { ApplyE ($1, VarE ($1, "__addressof"), [$2]) } | PRIMITIVE operator { PrimE ($1, $2) } | STAR expr %prec USTAR { ApplyE ($1, VarE ($1, "__star"), [$2]) } | expr LBRACK expr RBRACK { ApplyE ($2, VarE ($2, "__arrayelt"), [$1;$3]) } | SUB expr %prec USUB { ApplyE ($1, VarE ($1, "__sub"), [$2]) } | INC expr { ApplyE ($1, VarE ($1, "__increment"), [$2]) } | DEC expr { ApplyE ($1, VarE ($1, "__decrement"), [$2]) } | expr PLUS expr { ApplyE ($2, VarE ($2, "__add"), [$1;$3]) } | expr SUB expr { ApplyE ($2, VarE ($2, "__sub"), [$1;$3]) } | expr STAR expr { ApplyE ($2, VarE ($2, "__star"), [$1;$3]) } | expr DIV expr { ApplyE ($2, VarE ($2, "__div"), [$1;$3]) } | expr EQ expr { ApplyE ($2, VarE ($2, "__equal"), [$1;$3]) } | expr NEQ expr { ApplyE ($2, VarE ($2, "__not_equal"), [$1;$3]) } | expr LT expr { ApplyE ($2, VarE ($2, "__less_than"), [$1;$3]) } | expr GT expr { ApplyE ($2, VarE ($2, "__greater_than"), [$1;$3]) } | expr LEQ expr { ApplyE ($2, VarE ($2, "__less_equal"), [$1;$3]) } | expr GEQ expr { ApplyE ($2, VarE ($2, "__greater_equal"), [$1;$3]) } | expr OR expr { ApplyE ($2, VarE ($2, "__or"), [$1;$3]) } | expr AND expr { ApplyE ($2, VarE ($2, "__and"), [$1;$3]) } | expr PERCENT expr { ApplyE ($2, VarE ($2, "__mod"), [$1;$3]) } | NOT expr { ApplyE ($1, VarE ($1, "__not"), [$2]) } | alloc typ LPAREN expr_list RPAREN { NewE ($3, $1, $2, $4) } | NEW LPAREN expr RPAREN typ LPAREN expr_list RPAREN { PlacementNewE ($1, $3, $5, $7) } | alloc typ LBRACK expr RBRACK { match $1 with Stack -> error $3 "May not stack allocate dynamically sized arrays" | _ -> NewArrayE ($3, $1, $2, $4) } | alloc tyname LBRACE init_list RBRACE { (* struct or union creation *) match $2 with VarT (i, n) -> StructE ($3, $1, n, [], $4) | ClassT (i, n , ts) -> StructE ($3, $1, n, ts, $4) | _ -> error UNKNOWN "expected a type name after new" } | DELETE expr { DeleteE ($1, $2) } | DESTROY expr { DestroyE ($1, $2) } | PRIMITIVE NEW alloc typ LPAREN expr_list RPAREN { ApplyE ($1, InstE ($1, PrimE ($1, NewP $3), [$4]), $6) } | PRIMITIVE NEW alloc typ LBRACK expr RBRACK { ApplyE ($1, InstE ($1, PrimE ($1, NewArrayP $3), [$4]), [$6]) } | expr OUTPUT expr { ApplyE ($2, VarE ($2, "__output"), [$1;$3]) } | expr INPUT expr { ApplyE ($2, VarE ($2, "__input"), [$1;$3]) } ; expr_list: { [] } | term { [$1] } | term COMMA expr_list { $1::$3 } ; typ_list: { [] } | typ { [$1] } | typ COMMA typ_list { $1::$3 } ; init_list: { [] } | init { [$1] } | init COMMA init_list { $1::$3 } ; init: NAME { ($1.v, VarE ($1.i, $1.v)) } | NAME ASSIGN expr { ($1.v, $3) } member_init_list: { [] } | COLON mem_init_list { $2 } ; mem_init_list: mem_init { [$1] } | mem_init COMMA mem_init_list { $1::$3 } ; mem_init: NAME LPAREN expr_list RPAREN { ($1.v, $3) } ;