Bison 野牛移位/减少A:::=AA规则中的冲突

Bison 野牛移位/减少A:::=AA规则中的冲突,bison,yacc,operator-precedence,shift-reduce-conflict,Bison,Yacc,Operator Precedence,Shift Reduce Conflict,我编写了以下bison语法文件: %left '+' '-' %left '*' '/' %token NUMBER %% expr : NUMBER | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | expr expr %prec '*' /* implicit multiplication */ ; 现在,bison报告了有关expr:expr expr expr的移位/减少冲突。我已将问题提取

我编写了以下bison语法文件:

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

%token NUMBER

%%

expr
: NUMBER
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| expr     expr %prec '*' /* implicit multiplication */
;
现在,
bison
报告了有关
expr:expr expr expr
的移位/减少冲突。我已将问题提取到以下最小集:

%left OP

%%

expr
: 'a'
| expr expr %prec OP
;
我不明白为什么野牛仍然抱怨移位/减少冲突。我发现了一些旧的邮件档案:,但我也不理解作者的解释

有人能解释一下为什么这个语法不明确,以及如何解决冲突吗


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

部分答案是仔细查看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
它无法判断是否将其解析为:

(编号OP编号)编号 expr expr

或作为:

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


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

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

expr expr %prec MISSING
这并没有改变任何事情。通过在其他操作符之前列出MISSING,也不会使其优先级非常低

如果你考虑一个这样的表达式应该如何解析,你就会明白问题:

NUMBER OP NUMBER NUMBER NUMBER OP NUMBER NUMBER OP NUMBER

其中OP在每个外观中都是相同的。我的脑子疼!野牛也是如此

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

现在,您可以通过为
NUMBER
添加优先级来修复此语法(使其与
*
相同),但如果您为表达式添加任何以
NUMBER
以外的任何标记开头的规则,则会返回该语法-例如,如果您添加
expr:'('expr')”
,则会在
上得到移位/减少冲突(“

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


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

你希望相邻的数字做什么?@JonathanLeffler,我将实际上,我想实现隐式乘法,这样星号就可以在例如“4*(1+2)”->“4(1+2)”中省略您的回答非常详细,谢谢。唉,它并没有解决最初的问题,因为我已经用
%prec'*'
显式地设置了
expr:expr expr
规则优先级。正如我所描述的,问题在于精简语法。是的,您是对的。我最终解决了这个问题,将
NUMBER
声明为
%nonassoc NUMBER优先于其他优先级声明,因此其他规则总是被缩减(如我所愿)。这是一个有点难看的解决方案,但我找不到任何其他方法来覆盖任意标记的优先级。将其设置为最低优先级意味着
NUM+NUM
将被解析为
(NUM+NUM)NUM
这可能是您想要的,也可能不是您想要的。。。