如果第二条规则失败,请尝试第一条规则 [英] Try the first rule if the second rule fails
问题描述
我定义了两组标识符 IDENTIFIER_ONE
和 IDENTIFIER_TWO
,它们都是 IDENTIFIER
的专有子集.我想编写一个解析器:
I have defined two sets of identifiers IDENTIFIER_ONE
and IDENTIFIER_TWO
which are both exculsive subsets of IDENTIFIER
. I would like to write a parser such that:
"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)
:
where i1
(resp., i2
) belongs to IDENTIFIER_ONE
(resp., IDENTIFIER_TWO
); arg
and value
belong to IDENTIFIER
. The following parser.mly
has already realized all the points I am after, except (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
就不行了被解析.
Given i1(arg) = value EOS
as input, as goal (3)
it is correctly read as BSE_Let (i1, arg, value)
. However, given i2(arg) = value EOS
as input, it stops the parsing after reading EQUAL
. I guess it is because once the parse meets i2(arg)
, it goes to the 2nd rule of block_statement_EOS
, and later EQUAL
can't be parsed.
理想情况下,如果第二条规则失败,我希望解析器可以尝试 block_statement_EOS
的第一条规则.有人能帮我实现这个吗?
Ideally, I would hope the parser could try the 1st rule of block_statement_EOS
if the 2nd rule fails. Could anyone help me to make this possible?
PS:如果我把parser.mly
写成如下,所有的目标都可以实现.有谁知道为什么?此外,我真的不喜欢这种解决方法,因为我确实需要编写 identifier
而不是许多其他规则中的两个子集,我希望有一个更优雅的解决方案...
PS: If I write the parser.mly
as follows, all the goals can be achieved. Does anyone know why? Additionally I really don't like this workaround, because I do need to write identifier
instead of two subsets in many other rules, I would hope a more elegant solution...
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) }
推荐答案
当你的解析器遇到 IDENTIFIER_TWO
之后的 LPAREN
时,它必须决定是移还是移减少:
When your parser encounters an LPAREN
after an IDENTIFIER_TWO
, it has to decide whether to shift or to reduce:
- shift:将
LPAREN
放入栈中; - reduce:用
identifier
替换栈顶的IDENTIFIER_TWO
.
- shift: put
LPAREN
on the stack; - reduce: replace
IDENTIFIER_TWO
, which is on top of the stack, byidentifier
.
如果你的解析器选择移动,它永远不会将这个特定的 IDENTIFIER_TWO
减少到 identifier
(因为这个特定的 IDENTIFIER_TWO
永远不会在上面堆栈再次),这意味着它总是会减少block_statement_EOS
的第二条规则.
If your parser chooses to shift, it will never reduce this particular IDENTIFIER_TWO
into identifier
(because this particular IDENTIFIER_TWO
will never be on top of the stack again), meaning that it will always reduce the second rule of block_statement_EOS
.
如果您的解析器选择减少,它永远不会减少 block_statement_EOS
的第二条规则,因为该规则以 IDENTIFIER_TWO
而不是 identifier
开头.
If your parser chooses to reduce, it will never reduce the second rule of block_statement_EOS
, as this rule starts with IDENTIFIER_TWO
and not identifier
.
这就是您的第二个版本有效的原因,因为在 IDENTIFIER_TWO
之后无需在移位和减少之间进行选择.如果您愿意,可以稍后进行选择.
This is why your second version works, because there is no need to choose between shifting and reducing after IDENTIFIER_TWO
. The choice is made later, if you wish.
这篇关于如果第二条规则失败,请尝试第一条规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!