如果我的一个规则与另一个规则的一部分扩展相同,我将如何标记优先级?例如,我有一个expression IS type
规则,它应该递归地将type
扩展为type DOT identifier
。但在相同的规则expression
中,我有expression DOT identifier
,野牛将其报告为冲突。很明显,我希望作为表达式类型部分的所有DOT
一起减少为type
,而不是作为表达式。Ie:a is b.c.d
应该解析为(a is b.c.d)
,其中b.c.d
是type
而不是(a is b).c.d
。以下是显示冲突的最小语法:
%require "3.0"
%defines
%define api.pure full
%define parse.trace
%token DOT '.'
%token IS "is"
%left DOT
%left IS
%%
example
: expression
;
expression
: expression DOT identifier
| expression IS type
| identifier
;
type
: fqtypename
;
fqtypename
: identifier
| fqtypename DOT identifier
;
identifier:
"blah"
;
%%
和错误:
State 10
5 type: fqtypename •
7 fqtypename: fqtypename • DOT identifier
DOT shift, and go to state 12
DOT [reduce using rule 5 (type)]
$default reduce using rule 5 (type)
从冲突状态中可以看出,冲突实际上与IS
令牌无关。相反,冲突是在转移DOT
和减少产量type: fqtypename
之间,您希望将其解决为转移DOT
。
事实上,这是没有任何优先级声明的默认解决方案。Bison和Yacc一样,自动解决shift-release冲突以支持shift,并减少冲突以支持语法文件中较早出现的生产。您可以在粘贴的状态表中看到该分辨率(DOT
在该状态下发生了偏移(。当然,每次生成解析器时都会看到野牛警告,这并不理想。您可以通过使用%expect
声明来避免警告,该声明基本上告诉Bison预期自动解决的减少移位冲突的数量。对于最近的Bison版本,您可以将声明附加到产品本身,这使得期望更加精确。请参阅Bison手册的链接,其中显示了一个与您的语法有点相似的语法示例。
再做一点工作,就可以使用优先级声明来实现同样的效果,其优点是稍微更精确,但代价是使语法变得更神秘。下面是一个基于你问题中语法的例子。请注意,%prec
声明附加到实际参与冲突的生产中。因为该产品根本没有终端符号,所以有必要使用伪令牌来表示优先级。
/* I removed the token names for '.' and "is" to make the grammar shorter. */
%left TYPE_UNIT
%left '.'
%%
example
: expression
expression
: expression '.' identifier
| expression "is" type
| identifier
type
: fqtypename %prec TYPE_UNIT
fqtypename
: identifier
| fqtypename '.' identifier
identifier:
"blah"