为什么%prec不会影响这个野牛语法?

Wim*_*wis 2 compiler-construction parsing bison

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

%token ident
%left '+'
%left CALLPREC

%%

start: add ';' ;
expr: ident | call |  add ;
call: expr '(' ')' %prec CALLPREC ;
add: expr '+' expr ;
Run Code Online (Sandbox Code Playgroud)

显然没有优先权,在解析表达式时会出现/ r冲突foo + bar().我试图理解为什么%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]
Run Code Online (Sandbox Code Playgroud)

奇怪的是,消除%prec CALLPREC和宣告%left '('解决了冲突,但声明%left ')'没有.这与我对Bison文档的期望相反,后者说默认情况下,规则的优先级是其最后一个标记的优先级.

Chr*_*odd 7

具有对优先级移位野牛优先分辨率/减少冲突的作品标记和规则.当它发现移位/减少冲突时,bison会比较要减少的规则的优先级和要移位的令牌的优先级,并选择更高优先级的优先级.一个%prec指令只设置一个规则的优先级; 它对令牌的优先级没有影响.

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

ident '+' ident '(' ')'
Run Code Online (Sandbox Code Playgroud)

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

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

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