我有一个LR(1)冲突的语法,我无法解决;然而,语法应该是明确的。我将首先使用五个令牌来简化语法上的问题:(
,)
,{}
,,
和id
。
EBNF看起来像这样:
args = ( id ',' )*
expression = id
| '(' expression ')'
| '(' args ')' '{}'
语法是明确的,最多需要两个前瞻标记。当(
移位时,只有五种可能性:
(
→Recur。)
→缩减为'(' args ')'
。id
)
而非{}
→缩减为'(' expression ')'
。id
)
{}
→缩减为'(' args ')' '{}'
id
,
→缩减为'(' args ')' '{}'
(最终)。天真的翻译会产生以下结果(和conflicts):
formal_arg: Ident
{}
formal_args: formal_arg Comma formal_args
| formal_arg
| /* nothing */
{}
primary: Ident
| LParen formal_args Curly
| LParen primary RParen
{}
因此,语法最多需要三个前瞻标记来决定。我知道LR(3)语法can be transformed到LR(1)语法。
但是,我不太了解如何在这种特殊情况下进行转换。请注意,上面的简化语法是从larger body of code中提取的;特别是,是否可以在不触及primary
以及上述所有内容的情况下转换expr
?
答案 0 :(得分:1)
我在这里提供了一个非常类似问题的解决方案:Is C#'s lambda expression grammar LALR(1)?。基本想法是将( id )
案例与其他两种可能性(( expr_not_id )
和( list_at_least_2_ids )
)区分开来。然后可以推迟关于如何减少( id )
的决定,直到前瞻标记可用(在您的情况下,{
,假设这已足够)。
不幸的是,虽然将expr
转换为expr_not_id
非常简单且几乎是机械的,但它绝对涉及很多制作。而且,它有点难看。所以它无法解决你在最后一句中出现的问题。我实际上并不认为可以在不触及primary
的情况下转换expr
,但我之前一直感到惊讶。
(另一个明显的解决方案,因为语法实际上是明确的,是使用GLR解析器生成器,但我不相信你使用的解析器生成器具有该功能。)