为什么没有预先对这个野牛语法产生影响?

时间:2014-10-03 23:54:11

标签: parsing compiler-construction bison

考虑下面的Bison语法(这是从我正在研究的更大的语法中删除的):

%token ident
%left '+'
%left CALLPREC

%%

start: add ';' ;
expr: ident | call |  add ;
call: expr '(' ')' %prec CALLPREC ;
add: expr '+' expr ;

在解析像foo + bar()这样的表达式时,显然没有优先权就会出现s / r冲突。我试图理解为什么%prec声明无法解决冲突。我使用的是Bison 3.0.2,它似乎认为该指令毫无用处:

$ bison -r state,solved -Wall  ambigram.y 
ambigram.y: warning: 1 shift/reduce conflict [-Wconflicts-sr]
ambigram.y:5.1-5: warning: useless precedence and associativity for CALLPREC [-Wprecedence]

奇怪的是,取消%prec CALLPREC并声明%left '('可以解决冲突,但声明%left ')'却没有。这与我对Bison文档的期望相反,后者说[by] default, the precedence of a rule is that of its last token

1 个答案:

答案 0 :(得分:6)

移位/减少冲突的Bison优先解决方案通过在两个令牌和规则上具有优先级来工作。当它发现移位/减少冲突时,bison会比较要减少的规则的优先级和要移位的令牌的优先级,并选择更高的优先级。 %prec指令只设置规则的优先级;它对令牌的优先顺序没有影响。

语法中的冲突(含糊不清)来自

之类的输入
ident '+' ident '(' ')'

可以解析为第二个操作数是调用的add,也可以解析为被调用的expr是add的调用。它表示移位/缩小解析器作为移位/减少冲突 在看到add输入后减少'('规则和转移expr + expr令牌之间的关系。因此,重要的是add规则和'('令牌的优先级 - call规则的优先级无关紧要,因为呼叫尚未被识别。

在您的情况下,您会收到第二个警告,因为调用规则的显式设置优先级永远不会用于解决任何冲突。

我已经想到了编写yacc变体的想法,该变体能够以更符合大多数人直觉的方式处理优先级。它不是优先于令牌,而是在规则上只有 。当发生转移/减少冲突时,它会将要减少的规则的优先级与转移令牌后可以减少的规则的优先级进行比较。这可能无法解决冲突(如果转变导致多个规则可以减少,一些更高的优先级和一些更低的规则),但通常会更灵活,并且不太可能通过以意想不到的方式解决冲突来使人们陷入困境。