简单的回答:你不能。优先级(和关联性)仅适用于产生式(左侧)和终端(右侧)。它们不适用于非终端。
这不是一个武断的决定。这是野牛处理移位/减少冲突的方式所固有的。在每个解析步骤中,前瞻标记(终端)最终都必须被移动,但有可能在终端移动之前存在可以减少的产生式。如果不立即执行缩减,则永远不会执行。LR(1) 语法允许解析器根据当前的解析堆栈和前瞻标记来决定是否应该执行缩减或是否应该立即移动前瞻标记。如果这两个动作都是可能的,则称该文法存在移位/归约冲突,严格来说它不是 LR(1)。
优先级和关联性规则用于解决移位/减少冲突。产生式可能具有隐含或显式优先级:显式优先级由%prec
宣言; 否则使用生产中最后一个终端的优先级。在发生移位/减少冲突的情况下,将可以减少的生产的优先级与可以移位的先行终端的优先级进行比较,并且具有较大优先级的优先级获胜。而已。优先级不会保留或继承。事实上,说比较优先级是不准确的,因为在解析期间不会发生这种情况。解析器有一个动作或转换表,它定义了在特定堆栈配置(“状态”)和前瞻令牌的情况下要做什么,并且优先级信息在解析器生成时用于填写动作表中的条目否则会模棱两可。
在您的生产中
binary_op: '|' %prec BINARY_OP
%prec
声明是无用的,因为binary_op
必须立即减少;它不能参与移位/减少冲突。shift/reduce 冲突伴随着non_keyword_expression
生产而来,它标有(不同的)%prec
声明,这就是将用于该生产的声明。
for 的产生non_keyword_expression
式没有终结符,因此也没有隐含的优先级。这通常不是您想要的,并且使用以下产品:
binary_op: '|' | "OR" ;
与使用优先级解决解析冲突并不真正兼容。
注 1:如果您要求 GLR 解析器,这并不完全正确。GLR 解析器可以同时执行移位和归约,因为它(有效地)同时维护多个解析器状态。最终,除了其中一种状态之外,所有状态都必须被消除;否则,解析是不明确的。GLR 解析器使用优先级(和%prec
声明)的方式与非 GLR 解析器完全相同;被优先级消除的解析器动作确实被消除了,并且不会导致并行状态。但是,GLR 解析器也可以处理归约/归约冲突,其中有两种可能的归约(可能是同一个非终结符)。这些冲突可以使用%dprec
(“动态优先级”)声明来解决。