0

我已经定义了两组标识符IDENTIFIER_ONEIDENTIFIER_TWO它们都是IDENTIFIER. 我想写一个解析器,这样:

"i1(arg) EOS" can't be parsed (1)
"i2(arg) EOS" can be parsed (2)
"i1(arg) = value EOS" can be parsed (3)
"i2(arg) = value EOS" can be parsed (4)

其中i1(resp., i2) 属于IDENTIFIER_ONE(resp., IDENTIFIER_TWO); arg并且value属于IDENTIFIER。以下parser.mly已经实现了我所追求的所有要点,除了(4)

identifier:
| IDENTIFIER_ONE { $1 }
| IDENTIFIER_TWO { $1 } 

block_statement_EOS:
| identifier LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EOS { BSE_I_I ($1, $3) }

作为i1(arg) = value EOS输入,作为目标(3),它被正确读取为BSE_Let (i1, arg, value). 但是,i2(arg) = value EOS作为输入,它会在读取后停止解析EQUAL。我猜是因为一旦解析遇到i2(arg),它就会进入 的第二条规则block_statement_EOS,之后EQUAL就无法解析了。

block_statement_EOS理想情况下,如果第二条规则失败,我希望解析器可以尝试第一条规则。谁能帮助我使这成为可能?

PS:如果我写parser.mly如下,所有的目标都可以实现。有谁知道为什么?另外我真的不喜欢这种解决方法,因为我确实需要identifier在许多其他规则中编写而不是两个子集,我希望有一个更优雅的解决方案......

block_statement_EOS:
| IDENTIFIER_ONE LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EQUAL identifier EOS { BSE_Let ($1, $3, $6) }
| IDENTIFIER_TWO LPAREN identifier RPAREN EOS { BSE_I_I ($1, $3) }
4

1 回答 1

0

当您的解析器遇到LPARENafter anIDENTIFIER_TWO时,它必须决定是移位还是减少:

  • shift:LPAREN入栈;
  • 减少:将IDENTIFIER_TWO堆栈顶部的替换为identifier

如果您的解析器选择转换,它永远不会将这个特定元素归约为IDENTIFIER_TWOidentifier因为这个特定IDENTIFIER_TWO元素永远不会再次位于堆栈顶部),这意味着它将始终归约block_statement_EOS.

如果您的解析器选择归约,它永远不会归约 的第二条规则block_statement_EOS,因为这条规则以IDENTIFIER_TWOand not开头identifier

这就是您的第二个版本有效的原因,因为无需在 shift 和 reduce after 之间进行选择IDENTIFIER_TWO。如果您愿意,稍后会做出选择。

于 2014-01-29T09:37:59.770 回答