到目前为止,我在Google上搜索过的内容,LALR(1)和SLR(1)之间的唯一区别是LALR(1)使用具有合并前瞻集的状态。有消息称,LALR(1)不会遇到移位减少冲突,因为解析器会记住"记住"它来自哪个州的现状。但是,解析算法没有区别,因此我很难看到这些合并的前瞻集如何帮助LALR解析器解决shift-reduce冲突。如果解析器记得它到达当前状态的状态,为什么它仍然容易受到减少 - 减少冲突的影响?
答案 0 :(得分:1)
实际上是使用合并前瞻套件的SLR。或者,更准确地说,SLR解析表中每个生产的前瞻集近似为生产中最后一个符号的FOLLOW集,有效地忽略了上下文。
LALR解析器已经针对规范LR解析器合并了状态。在LR和LALR中,与SLR相比,精确计算了先行集,但在LALR解析器的情况下,状态被合并,因此它具有与SLR解析器相同的状态(但不是相同的前瞻集)
对维基百科关于SLR解析,LALR解析和Canonical LR解析的文章中的差异进行了合理的讨论。有关详细信息,请参阅这些文章的参考资料。
无论您使用哪种解析器生成技术,如果语法需要更多前瞻,都会出现冲突。例如,以下语法需要两个lokahead符号来决定是否移位或减少NAME
:
prog → λ
prog → prog defn
defn → NAME :
defn → defn NAME
这里,NAME是defn
的一部分,如果它后面没有冒号,那么要决定是否要移动NAME,你不仅需要NAME,这是前瞻标记,但是也是tge跟随令牌,第二个前瞻。
这是一个非常简单的语法,它不是SLR(1),它可能会使用跟随集来解决问题。 (它直接来自龙书,并经常被用作SLR(1)语法不足的原因的例子:
S → L = R
S → R
L → id
L → * R
R → L
这里,ROLL和L的FOLLOW集是相同的。 R和L都包含=
,因为* R = ...
有效,并且将减少到L = ...
,并且显然R和L都可以出现在S的末尾,因此两个FOLLOW集包括输入结束标记。
然后问题是决定是否减少R → L
。在L = R
中,我们应该保留L
并转移=
。但是FOLLOW集没有帮助,因为R
可以跟=
。因此,在仅使用FOLLOW集的SLR(1)语法中,状态中存在移位/减少冲突:
S → L • = R
R → L •
LALR(1)语法中不存在此冲突,因为在该状态下
为生产R → L
设置的前瞻不包括=
,因为生产是从项目S → • R
中包含的,其前瞻是输入结束标记。