我先了解并遵循,但我完全迷失在预测集上。有人可以向我解释如何使用第一组和后续集来查找语法中的预测集合吗?我没有提供语法,因为这是一个家庭作业,我想知道怎么做,而不是如何为这个特定的语法做。
答案 0 :(得分:0)
直观地说,生产A → α
[注1]的预测集是一组终端符号,如果要预测该生产,它可能是下一个要读取的符号。 (这意味着生产的非终端(A
)已被预测,解析器现在必须决定预测哪个非终端的产品。)
显然,这包括所有可能是右侧第一个符号的终端符号。但是,如果右侧可能派生ε,空字符串怎么办?在这种情况下,输入中的下一个符号将是在预测的非终端A
之后的第一个符号;换句话说,它将是FOLLOW(A)
的成员。因此,如果α
可以派生出空字符串,则预测集包含可能从右侧FOLLOW(A)
开始的终端,以及α
中的所有符号。 [注2]
更正式地说,PREDICT(A → α)
是:
FIRST(α)
if ε ∉ FIRST(α)
(FIRST(α) ∪ FOLLOW(A)) - {ε}
if ε ∈ FIRST(α)
请记住,我们通过“浏览”epsilons来计算句子形式上的FIRST
:
FIRST(aβ)
是
FIRST(a)
if ε ∉ FIRST(a)
(FIRST(a) - {ε}) ∪ FIRST(β)
if ε ∈ FIRST(a)
因此,如果右侧的每个符号都可以为空,则右侧的FIRST
仅包含ε
。
我使用大写字母(A
...)引用非终端的常见约定,小写字母(a
...)引用语法符号(终端)或非终端)和希腊字母(α
...)指的是可能空的语法符号序列。
除了预测起始符号的第一步之外,当前预测始终包含多个符号。因此,如果A
是下一个要扩展的非终端,并且我们看到它可以为空(即,它可能无法获取),我们实际上不需要查找FOLLOW(A)
因为我们可以看一下预测堆栈,看看我们预测会跟随A
。在某些情况下,这可能会让我们避免与A
的其他替代方案发生冲突。
但是,无论如何,使用FOLLOW(A)
是正常的。始终使用FOLLOW(A)
通常称为“强LL”(SLL)算法。虽然计算已知预测堆栈的第一组似乎比使用预先计算的FOLLOW集更强大,但它实际上并没有提高LL解析的能力;每个非LL语法都可以转换为SLL语法。