Parsing 如何解决LR(1)三元表达式(a?b:c)和“a”之间的语法歧义;也许吧;表达方式(a?)?
我创建了一个语法,其精简版本如下:Parsing 如何解决LR(1)三元表达式(a?b:c)和“a”之间的语法歧义;也许吧;表达方式(a?)?,parsing,lr,shift-reduce-conflict,glr,Parsing,Lr,Shift Reduce Conflict,Glr,我创建了一个语法,其精简版本如下: (0) exp1: ternary; (1) exp1: exp2; (2) ternary: exp2 "?" exp1 ":" exp1; (3) exp2: exp2 "+" exp3; (4) exp2: exp3; (5) exp3: maybe; (6) exp3: "1"; (7) maybe: exp3 "?"; 我相信这种语言是明确的,应该是LR-parsable。(如果我错了,请告诉我!) 但是,当我尝试为该语法生成LR(1)解析器时,会
(0) exp1: ternary;
(1) exp1: exp2;
(2) ternary: exp2 "?" exp1 ":" exp1;
(3) exp2: exp2 "+" exp3;
(4) exp2: exp3;
(5) exp3: maybe;
(6) exp3: "1";
(7) maybe: exp3 "?";
我相信这种语言是明确的,应该是LR-parsable。(如果我错了,请告诉我!)
但是,当我尝试为该语法生成LR(1)解析器时,会出现移位/减少冲突,因为当解析器看到带有lookahead的exp3
?,它不知道是移位还是减少:
Conflicts in state 3:
Reduction using rule 4: exp2: exp3 · | "?"
Shift to state 6
Conflicts in state 9:
Reduction using rule 3: exp2: exp2 "+" exp3 · | "?"
Shift to state 6
Conflicts in state 13:
Reduction using rule 4: exp2: exp3 · | "?"
Shift to state 16
Conflicts in state 20:
Reduction using rule 4: exp2: exp3 · | "?"
Shift to state 23
Conflicts in state 25:
Reduction using rule 3: exp2: exp2 "+" exp3 · | "?"
Shift to state 23
Conflicts in state 28:
Reduction using rule 3: exp2: exp2 "+" exp3 · | "?"
Shift to state 16
对于我来说,有没有一种合理的方法使这种语言LR(1)-可分析(没有冲突)?
或者GLR(或者可能是LR(2))是我对这种语言唯一现实的选择吗?(或者说,我一开始就认为语言是明确无误的,这是错误的吗?)
作为参考,我生成的不明确状态机如下(其中♦ 是(EOF):
我认为这可能是一个优先问题。当解析器看到以下内容时,就会发生冲突:
a + b ? c : d
当解析器看到a+b?
并查看c
时,它无法决定是否需要
b?
,以便它将解析形式为a+(b?
的表达式,然后从那里继续,或者a+b
,以便它将解析形式为(a+b)的表达式?c:d
?
具有非常低的优先级(当用作三元运算符时),而在另一种情况下,它具有非常高的优先级(当用作一元运算符时)。但是,如果您确实以这种方式分配了先例,我认为解析器可能能够消除这些情况的歧义
希望这有帮助 语法不是模棱两可的事实并不一定意味着它是LR可分析的。任何确定性CFL都至少有一个LR(1)语法,所有确定性CFL也都有明确的语法。然而,并非所有明确的语法都描述确定性CFL。@templatetypedef:对,我知道明确性并不意味着LR可分析性,但我认为这一个确实是LR可分析的(似乎LR(2)可以很好地处理它,但不确定)。你是说不是?(例如,它是否需要无限的前瞻性?)嗯,
a+b?c:d
应该被解析为(a+b)?c:d
而不是a+(b?c:d)
,对吗?在这种情况下,一旦看到c
,它就知道该构造是一个三元表达式。(我试图在C语言中保留?
的语义。)@Mehrdad-啊,是的,我错了。这才是减少冲突的真正转变。我会更新我的答案。然而,我仍然认为这是一个优先问题。啊,是的,好吧,从我们的角度来看,这是一个优先问题(我确实需要一元?
比三元?
绑定得更紧),但解析器生成器实际上没有任何“优先”的概念;它只是解析语法,语法隐含了优先级。我不知道你所说的“如果你确实这样分配了先例”是什么意思。。。你是建议我改变语法隐含的先例(我不能这样做,因为语义会改变),还是你的意思是我应该用其他方法来修正它?你在使用什么解析器生成器?大多数标准的LR解析器生成器(yacc
,bison
等)都允许使用优先级规范,因为它大大简化了语法的编写。@Mehrdad-你太棒了!实际上,将先例合并到LR(1)解析器生成器中并不难,而且它极大地简化了语法创建。其基本思想是,每当发生移位/减少冲突时,您都会根据生产中第一个终端相对于前向终端的优先级来确定是移位还是减少。紫龙书有一些关于如何做到这一点的细节。除此之外,您需要重写大量语法来隐式地强制执行优先级,这是相当棘手的。由你决定。
a + b ? c : d