2014-10-03 173 views
1

考虑下面的野牛语法(这是从一个更大的语法我正在剥了下来):为什么%prec在这个野牛语法中没有效果?

%token ident 
%left '+' 
%left CALLPREC 

%% 

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

显然没有先例解析表达式像foo + bar()时,有一个S/R冲突。我试图理解为什么%prec声明不能解决这个冲突。我使用的是野牛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

回答

6

移位/减少冲突的野牛优先分辨率通过的两个令牌和规则具有优先级。当发现移位/缩小冲突时,野牛比较要缩小的规则的优先级和要移动的令牌的优先级,并选择较高的优先级。 A %prec指令只是设置规则的优先顺序;它对令牌的优先级没有影响。

在你的语法冲突(不确定性)来自输入像

ident '+' ident '(' ')' 

可以解析为无论是附加在第二个操作数是呼叫,或作为呼叫,其中被叫expr是一个加。它在移位/归约解析器中表现为在看到expr + expr输入之后减少add规则和移动'('令牌之间的移位/减少冲突 。因此,所有重要的是add规则和'('令牌的优先级 - 由于呼叫尚未被识别,所以call规则的优先级是不相关的。

由于显式设置的调用规则的优先级永远不会用于解决任何冲突,因此会得到第二个警告。

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

+0

很清楚,谢谢!我有你所描述的错误观念。现在我已经发布了,我看到[你回答了几乎相同的问题](http://stackoverflow.com/questions/2068637/shift-reduce-problem-with-c-like-grammar-under-bison)四几年前也是如此。 – 2014-10-04 01:04:56