改变语法以消除移位减少if-then-else中的冲突

时间:2012-10-04 16:44:13

标签: bison shift-reduce-conflict

如何针对给定语法删除bison的shift-reduce冲突?

 selection-stmt -> if ( expression ) statement |
                      if ( expression ) statement else statement

提供修改过的语法的解决方案将受到高度赞赏。

3 个答案:

答案 0 :(得分:37)

有一个更简单的解决方案。如果你知道LR解析器是如何工作的,那么你知道冲突发生在这里:

if ( expression ) statement * else statement

其中星号标记光标的当前位置。解析器必须回答的问题是“我应该转移,还是应该减少”。通常,您希望将else绑定到最近的if,这意味着您现在要转移else令牌。现在减少意味着您希望else等待绑定到“较旧”if

现在,您想“告诉”您的解析器生成器“当令牌"else"与规则”stm - >之间存在转换/减少冲突时if(exp)stm“,那么令牌必须赢”。为此,请为您的规则优先级“命名”(例如"then"),并指定"then"的优先级低于"else"。类似的东西:

// Precedences go increasing, so "then" < "else".
%nonassoc "then"
%nonassoc "else"
%%
stm: "if" "(" exp ")" stm            %prec "then"
   | "if" "(" exp ")" stm "else" stm

使用Bison语法。

实际上,我最喜欢的答案是赋予"then""else"相同的优先权。当优先级相等时,为了打破想要转移的令牌和想要减少的规则之间的联系,Bison / Yacc将查看关联性。在这里,你想要促进权利相关性(更准确地说,你想促进“转变”),所以:

%right "then" "else" // Same precedence, but "shift" wins.

就足够了。

答案 1 :(得分:6)

你需要认识到if-else案例中的中间statement不能(或以其结尾)悬挂if(如果没有其他的话)。最简单的方法是拆分stmt规则为两个:

stmt -> stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if
stmt-not-ending-with-dangling-if ->
    if ( expression ) stmt-not-ending-with-dangling-if else stmt-not-ending-with-dangling-if |
    ...other statements not ending with dangling if...
stmt-ending-with-dangling-if ->
    if ( expression ) stmt |
    if ( expression ) stmt-not-ending-with-dangling-if else stmt-ending-with-dangling-if |
    ...other statements ending with dangling if...

其他stmt -> whatever规则whatever未以stmt结尾的内容符合stmt-not-ending-with-if规则,而任何stmt规则均以stmt结尾not-ending-with-if分为两个版本; not-ending-with-if规则中的dangling-if版本和dangling-if规则中的stmt : stmt-ending-with-dangling-if | stmt-not-ending-with-dangling-if stmt-not-ending-with-dangling-if : IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-not-ending-with-dangling-if | WHILE '(' expr ')' stmt-not-ending-with-dangling-if | DO stmt WHILE '(' expr ')' ';' | expr ';' | '{' stmt-list '}' stmt-ending-with-dangling-if: IF '(' expr ')' stmt | IF '(' expr ')' stmt-not-ending-with-dangling-if ELSE stmt-ending-with-dangling-if | WHILE '(' expr ')' stmt-ending-with-dangling-if 版本。

修改

与其他作品更完整的语法:

WHILE (expr) stmt

stmt之类的规则会被分成两部分(因为它们以expr;结尾),而像{{1}}这样的规则却没有。{/ p>

答案 2 :(得分:0)

使if else比正常语句更高级别,例如:

statements:
  statements lineEnd statement
| statements lineEnd IfStat
| statements lineEnd IfElseStat
| IfStat
| IfElseStat
;
IfStat:
  if ( statement )
;
IfElse:
  IfStat else statement
;