我发现了一个练习,需要一个技巧来理解语法是否为LR(1)而没有解析表操作。
语法如下:
public static void installMouseMotionListenerOnAll(Component c, MouseMotionListener mml) {
c.addMouseMotionListener(mml);
if (c instanceof Container) {
for (Component child : ((Container)c).getComponents()) {
installMouseMotionListenerOnAll(child, mml);
}
}
}
你知道背后的诀窍是什么?
谢谢,))
答案 0 :(得分:1)
想象一下,你是一个LR(1)解析器,而你刚刚读过aab
并且前瞻b
。 (我知道,你可能在想“男人,这一直发生在我身上!”)你究竟应该在这做什么?
查看语法,您无法判断初始制作是Aa
还是Bb
,因此您必须同时考虑A
的制作规则以及B
。如果您查看A
选项,您会看到此处的一个选项是减少A
→ab
,这在这里是合理的,因为前瞻是b
这正是您在展开ab
后看到A
后所期望的结果(注意有规则A
→aRb
,所以任何递归扩展A
之后会有b
。所以这告诉你减少。另一方面,请查看B
选项。如果您看到aab
后跟b
,那么您会想到“哦,那第二个b
将会aabb
,然后我会去减少B
→abb
,因为这是我喜欢做的事情,因为我是LR(1)解析器。“所以这告诉你转移。那时,bam!你有一个转换/减少冲突,所以你几乎肯定不会有LR(1)语法。
那实际上是这样吗?那么,让我们构建LR(1)配置集,如果我们确实阅读了aab
并看到b
作为预测,我们会看到它们:
Initial State
S' -> .S [$]
S -> .Aa [$]
S -> .Bb [$]
A -> .aAb [a]
A -> .ab [a]
B -> .aBbb [b]
B -> .abb [b]
State after reading a
A -> a.Ab [a]
A -> a.b [a]
A -> .aAb [b]
A -> .ab [b]
B -> a.Bbb [b]
B -> a.bb [b]
B -> .aBbb [b]
B -> .abb [b]
State after reading aa
A -> a.Ab [b]
A -> a.b [b]
A -> .aAb [b]
A -> .ab [b]
B -> a.Bbb [b]
B -> a.bb [b]
B -> .aBbb [b]
B -> .abb [b]
State after reading aab
A -> ab. [b]
B -> ab.b [b]
嘿!我们谈论的是那种转变/减少冲突。第一个项目在b上减少,但第二个项目在b上减少。你去吧!我们的直觉使我们认为这不是LR(1)语法,如果我们查看表格,数据就支持证据。
那你怎么知道尝试呢?嗯,总的来说,这很难做到。对我来说,主要的提示是,解析器必须在某个时候猜测它是否需要A
或B
,但它的抢先方式是b
s的数量。解析器必须在某个时刻确定它是否喜欢ab
并与A
一起使用,或者它是否喜欢abb
并与B
一起使用,但它可以在做出决定之前,不要看到b
两个。这让我觉得我们想找到某种冲突,我们已经看到足够的知道发生了一些递归(以便尾随b
会引起问题)并找到一个地方递归在两个生产规则之间会有所不同。