【问题标题】:Bison shift/reduce conflict in A ::= AA ruleA ::= AA 规则中的 Bison shift/reduce 冲突
【发布时间】:2012-02-11 18:49:02
【问题描述】:

我写了以下野牛语法文件:

%left '+' '-'
%left '*' '/'

%token NUMBER

%%

expr
: NUMBER
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| expr     expr %prec '*' /* implicit multiplication */
;

现在bison 报告关于expr : expr expr 的移位/减少冲突。我已将问题提取到以下最小集合:

%left OP

%%

expr
: 'a'
| expr expr %prec OP
;

我不明白为什么 bison 仍然抱怨 shift/reduce 冲突。我找到了一些旧邮件存档:Re: bison/yacc: shift/reduce conflict using %prec for composition,但我也不明白作者的解释。

有人能解释一下为什么这个语法有歧义,以及如何解决冲突吗?

编辑:NUMBER NUMBER 我的意思是NUMBER * NUMBER,即这两个数字的乘积。

【问题讨论】:

  • 你希望相邻的数字做什么?
  • @JonathanLeffler,我将它们相乘。实际上,我想实现隐式乘法,以便可以省略星号,例如"4*(1+2)" -> "4(1+2)

标签: bison yacc operator-precedence shift-reduce-conflict


【解决方案1】:

这里的问题是令牌NUMBER 没有优先级。因此,当有一个状态可以转移 NUMBER 或减少规则(无论该规则是否具有优先级)时,它无法决定该做什么。

现在您可以通过为NUMBER 添加优先级来修复此语法(使其与* 相同),但如果您为表达式添加任何以除@ 以外的任何标记开头的规则,它将返回987654325@ -- 例如,如果您添加 expr: '(' expr ')',您将在 '(' 上遇到 shift/reduce 冲突。

更大的问题是,如果您添加一元前缀运算符,例如expr: '-' expr。在这种情况下,您不会遇到冲突,因为“-”已经具有优先级,但是像 NUMBER - NUMBER 这样的输入将被解析为 NUMBER ( - NUMBER ),这可能根本不是您想要的。没有用优先规则处理这个问题的好方法。

造成这种混淆的根本原因是,bison 的优先规则不能通过比较两个规则来解决优先级问题,正如您基于使用“优先级”一词可能天真地期望的那样。相反,它们通过将要减少的规则的“优先级”与要转移的令牌的“优先级”进行比较,并以此为基础决定转移或减少。在解析中发生这种情况的地方,第二条规则尚未被识别;相反,野牛只是根据令牌猜测它可能是什么。

【讨论】:

  • 是的,你是对的。我终于通过将NUMBER 声明为%nonassoc NUMBER before 其他优先级声明来解决了这个问题,因此其他规则总是被减少(如我所愿)。这是一个有点丑陋的解决方案,但我找不到任何其他方法来覆盖任意令牌的优先级。
  • 将其设为最低优先级意味着NUM + NUM NUM 将被解析为(NUM + NUM) NUM,这可能是也可能不是您想要的...
【解决方案2】:

部分答案是仔细查看来自bison -v 的输出文件。对于你的第一个语法,我得到了这些摘录:

State 8 conflicts: 1 shift/reduce
State 9 conflicts: 1 shift/reduce
State 10 conflicts: 1 shift/reduce
State 11 conflicts: 1 shift/reduce
State 12 conflicts: 1 shift/reduce

Grammar

    0 $accept: expr $end

    1 expr: NUMBER
    2     | expr '+' expr
    3     | expr '-' expr
    4     | expr '*' expr
    5     | expr '/' expr
    6     | expr expr

所以语法中有 5 个移位/归约冲突。这些是不太严重的冲突类型;如果您确信语法所做的事情是正确的,您可以在语法中使用%expect 5 声明您期望它们。

state 0

    0 $accept: . expr $end

    NUMBER  shift, and go to state 1

    expr  go to state 2

state 1

    1 expr: NUMBER .

    $default  reduce using rule 1 (expr)

state 2

    0 $accept: expr . $end
    2 expr: expr . '+' expr
    3     | expr . '-' expr
    4     | expr . '*' expr
    5     | expr . '/' expr
    6     | expr . expr

    $end    shift, and go to state 3
    '+'     shift, and go to state 4
    '-'     shift, and go to state 5
    '*'     shift, and go to state 6
    '/'     shift, and go to state 7
    NUMBER  shift, and go to state 1

    expr  go to state 8

state 3

    0 $accept: expr $end .

    $default  accept

state 4

    2 expr: expr '+' . expr

    NUMBER  shift, and go to state 1

    expr  go to state 9

状态 5、6、7 模拟状态 4,但适用于其他运算符。状态 8 是第一个发生转移/减少冲突的状态。请记住,规则中的.(点)表示解析器到达此状态时所处的位置。

state 8

    2 expr: expr . '+' expr
    3     | expr . '-' expr
    4     | expr . '*' expr
    5     | expr . '/' expr
    6     | expr . expr
    6     | expr expr .

    NUMBER  shift, and go to state 1

    NUMBER    [reduce using rule 6 (expr)]
    $default  reduce using rule 6 (expr)

    expr  go to state 8

state 9

    2 expr: expr . '+' expr
    2     | expr '+' expr .
    3     | expr . '-' expr
    4     | expr . '*' expr
    5     | expr . '/' expr
    6     | expr . expr

    '*'     shift, and go to state 6
    '/'     shift, and go to state 7
    NUMBER  shift, and go to state 1

    NUMBER    [reduce using rule 2 (expr)]
    $default  reduce using rule 2 (expr)

    expr  go to state 8

这两个状态有区别也有相似之处,但是状态10、11、12匹配状态9除了歧义点不同。

麻烦的是,当语法看到:

NUMBER OP NUMBER NUMBER

它无法判断是否将其解析为:

(号码操作号码)号码 expr 表达式

或作为:

NUMBER OP ( NUMBER NUMBER )
 expr  OP       expr

鉴于在每种情况下都是移位/减少冲突,它选择移位。如果这就是您想要的,那么添加%expect 5 并继续生活。如果那不是你想要的,那么你需要重新考虑你的语法。一对相邻的数字表示什么,您确定不需要一些运算符字符(可能是逗号或冒号)来分隔它们吗?


我尝试使用以下方法提高缺失运算符的优先级:

%left MISSING

在其他优先级声明之后,然后使用:

expr expr %prec MISSING

这并没有改变任何东西。通过将 MISSING 列在其他运算符之前也不会降低 MISSING 的优先级。

如果您考虑应该如何解析这样的表达式,您就会对问题有所了解:

NUMBER OP NUMBER NUMBER NUMBER OP NUMBER NUMBER OP NUMBER

每次出现的 OP 都相同。我的脑袋好痛! bison's 也是如此!

【讨论】:

  • 你的回答很详细,谢谢。唉,它没有解决原始问题,因为我已经明确地将expr : expr expr 规则优先级设置为%prec '*'。正如我所描述的,问题在于缩小的语法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多