【问题标题】:Bison shift/reduce conflict with balanced parentheses grammar野牛移位/减少与平衡括号语法的冲突
【发布时间】:2020-05-31 09:30:58
【问题描述】:

我正在练习平衡括号的语法:

S -> (S)

S -> SS

S -> ()

编译器返回一个移位/减少冲突。这是我的野牛语法:

%%
prog:
  srule
;

srule 
    : ( srule )
    | srule srule 
    | ( )
;
%%

谁能给我解释一下原因以及如何在不改变语法的情况下解决它?

【问题讨论】:

  • 不改语法是解决不了的,除非使用%prec%assoc不被认为是改语法。你确定你转录正确吗?
  • 更改语法非常简单,例如使用此语法即可:S -> (S)S | ε。我想知道移位/减少的原因以及在这种情况下如何使用优先运算符。再次感谢您。

标签: bison yacc


【解决方案1】:

您的语法不明确,不明确的语法总是会产生冲突。那是因为歧义意味着会有两个不同的解析是可能的,这意味着两个不同的解析动作是可能的。这是解析冲突的定义。

歧义非常明显。 S: S S 表示两个S 的串联是有效的S。但是()()() 都是有效的S。所以你可以通过连接()()() 来创建一个新的S,或者你可以通过连接()()() 来创建一个新的S。不幸的是,它们都是相同新的S,并且语法没有指定要使用哪种分解。

修复语法是一种方法,修复非常简单。我们只需要指定当连接两个平衡的句子时,第一个本身不能是一个连接。这意味着()•()() 是一个有效的组合,但()()•() 不是。

正如您在评论中所指出的,通过将连接规则替换为S: ( S ) S,可以很简单地使用此要求修改语法。该规则中的两个文字括号匹配,这意味着第一个 S 之前的规则部分不能是串联。

但是我们可以使用正常的 yacc/bison 机制来处理模棱两可的语法。我们需要做的就是要求解析器始终解决冲突以支持归约操作。 (这不是一个通用的解决方案,但它可以在这里工作。)

为了使 yacc/bison 优先规则生效,可能减少的右侧必须比可能移动的前瞻字符具有更高的优先级。右侧的优先级被指定为右侧第一个标记的优先级,但不幸的是我们感兴趣的右侧——连接规则——根本没有任何标记.所以我们需要用%prec 标记来标记它。因为我们知道前瞻符号总是() 没有歧义,因为解析器必须减少直到 ) 可以移动),我们可以将产生式标记为具有优先级( 然后声明 ( 是右结合的,这意味着减少优先于移位:

%right '('
%%
%%
srule: '(' srule ')'
     | '(' ')'
     | srule srule %prec '('

其实上面%right的使用完全是任意的。如果我们从明确的语法S → S ( S ) | ε 而不是S → ( S ) S | ε 开始,我们将创建一个左关联组合,其中()()() 必须分解为()()•() 而不是()•()()。这将通过将上述 Bison sn-p 中的 %right 更改为 %left 来实现,这将导致在生成的解析器中更有效地使用解析器堆栈。

【讨论】:

  • 如果我将其声明为左关联而不是右关联,会发生什么变化? %left '('。我问它是因为通过尝试它可以平等地解决冲突并且测试成功。
  • @valerio:然后它和S->S(S) | ε 做同样的事情,产生左倾解析。但识别出的是同一组字符串。
  • 我只是想我应该提到这一点。我稍后会编辑答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-20
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 2013-07-09
相关资源
最近更新 更多