If statement OCaml中的Yacc NULL?

If statement OCaml中的Yacc NULL?,if-statement,ocaml,yacc,ocamlyacc,If Statement,Ocaml,Yacc,Ocamlyacc,我正在OCamlyacc和ocamlex中实现以下语法: my 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

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

my 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 ($3, $5, ???) } /*line 1*/
   |    IF LPAREN e RPAREN stmt ELSE stmt       { S.IF ($3, $5, $7) }  /*line 2*/
但是,如果问号用于没有ELSE行1的IF语句,那么如何为语句类型stmt设置NULL?我无权访问只有表达式exp和一条语句的语句类型


我曾考虑过在那里放一个while0{print0}语句,但这不是你应该做的,特别是因为它将在while语句中解析,而它不应该这样做。

一个解决方案是显式地添加一个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
如果您不能修改您的类型,您仍然可以执行虚拟assignment:lv=lv

另一个可能更干净的解决方案是显式地添加 如果对您的语句执行以下操作:

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的帖子,但我无法修改OCaml中的类型规则。因此,禁止添加新规则或扩展任何类型

我终于明白我该做什么了。我认为OCaml中缺少了一些特别的东西,所以我故意省略了这个特定任务的细节,我认为这些细节会让我的问题变得模糊,但实际上是有用的

让我给出我的答案,但首先让我给出一些额外的细节:

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

stmt:
   |    IF LPAREN e RPAREN stmt ELSE stmt       { S.IF ($3, $5, $7) }  /*line 1*/
   |    IF LPAREN e RPAREN stmt                 { S.IF ($3, $5, S.BLOCK ([],[])) } /*line 2*/
你基本上保留了ELSE,但你只是在空的大括号里放了一个空的或者什么都不做的动作

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

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