如何将这个语法转换为LR(1)?

时间:2013-06-30 03:10:20

标签: parsing lr

我有一个LR(1)冲突的语法,我无法解决;然而,语法应该是明确的。我将首先使用五个令牌来简化语法上的问题:(){},id

EBNF看起来像这样:

      args = ( id ',' )*

expression = id
           | '(' expression ')'
           | '(' args ')' '{}'

语法是明确的,最多需要两个前瞻标记。当(移位时,只有五种可能性:

  1. (→Recur。
  2. )→缩减为'(' args ')'
  3. id )而非{}→缩减为'(' expression ')'
  4. id ) {}→缩减为'(' args ')' '{}'
  5. id ,→缩减为'(' args ')' '{}'(最终)。
  6. 天真的翻译会产生以下结果(和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

1 个答案:

答案 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解析器生成器,但我不相信你使用的解析器生成器具有该功能。)