LL(1)-parser需要一个先行符号才能决定使用哪种产品。这就是我一直认为使用术语“超前”的原因,当解析器查看下一个输入令牌而不“消耗”它时(即,它仍然可以通过下一个动作从输入中读取)。然而,LR(0)解析器让我怀疑这是正确的:
我见过的LR(0)-parsers的每个例子也使用下一个输入标记来决定是移位还是减少。 如果减少,则不会消耗输入令牌。
我使用免费软件工具“ParsingEmu”生成LR表并在下面对单词“aab”执行LR评估。如您所见,列标题包含标记。从评估中可以看出,解析器通过查看下一个输入令牌来决定使用哪个列。但是当解析器在步骤4到6中减少时,输入不会改变(尽管解析器在执行到下一个状态的转换时需要知道下一个输入标记“$”。)
语法:
S -> A
A -> aA
A -> b
表:
评价为:
现在我因为混淆而做出以下假设:
我对“lookahead”定义的假设(lookahead =输入令牌未被消耗)是错误的。 Lookahead对于LL解析器或LR解析器来说只意味着两种不同的东西。如果是这样,那么如何定义“先行”?
LR解析器(从理论上来说,当你使用下推自动机时)有额外的内部状态,它们通过将输入令牌放在堆栈上来消耗输入令牌,因此能够进行移位 - 通过查看堆栈来减少决策。
上面显示的评估是LR(1)。如果为真,那么LR(0)评估会是什么样的?
现在什么是正确的,1,2或3或完全不同的东西?
答案 0 :(得分:2)
准确地说,这很重要:
LR ( k )解析器使用curent解析器状态和 k 前瞻符号来决定是否 reduce ,如果是的话,通过哪种生产。
它还使用移位转换表来决定在移动下一个输入令牌之后它应该移动到哪个解析状态。无论 k 的值如何,移位转换表都由当前状态和(单个)转移键控。
如果在给定的解析器状态中,可以同时生成shift和reduce操作,则解析器会发生shift / reduce冲突,并且它无效。因此,理论上可以非确定地进行上述两个确定。
如果在给定的解析器状态中,不可能进行reduce,并且下一个输入符号不能被移位(也就是说,该输入符号没有转换该状态),则解析失败并且算法终止。 / p>
另一方面,如果移位转换导致指定的Accept状态,则解析成功并且算法终止。
所有这一切意味着前瞻用于预测应该应用哪种减少(如果有的话)。在 LR (0)解析器中,必须在读取下一个输入标记之前做出移位(更准确地说,尝试移位)的决定,但是要转换为do的状态的计算在读取令牌之后,如果不能进行换档,它将发出错误信号。
LL ( k )解析器必须在看到非终端时预测哪个生产替换非终端。基本LL算法以包含[ S , $ ](从上到下)的堆栈开始,并且在完成之前执行以下任何一项:
如果堆栈顶部是非终端,则使用下一个 k 输入符号来替换堆栈顶部的非终端产品之一哪一个(不移动输入光标),然后继续。
如果堆栈顶部是终端,请读取下一个输入令牌。如果它是同一个终端,则弹出堆栈并继续。否则,解析失败并且算法结束。
如果堆栈为空,则解析成功并且算法结束。 (我们假设在输入结束时有一个唯一的EOF标记 $ 。)
在这两种情况下,前瞻都有相同的含义:它包括查看输入令牌而不移动输入光标。
如果 k 为0,则:
LR ( k )解析器必须决定是否在不检查输入的情况下进行缩减,这意味着没有状态可以有两个不同的reduce操作或减少和转移行动。
LL ( k )解析器必须在不检查输入的情况下决定给定非终端的哪个产品是可用的。实际上,这意味着每个非终端只能有一个产品,这意味着语言必须是有限的。