编译原理FIRST集、FOLLOW集、SELECT集求法通俗解释 & LL(1)文法判定

时间:2024-05-23 12:16:01

1.为什么要引入FIRST集的概念?

  • 因为有公共左因子的问题,公共左公因子是指在文法的产生式集合中,某个非终结符的多个候选式具有相同的前缀。
  • 一般来说,公共左公因子的产生式为
    Aαβ1αβ2
  • 如果有公共左因子的问题,那么只能采取试探的方法来分析每一个候选式,分析的过程很可能产生回溯,回溯分析法是一种不确定的方法。
  • 若所有候选式都没有公共左因子就可以选择惟一匹配的候选式,不会产生(公共左公因子引起的)回溯。
  • 为了消除回溯,对任何一个非终结符和当前的待匹配符号,期望
    • 要么只有一个候选式可用
    • 要么没有候选式可用

因此引入以下FIRST集合的概念:

  • α(VTVN),有
    FIRST(α){a|αa,aVT}

    特别地,若αε,则εFIRST(α)

因此对于每一文法符号 XVTVN,构造FIRST(X)的方法为:
使用下列规则,直至每个FIRST集不再增大为止:

  • XVT,则FIRST(X)={X}(意思是如果X是终结符,则其FIRST集合为其自身);
  • XVN,那么X的产生式分以下三种情况:

    • Xε
    • εFIRST(X)
    • Xa
    • aFIRST(X)
    • XY,且YVN
    • FIRST(Y){ε}FIRST(X)

    • 特例: XY1Y2Yi1YiYk
          且 Y1,Y2,Yi1VN
           Y1,Y2,Yi1ε

      • FIRST(Yj){ε}FIRST(X)(1ji1)FIRST(Yi)FIRST(X)
    • 特别地,当Y1Y2Yi1YiYkε

      • εFIRST(X)

结论:针对无空产生式的文法G,同一非终结符的任两个产生式的右部符号串的FIRST集无交集,即可进行确定的自顶向下分析。

2.为什么要引入FOLLOW集的概念?

考虑文法G[S]:
SaA
Sd
AbAS
Aε
求得各终结符和符号串的FIRST集合如下:
FIRST(S)={a,d}
FIRST(A)={b,ε}
FIRST(aA)={a}
FIRST(d)={d}
FIRST(bAS)={b}
FIRST(ε)={ε}
  若输入串W=abd,则试图推导出abd串的推导过程为SaAabASabSabd
  从以上推导过程中可以看到,在第2步到第3步的推导中,即abASabS时,因为当前面临的输入符号为d,但是最左非终结符A的产生式右部的开始符号集都不包含d,但有ε,因此对于d的匹配自然认为只能依赖于在可能的推导过程中A的后面的符号,所以这时候选用产生式Aε向下推导。而当前A后面的符号为SS产生式右部的开始符号集包含了d,所以例子中可用Sd推导得到匹配。
语法树如下所示:
编译原理FIRST集、FOLLOW集、SELECT集求法通俗解释 & LL(1)文法判定
很显然,我们从以上叙述中可以得出:
  当某一非终结符的产生式中含有空产生式时,它的非空产生式右部的开始符号集两两不相交,并与在推导过程中紧跟该非终结符右部可能出现的终结符集也不相交,则仍可构造确定的自顶向下分析。因此,引入了一个文法符号的后跟符号集合。
引入以下FOLLOW集的概念:

  • AVN,有
    FOLLOW(A)={a|SAaaVT}
    SA,则规定#FOLLOW(A)
    这里用#作为输入串的结束符,也称为输入串括号。

因此对于每一文法符号 AVN,实际上求FOLLOW(A)
就是考察A在产生式右端的出现情况,哪些终结符号可以跟随在A后面?

