【问题标题】:Resolve conflict in bison grammar with space separated expression lists + if/then/else用空格分隔的表达式列表 + if/then/else 解决野牛语法中的冲突
【发布时间】:2018-05-29 15:40:40
【问题描述】:

我有以下yacc/bison/happy语法:

%token 
  if              TokenIf
  then            TokenThen
  else            TokenElse
  true            TokenTrue
  false           TokenFalse

%left APP
%right IF

%%

Hungry
  : NoHungry
  | Hungry NoHungry %prec APP
  | if Hungry then Hungry else Hungry %prec IF

NoHungry
  : true
  | false

bison -v 告诉我以下情况有两个冲突:

State 12

    2 Hungry: Hungry . NoHungry
    3       | if Hungry then Hungry else Hungry .

    true   shift, and go to state 2
    false  shift, and go to state 3

    true      [reduce using rule 3 (Hungry)]
    false     [reduce using rule 3 (Hungry)]
    $default  reduce using rule 3 (Hungry)

    NoHungry  go to state 8

我试图通过使用%prec 给出明确的优先级声明来解决冲突,但无济于事。鉴于野牛根据需要解决冲突(例如,转变而不是减少),这还不错,但我想知道我们如何在不改变接受的语言的情况下摆脱冲突。

【问题讨论】:

    标签: bison yacc parser-generator shift-reduce-conflict happy


    【解决方案1】:

    从野牛报告中可以看出,冲突是与终端truefalse 的冲突,它们没有在优先关系中列出。因此,优先规则不适用于这些冲突。

    回想一下,在产生式和终端之间定义了优先关系。它不涉及两个终端或两个产生式(因此不能用于解决归约-归约冲突)。可以减少的生产的优先级与前瞻终端之间的比较确定是否会发生减少或转移。为方便起见,产生式由终端名称表示,通常是产生式中唯一的终端;这对应于一个常见的用例,但有时会令人困惑。特别是,%prec 声明仅用于为规则命名以在优先声明中使用,并且以这种方式考虑它可能比作为“显式”声明更好。

    简而言之,您问题中简化语法的冲突可以通过在优先关系中显式添加适当的终端来解决:

    %precedence "if"
    %precedence "true" "false"
    
    %%
    
    Hungry
      : NoHungry
      | Hungry NoHungry
      | "if" Hungry "then" Hungry "else" Hungry %prec "if"
    
    NoHungry
      : "true"
      | "false"
    

    摘自-v输出:

    State 12
    
        2 Hungry: Hungry . NoHungry
        3       | "if" Hungry "then" Hungry "else" Hungry .
    
        "true"   shift, and go to state 2
        "false"  shift, and go to state 3
    
        $default  reduce using rule 3 (Hungry)
    
        NoHungry  go to state 8
    

    通过使用-r solved 而不是-v,您可以更明确地看到分辨率:

        Conflict between rule 3 and token "true" resolved as shift ("if" < "true").
        Conflict between rule 3 and token "false" resolved as shift ("if" < "false").
    

    我本可以使用"else" 作为if 产品的名称,如果没有%prec 声明,这将是默认名称,但"if" 似乎更直观。

    %precedence 声明(在最近的野牛版本中可用)并不意味着左关联或右关联;在这种情况下,关联性不适用,因为不存在冲突涉及同等优先级的产生和终结的情况。如果 Happy 没有实现它,%left%right 都可以用于相同的原因(关联性无关紧要),但我认为 %precedence 更好地记录了这种情况。

    由于这无疑是一个简化的例子,值得注意的是,更完整的语法需要一些语法分析。特别是,优先级大于 "if" 的终端列表必须包括 FIRST(NoHungry) 中的所有终端,并且 bison 不提供执行该计算的自动工具,尽管您通常可以从 shift-reduce 中提取列表冲突报告。 (甚至可能"if" 是集合的一部分,在这种情况下关联性很重要。)

    【讨论】:

    • 非常有帮助,谢谢!事实上,激励语法是一个 lambda 演算,但我能够解决与您的答案的冲突。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2021-10-04
    相关资源
    最近更新 更多