如何处理yacc/bison中的变量引用(使用ocaml)

Jac*_*ack 4 variables grammar ocaml yacc compilation

我想知道如何在用ocamlyacc和ocamllex编写语法时处理语句中的变量引用.

问题是表格的陈述

var x = y + z
var b = true | f;
Run Code Online (Sandbox Code Playgroud)

应该是正确的,但在第一种情况下,变量引用数字,而在第二种情况下,f变量是布尔变量.

在我写的语法中我得到了这个:

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 }
;
Run Code Online (Sandbox Code Playgroud)

这显然是行不通的,因为两个var_ref非终端减少到相同(减少/减少冲突).但我希望在解析阶段本身进行大多数静态类型检查(关于变量引用).

这就是为什么我想知道哪个是变量引用的最佳方法并保持这种结构.正如附加信息一样,我有一些函数可以通过将语法树转换为与此类似的字节代码来编译语法树:

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) 
    | _ -> []
Run Code Online (Sandbox Code Playgroud)

gas*_*che 9

解析根本不是进行类型检查的正确位置.我不明白为什么你坚持在这个传球中这样做.通过单独传递,您可以拥有更清晰的代码和更强大的表现力.

这是出于效率原因吗?我相信你可以在其他地方设计有效的增量打字例程,从语法生成中调用(但我不确定你会赢得那么多).这看起来像是过早优化.

已经开始编写类型系统作为属性语法(可以看作是表达类型派生的声明方式),但我认为它不是要在一次通过中混合解析和键入.

如果你真的想在这方面走得更远,我会建议你在num-typed和bool-typed变量之间使用简单的词法区分.这听起来很难看但很简单.