下面是AA野牛语法这说明我的问题。 我使用的实际语法是比较复杂的。
%glr-parser
%%
s : e | p '=' s;
p : fp | p ',' fp;
fp : 'x';
e : te | e ';' te;
te : fe | te ',' fe;
fe : 'x';
输入的一些例子是:
x
x = x
x,x = x,x
x,x = x;x
x,x,x = x,x;x,x
x = x,x = x;x
我后是对的“=”左侧X的比右边要分析不同。 然而,该组可以对一个“=”右边出现合法“表述”的 - 符号比左侧大(因为“;”)。
野牛打印消息(输入文件是test.y):
test.y: conflicts: 1 reduce/reduce.
必须有解决这个问题的一些方式。 在C语言中,你有类似的情况。 下面的程序通过,没有错误的gcc。
int main(void) {
int x;
int *px;
x;
*px;
*px = x = 1;
}
在这种情况下,“PX”和“X”得到不同的待遇取决于他们是否出现一个“=”的左边或右边 - 标志。
您正在使用%glr-parser
,所以没有需要“修复”减少/减少冲突。 野牛只是告诉你有一个,让你知道你的语法可能是不明确的,所以你可能需要加用模糊分辨率%dprec
或%merge
指令。 但是,在你的情况下,语法也不含糊,所以你不需要做任何事情。
冲突是不是一个错误,它只是一个参考,你的语法不是LALR(1)。
在你的语法的降低,减少冲突来自于背景:
... = ... x ,
在这一点上,解析器有权决定是否x
是fe
或fp
,它不能用一个符号前瞻知道。 事实上,它不知道任何有限的前瞻,你可以有任意数量的重复x ,
下面没有遇到一个点=
, ;
或输入,其中的任何一个会揭晓答案的结束。
这是不太一样的C的问题,可以用单个符号先行解决。 然而,C的例子就是为什么SLR(1)语法比LALR不那么强大的一个典型例子(1)语法 - 它用于龙书的目的 - 和类似问题的语法之间的差异的例子LALR(1)和LR(1); 它可以在野牛手册(找到这里 ):
def: param_spec return_spec ',';
param_spec: type | name_list ':' type;
return_spec: type | name ':' type;
type: "id";
name: "id";
name_list: name | name ',' name_list;
(野牛手册介绍如何解决此问题的LALR(1)语法,虽然使用GLR语法始终是一种可能性。)
解决这种冲突,而无需使用GLR语法的关键是避免强迫解析器做出过早的决定。
例如,它是对传统的左值和右值之间的语法区别,有的语言继续这样做。 C和C ++不这样做,但是, 这证明是C中的非常强大的特征++,因为它允许的能够作为左值起作用的功能的定义。
在C语言中,我认为这只是简化的语法有点:表示C语法允许任何一元运算符的结果出现在赋值运算符的左侧,但一元运算符实际上是左值的混合( *v
, v[expr]
和右值( sizeof v
, f(expr)
)。 语法可以有两种元运算符之间区分,但它解决不了实际的限制,这是只可修改左值可能出现在赋值运算符的左侧。
C ++允许任意表达式出现在赋值运算符的左手侧(虽然某些需要被括号); 因此,以下是完全合法的:
(predicate(x) ? *some_pointer : some_variable) = 42;
在你的情况,你可以通过更换语法解决冲突te
与p
,由于两个非终端产生相同的一组推导的。 这可能不是一般的解决办法,除非是真的在你那左侧表达式是右侧表达式的严格的子集完整语法的情况。 在一个完整的语法,你可能最终有三个类型的表达式(左只,右只,普通),这可能相当复杂的语法,并留下了语义分析的分辨率可能被证明是更容易(甚至,如在C ++中,令人惊讶的是有用的)的情况下。