Bison 野牛移位/减少A:::=AA规则中的冲突
我编写了以下bison语法文件: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的移位/减少冲突。我已将问题提取
%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
这可能是您想要的,也可能不是您想要的。。。