OCaml 中的 Yacc NULL?

Yacc NULL in OCaml?

我正在 OCamlyacc 和 OCamllex 中实现以下语法:

我的 IF-ELSE 子句的 OCaml 类型声明如下:

(* Some code not shown *)
and stmt  = ASSIGN of lv * exp
      | IF of exp * stmt * stmt 
      | WHILE of exp * stmt
      | DOWHILE of stmt * exp
      | READ of id
      | PRINT of exp 
      | BLOCK of block
(* Some code not shown *)

我可以这样定义 OCamlyacc 中的 IF-ELSE 部分:

stmt:
   |    IF LPAREN e RPAREN stmt                 { S.IF (, , ???) } /*line 1*/
   |    IF LPAREN e RPAREN stmt ELSE stmt       { S.IF (, , ) }  /*line 2*/

但是,如何将 "NULL" 用于 语句 类型 ("stmt"),其中问号用于 没有 ELSE(第 1 行)的 IF 语句?我无法访问只有一个 表达式 ("exp") 并且只有一个 语句的 语句 类型.

我考虑过在其中放置一个 "while(0){print(0)}" 语句 ,但这不是你应该做的,特别是因为它会在 while-statement 不应该的时候。

一个解决方案可以是显式添加一个 nop 语句,该语句根据定义不执行任何操作。

stmt  = ASSIGN  of lv   * exp
      | IFTE    of exp  * stmt * stmt
      | WHILE   of exp  * stmt
      | DOWHILE of stmt * exp
      | READ    of id
      | PRINT   of exp 
      | BLOCK   of block
      | NOP

如果你不能修改你的类型,你仍然可以做虚拟赋值:lv = lv

在我看来,另一个可能更干净的解决方案是显式添加 if-then 操作你的语句:

stmt  = ASSIGN  of lv   * exp
      | IFTE    of exp  * stmt * stmt
      | IFT     of exp  * stmt  
      | WHILE   of exp  * stmt
      | DOWHILE of stmt * exp
      | READ    of id
      | PRINT   of exp 
      | BLOCK   of block

感谢 ghilesZ 的 post,但我无法修改 OCaml 中的类型规则。因此,禁止添加新规则或扩展任何类型。

我终于明白我必须做什么了。我认为 OCaml 中有一些我遗漏的特别之处,所以我故意省略了这个特定任务的细节,我认为这些细节只会掩盖我的问题,但实际上很有用。

让我展示一下我对此的回答,但首先让我提供一些额外的细节:

因此,通过使用上面的语法规则和下面提供的 OCaml,解决方案是:

stmt:
   |    IF LPAREN e RPAREN stmt ELSE stmt       { S.IF (, , ) }  /*line 1*/
   |    IF LPAREN e RPAREN stmt                 { S.IF (, , S.BLOCK ([],[])) } /*line 2*/

你基本上保留了 ELSE,但你只是放入了空花括号,有效地放入了一个 "NULL" 或一个 "do-nothing" 动作。

最后,我翻转了顺序,因为要正确解析这两个 IF 语句,您需要设置优先级,这可以通过以下方式完成:

%nonassoc RPAREN  /* Right parenthesis */
%nonassoc ELSE