使用下列规则,直至每个FOLLOW集不再增大为止:

  • 首先,设S为文法的开始符号,把{#}加入FOLLOW(S)中(这里#为句子括号)
  • BαAβ是一个产生式,则 FIRST(β){ε}FOLLOW(A)
  • 如果BαA或者BαAββε,则 FOLLOW(B)FOLLOW(A)
    • 解释: 因为在推导过程中可能出现如下的句型序列:
    • Sα1Bβ1α1αAββ1α1αAβ1

例题:
ABCc | gDB
BbCDE | ε
CDaB | ca
DdD | ε
EgAf | c

非终结符 FIRST FOLLOW
A {a, b, c, d, g} {f, #}
B {b, ε} {a, c, d, g, f, #}
C {a, c, d} {c, d, g}
D {d, ε} {a, b, c, g, f, #}
E {c, g} {a, c, d, g, f, #}

对于FIRST集合,解释其中的FIRST(A)的求解。

  • ABCc属于上述产生式的特例情况,很显然BεCε,因此
    (FIRST(B){ε})FIRST(C)FIRST(A)
  • AgDB属于上述产生式的第二种情况,因此gFIRST(A)
  • 最后得出:
    FIRST(A)=(FIRST(B){ε})FIRST(C){g}
  • FIRST(B)={b,ε}FIRST(C)={a,c,d}
  • FIRST(A)={a,b,c,d,g}

对于FOLLOW集合,有如下的计算情况:

FOLLOW(A)=(FIRST(f){ε}){#}={f,#}

FOLLOW(B)   =(FIRST(Cc){ε})FOLLOW(A)FOLLOW(C)={a,c,d}{f,#}FOLLOW(C)={a,c,d}{f,#}{c,d,g}={a,c,d,g,f,#}

FOLLOW(C)  =(FIRST(c){ε})(FIRST(DE){ε})={c}(FIRST(D){ε})FIRST(E)={c,d,g}

FOLLOW(D)  =(FIRST(B){ε})FOLLOW(A)(FIRST(E){ε})(FIRST(aB){ε})={b}{f,#}{c,g}{a}={a,b,c,g,f,#}

FOLLOW(E) =FOLLOW(B)={a,c,d,g,f,#}

3.为什么要引入SELECT集的概念?

由于从2中我们得出结论:
  当某一非终结符的产生式中含有空产生式时,它的非空产生式右部的开始符号集两两不相交,并与在推导过程中紧跟该非终结符右部可能出现的终结符集也不相交,则仍可构造确定的自顶向下分析。
  因此当文法中含有形如:

AαAβ

的产生式时,其中AVN,αβV,若αβ不能同时推导出空,假定αεβε,则当
FIRST(α)FOLLOW(A)= FIRST(β)FOLLOW(A)=

也即是FIRST(α)(FIRST(β)FOLLOW(A))=时,对于非终结符A的替换仍可唯一地确定候选。为了表示和分析方便,因此引入了SELECT集合。
SELECT集合定义如下:

  • 一个产生式的选择符号集SELECT。给定上下文无关文法的产生式Aα,AVN,αV,若αε,则SELECT(Aα)=FIRST(α)

  • 如果αε,则SELECT(Aα)=(FIRST(α){ε})FOLLOW(A)

因此一个上下文无关文法是LL(1)文法的充分必要条件是,对每个非终结符A的两个不同产生式,AαAβ,满足

SELECT(Aα)SELECT(Aβ)=

其中αβ不同时能ε

再次回到上述例题

ABCc | gDB
BbCDE | ε
CDaB | ca
DdD | ε
EgAf | c


非终结符 FIRST FOLLOW
A {a, b, c, d, g} {f, #}
B {b, ε} {a, c, d, g, f, #}
C {a, c, d} {c, d, g}
D {d, ε} {a, b, c, g, f, #}
E {c, g} {a, c, d, g, f, #}


右部产生式 FIRST
BCc {a, b, c, d}
gDB { g }
bCDE { b }
ε {ε}
DaB {a, d}
ca { c }
dD { d }
gAf { g }
c { c }

  因此根据以上所求得的FIRST集和FOLLOW集,可求得各产生式的SELECT集合如下:

         SELECT(ABCc)={a,b,c,d}SELECT(AgDB)={g}SELECT(BbCDE)={b}SELECT(Bε)={a,c,d,g,f,#}SELECT(CDaB)={a,d}SELECT(Cca)={c}SELECT(DdD)={d}SELECT(Dε)={a,b,c,g,f,#}SELECT(EgAf)={g}SELECT(Ec)={c}

  由上可知,有相同左部产生式的SELECT集合的交集为空,所以文法是LL(1)文法。