如何手动计算FIRST集

时间:2013-10-28 11:44:10

标签: parsing compiler-construction grammar

我不明白我的导师提供的一个例子。

实施例

S ::= aBA | BB | Bc
A ::= Ad | d
B ::= ε

我们有

FIRST(B) = FIRST(ε)
         = {ε}

FIRST(A) = FIRST(Ad) ∪ FIRST(d)
         = FIRST(A) ∪ {d}
         = {d}

FIRST(S) = FIRST(aBA) ∪ FIRST(BB) ∪ FIRST(Bc)
         = FIRST(a) ∪ (FIRST(B)\{ε}) ∪ FIRST(B) ∪ (FIRST(B)\{ε) ∪ FIRST(c)
         = {a, ε, c}

为什么FIRST(S)计算中存在FIRST(B)?不应该是

(FIRST(B)\{ε)?

为什么FIRST(S)计算中缺少A?

1 个答案:

答案 0 :(得分:8)

This page给出了导出FIRST(和FOLLOW)集的机械规则。我将尝试解释这些规则背后的逻辑以及它们如何应用于您的示例。

FIRST设置

FIRST(u)是可以在u的完全推导中首先出现的终端集合,其中u是终端和非终端的序列。换句话说,在计算FIRST(u)集合时,我们只查找可能是可以从u派生的字符串的第一个终端的终端。

FIRST(ABA)

根据定义,我们可以看到FIRST(aBA)缩减为FIRST(a),然后缩减为a。这是因为无论AB制作是什么,终端a将始终首先出现在aBA派生的任何内容中,因为a是终端,并且不能从该序列的前面删除。

FIRST(BC)

我现在暂时跳过FIRST(BB)并转到FIRST(Bc)。这里的情况有所不同,因为B是非终端的。首先,我们说FIRST(B)中的任何内容都在FIRST(S)中。不幸的是,FIRST(B)包含导致问题的ε,因为我们可能有方案

   FIRST(Bc)
-> FIRST(εc)
=  FIRST(c)
=  c

其中箭头是可能的派生/减少。因此,一般而言,我们说FIRST(Xu) ε位于FIRST(X)(FIRST(X)\{ε}) ∪ FIRST(u)等于FIRST(BB)。这解释了计算中的最后两个术语。

FIRST(BB)

使用上述规则,我们现在可以将(FIRST(B)\{ε}) ∪ FIRST(B)推导为FIRST(BBB)。同样,如果我们计算 FIRST(BBB) = (FIRST(B)\{ε}) ∪ FIRST(BB) = (FIRST(B)\{ε}) ∪ (FIRST(B)\{ε}) ∪ FIRST(B) ,我们会将其缩小为

   S
-> BB
-> εε
-> ε

值得注意的是,在计算FIRST集时,符号序列中的最后一个符号永远不会从中删除空字符串,因为此时空字符串是合法的可能性。这可以从您的示例中的可能派生中看出:

FIRST(B)

希望您可以从上述所有内容中看到为什么FIRST(A)出现在您的计算中,而{{1}}却没有。