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
我正在 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