I was wondering how to handle variable references inside statements when writing grammars with ocamlyacc and ocamllex.
The problem is that statements of the form
var x = y + z var b = true | f;
must be correct, but in the first case the variable refers to numbers, and in the second case f
is a logical variable.
In the grammar I'm writing, I have this:
numeric_exp_val: | nint { Syntax.Int $1 } | FLOAT { Syntax.Float $1 } | LPAREN; ne = numeric_exp; RPAREN { ne } | INCR; r = numeric_var_ref { Syntax.VarIncr (r,1) } | DECR; r = numeric_var_ref { Syntax.VarIncr (r,-1) } | var_ref { $1 } ; boolean_exp_val: | BOOL { Syntax.Bool $1 } | LPAREN; be = boolean_exp; RPAREN { be } | var_ref { $1 } ;
which, obviously, cannot work, since both var_ref
non-terminal are reduced to the same thing (reduction / reduction conflict). But I would like to have type checking, which is mostly statically performed (regarding variable references) during the analysis phase itself.
This is why I am wondering what is the best way to have variable references and maintain this structure. As additional information, I have functions that compile the syntax tree by translating it into byte code like this:
let rec compile_numeric_exp exp = match exp with Int i -> [Push (Types.I.Int i)] | Float f -> [Push (Types.I.Float f)] | Bop (BNSum,e1,e2) -> (compile_numeric_exp e1) @ (compile_numeric_exp e2) @ [Types.I.Plus] | Bop (BNSub,e1,e2) -> (compile_numeric_exp e1) @ (compile_numeric_exp e2) @ [Types.I.Minus] | Bop (BNMul,e1,e2) -> (compile_numeric_exp e1) @ (compile_numeric_exp e2) @ [Types.I.Times] | Bop (BNDiv,e1,e2) -> (compile_numeric_exp e1) @ (compile_numeric_exp e2) @ [Types.I.Div] | Bop (BNOr,e1,e2) -> (compile_numeric_exp e1) @ (compile_numeric_exp e2) @ [Types.I.Or] | VarRef n -> [Types.I.MemoryGet (Memory.index_for_name n)] | VarIncr ((VarRef n) as vr,i) -> (compile_numeric_exp vr) @ [Push (Types.I.Int i);Types.I.Plus;Types.I.Dupe] @ (compile_assignment_to n) | _ -> []