细讲如何判断文法是否是LL(1)文法

LL(1)文法判断

前言

​  在自然语言中,文法是文章的书写法规,一般用来指以文字、词语、短句、句子的编排而组成的完整语句和文章的合理性组织。

  而文法在计算机中是设计师制定的一些规则,编译器通过这些规则可以识别出程序设计语言的语义,然后通过分析编译出语言(代码)要表达的效果,它就像是编译器的大脑,没有它编译器就不能识别这些编程语言。而今天要讲的LL(1)文法是计算机文法中的一种,需要注意的是,并不是所有的语言都可以用LL(1)文法来描述,而且不存在判定某语言是否是LL(1)文法的算法。也就是说,确定的自顶向下分析只能实现一部分上下文无关语言的分析,这就是LL(1)文法所产生的语言。

​ LL(1)文法定义如下:
对 文 法 G 的 句 子 进 行 确 定 的 自 顶 向 下 语 法 分 析 的 充 分 必 要 条 件 是 , G 的 任 意 两 个 具 有 相 同 左 部 的 产 生 式 A → α ∣ β   满 足 下 列 条 件 : ( 1 ) 如 果 α 、 β 均 不 能 推 导 出 ε , 则 F I R S T ( α ) ∩ F I R S T ( β ) = ϕ ( 2 ) α 和 β 至 多 有 一 个 能 推 导 出 ε ( 3 ) 如 果 α → ε , 则 F I R S T ( α ) ∩ F O L L O W ( A ) = ϕ \begin{aligned} &对文法G的句子进行确定的自顶向下语法分析的充分必要条件是,G的任意两个具有相同左部的产生式A→α|β~满足下列条件:\\ &(1)如果α、β均不能推导出ε,则 FIRST(α) ∩ FIRST(β) = \phi\\ &(2)α 和 β 至多有一个能推导出 ε\\ &(3)如果 α \rightarrowε,则 FIRST(α) ∩ FOLLOW(A) = \phi\\ \end{aligned} GGAαβ :(1)αβεFIRST(α)FIRST(β)=ϕ(2)αβε(3)αεFIRST(α)FOLLOW(A)=ϕ
将满足上述条件的文法称为LL(1)文法。


注:希腊字母代表不同的非终结符跟终结符组成的序列,小写字母代表终结符,大写字母代表非终结符,id代表数字,#是输入结束符,ε是空, ...表示若干个终结符或者非终结符或者空

🐳LL(1)文法判断方法

LL(1)文法共有两种判断法:

  • 通过定义判断,满足前言中的定义则是LL(1)文法,具体步骤如下:

    • 消除左递归

    • 计算出FIRST集合

    • 计算出FOLLOW集合

    • 存在产生式 A→α|β,如果α、β均不能推导出ε,则需满足: FIRST(α) ∩ FIRST(β) =∅

    • 存在产生式 A→α|β,如果α 和 β 至多有一个能推导出 ε

      1)假设是 α 能推导出 ε,则要满足:FIRST(α) ∩ FOLLOW(A) = ε

      2)假设α 和 β 都不能推导出 ε,则直接满足条件

  • 通过SLECT集合求解

    • 消除左递归
    • 计算出FIRST集合
    • 计算出FOLLOW集合
    • 通过FIRST集合和FOLLOW集合计算出SELECT集合
    • 左部符号相同的SELECT集合进行交集运算,交集结果为空,则符合LL(1)文法

🐳左递归的消除

引言:

  左递归,是计算机科学里面一种递归的特殊状况。在上下文无关文法内的说法,若一个非终端符号(non-terminal)r有任何直接的文法规则或者透过多个文法规则,推导出的句型(sentential form)其中最左边的符号又会出现r,则我们说这个非终端符号r是左递归的。

  • 左递归的定义:一个文法是左递归的,若我们可以找出其中存在某非终端符号A,最终会推导出来的句型(sentential form)里面包含以自己为最左符号(left-symbol)的句型。

  • 左递归的分类

    • 直接左递归
      A → A α ∣ β A\rightarrow{A}\alpha|β AAαβ

    • 间接左递归
      A → B α B → . . . → A β \begin{aligned} &A\rightarrow{B\alpha}\\ &B\rightarrow{...}\rightarrow{Aβ} \end{aligned} ABαB...Aβ

  • 递归消除方法

    • 对于直接左递归
      A → β A ‘ A ‘ → α A ‘ ∣ ε \begin{aligned} &A\rightarrow{\beta}A^`\\ &A^`\rightarrow{\alpha}A^`|ε \end{aligned} AβAAαAε

    • 对于间接左递归

      1)把给定的文法G中所有非终结符按任意顺序排列,并编号

      2)若产生式右部最左的符号是非终结符,且这个非终结符序号大于左部非终结符,则暂不处理

      3)若序号小于左部的非终结符,则用序号小的产生式的右部来替换左部

      4)若消除过程中出现了直接左递归,就按照直接左递归的方法,来消除

      5)删除其中不可达的非终结符1

在这里插入图片描述
img

Step1:把文法G的所有非终结符按任意顺序排列,并编号
A_1、B_2、C_3


Step2:按照顺序遍历G中的非终结符,根据规则2)、3)、4)进行判断
对于A:
A的下标是1,右部是B,而B的下标是2大于1,故暂不处理

对于B:
同理,B也暂不处理

对于C:
C的下标大于右部A的下标,故进行替换
替换后的结果为:C → Bαγ | αγ | γ

此时C的下标仍然大于右部非终结符,故进行替换
替换后的结果为:C → Cαβγ | αβγ | αγ | γ

此时出现直接递归,则按照直接递归的方法来消除递归
消除后的结果为:
C → αβγC` | αγC` | γC`
C` → αβγC` | ε

Step3:删除其中不可达的非终结符,这里是A、B
所以文法G经过消除左递归后的最终结果为:
C → αβγC` | αγC` | γC`
C` → αβγC` | ε

备注:第一步对非终结符按任意方式排序,最后结果的产生式有可能不同,但它们是等价的


🐳FIRST集合求解

First 集合的定义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2MjyJxyU-1651328528765)(C:/Users/ghp/AppData/Roaming/Typora/typora-user-images/image-20220430145317988.png)]

这是百度上的介绍,有点晦涩难懂,总结来讲就是:一个文法符号串所可能推导出的符号串的第一个终结符的集合

FIRST集合求解规则:

  • 单个终结符的FIRST集合是它本身

  • 单个非终结符的FIRST集合

    • A → a…   此时 a∈FIRST(A)
    • A → B…   ε ∉ FIRST(B),此时 FIRST(B)⊆FIRST(A)
      A → Bα…  ε ∈ FIRST(B),此时FIRST(A) = FIRST(B)UFIRST(α)
      后续是递推关系……
    • A → B…|α…   此时 FIRST(A) = FIRST(B)UFIRST(α)
  • 多个符号的的FIRST集合

    • FIRST(aAB…) = {a}

    • FIRST(AB…) = FIRST(A)(假设 ε ∉ FIRST(A));

      当 ε∈FIRST(A), ε ∉FIRST(B) 时,FIRST(AB…) = FIRST(A)UFIRST(B…);

      后续是递推关系……

First集合中的符号一定是终结符终结符也包括空串ε

🌰举个例子,求下列文法G的FIRST集合:

  • Step1:通过第一个产生式可以知道: FIRST(T)⊆FIRST(E),此时不知道FIRST(T)暂且放在这不管

  • Step2:通过第二个产生式可以知道:{+,ε}⊆FIRST(E`)

  • Step3:通过第三个产生式可以知道:FIRST(F)⊆FIRST(T),此时不知道FIRST(F)暂且放在这不管

  • Step4:通过第四个产生式可以知道:{*,ε}⊆FIRST(T`)

  • Step5:通过第五个产生式可以知道:{id,(}⊆FIRST(F)

    此时已知FIRST(F),往回代入Step3,从而求得FIRST(T)={id,(};

    又将求得的FIRST(T)回代入Step1,从而求得FIRST(E)={id,(}

综上可知,上面各非终结符的FIRST集合为:

非终结符FIRST
E(,id
E`+,ε
T(,id
T`*, ε
F(,id

🐳FOLLOW集合求解

引言:

​ 这是书上的定义:

image-20220429194810700

书上说通过(2)和(3)的重复使用可以求出A的FOLLOW集合,刚开始看有点不太懂,后来通过做题实践,总结了求FOLLOW集合的一般性步骤,现在就让我们来看一下怎么如何简便求解FOLLOW集合吧😃


重点:
假如我们要求的是U的FOLLOW集合,其中U存在几种形式
1.    U → . . .                    此 时 # ∈ U                                                                                                                                                       2.    A → . . . U a             此 时 a ∈ F O L L O W ( U ) , 与 A 无 关 3.    A → . . . U P . . .        此 时 { F I R S T ( P ) − { ε } } ⊆ F O L L O W ( U ) , 与 A 无 关 4.    A → . . . U P            若 ε ∈ F I R S T ( P ) , 此 时 F O L L O W ( A ) ∪ { F I R S T ( P ) − { ε } } ⊆ F O L L O W ( U ) 5.    A → . . . U                此 时 F O L L O W ( A ) ⊆ F O L L O W ( U ) \begin{aligned} &1.~~U\rightarrow{...}~~~~~~~~~~~~~~~~~~此时\#\in{U}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\\ &2.~~A\rightarrow{...Ua}~~~~~~~~~~~此时a\in{FOLLOW(U)},与A无关\\ &3.~~A\rightarrow{...UP...}~~~~~~此时\{FIRST(P)-\{\varepsilon\}\}\subseteq{FOLLOW(U)},与A无关\\ &4.~~A\rightarrow{...UP}~~~~~~~~~~若\varepsilon\in{FIRST(P)},此时FOLLOW(A)\cup{\{FIRST(P)-\{\varepsilon\}\}}\subseteq{FOLLOW(U)}\\ &5.~~A\rightarrow...U~~~~~~~~~~~~~~此时FOLLOW(A)\subseteq{FOLLOW(U)} \end{aligned} 1.  U...                  #U                                                                                                                                                     2.  A...Ua           aFOLLOW(U),A3.  A...UP...      {FIRST(P){ε}}FOLLOW(U),A4.  A...UP          εFIRST(P)FOLLOW(A){FIRST(P){ε}}FOLLOW(U)5.  A...U              FOLLOW(A)FOLLOW(U)
拓展:
*当 A → . . . U P D . . . 时 , 且 ε ∈ P 且 ε ∉ D 时 , F O L L O W ( U ) = { F I R S T ( P ) − ε } ∪ F O L L O W ( P ) , 其 中 F O L L O W ( P ) 可 以 根 据 规 则 3. 来 求 解 A\rightarrow{...UPD...}时,且ε\in{P}且ε∉ {D}时,FOLLOW(U)=\{{FIRST(P)−{ε}}\}\cup{FOLLOW(P)},其中FOLLOW(P)可以根据规则3.来求解 A...UPD...εPε/D,FOLLOW(U)={FIRST(P)ε}FOLLOW(P)FOLLOW(P)3.
这是存在一种递推关系的,后面可以无限递推下去

在此,详细说明以下形式3.、形式4.和形式5.的关系
形式4.是形式3.的特例,当形式3.中…为ε,且ε∈FIRST(P)时,形式4.等于形式3.
形式5.是形式4.的特例,当形式4.中的P=ε时,就是形式5.

FOLLOW(U)通过上面1、2、3、4、5条规则进行求解,同时应当注意:Follow集合中的符号一定是终结符,但是不能包括空串ε

通过做题我们可以知道FOLLOW集合就是文法符号后面可能跟随的终结符的集合(不包括空 串ε)

🌰举个例子,求下列文法G的FOLLOW集合:

image-20220430160221388

上面我们求得了文法G的FIRST集合,如下:

非终结符FIRST
E(,id
E`+,ε
T(,id
T`*, ε
F(,id

现在让我们继续来求FOLLOW集合:

  • Step1:由形式1.可以知,所有的非终结符的FOLLOW集合都具有{#}

  • Step2:求FOLLOW(E),第五个产生式满足形式2.,所以)∈FOLLOW(E),此时FOLLOW(E)={#,)}

  • Step3:求FOLLOW(E`),第一个产生式满足形式5.,所以FOLLOW(E)⊆FOLLOW(E’),此时FOLLOW(E’)={#,)}

  • Step4:求FOLLOW(T),第一个产生式满足形式4.,所以
    FOLLOW(E)⊆FOLLOW(T);第二个产生式满足形式3.,所以

    {FIRST(E`)-{ε}}⊆FOLLOW(T),此时FOLLOW(T)={#,),+}

  • Step5:同理可求得FOLLOW(T`)={#,),+}

  • Step6:同理,FOLLOW(F)={#,),+,*}

综上可知,上面各非终结符的FOLLOW集合为:

非终结符FIRSTFOLLOW
E(,id#,)
E`+,ε#,)
T(,id#,),+
T`*, ε#,),+
F(,id#,),+,*

🐳SELECT集合求解

SELECT集合就是产生式左部的可能的推导结果的起始符号
A → α   同 时   ε ∉ F I R S T ( α ) 此 时 S E L E C T ( A → α ) = { F I R S T ( α ) − { ε } } A → α   同 时   ε ∈ F I R S T ( α ) 此 时 S E L E C T ( A → α ) = { F I R S T ( α ) − { ε } } ∪ F O L L O W ( A ) \begin{aligned} &A\rightarrow{\alpha}~同时~\varepsilon∉FIRST(\alpha)\qquad此时SELECT(A\rightarrow{\alpha}) = \{FIRST(\alpha)-\{\varepsilon\}\}\\ &A\rightarrow{\alpha}~同时~\varepsilon\in FIRST(\alpha)\qquad此时SELECT(A\rightarrow\alpha)=\{FIRST(\alpha)-\{\varepsilon\}\}\cup FOLLOW(A) \end{aligned} Aα  ε/FIRST(α)SELECT(Aα)={FIRST(α){ε}}Aα  εFIRST(α)SELECT(Aα)={FIRST(α){ε}}FOLLOW(A)
注:SELECT集合中不包括空串ε,但有可能会包含#

🌰举个例子,求下列文法G的SELECT集合:

image-20220430160221388

上面我们求得了文法G的FIRST集合和FOLLow集合,如下:

非终结符FIRSTFOLLOW
E(,id#,)
E`+,ε#,)
T(,id#,),+
T`*, ε#,),+
F(,id#,),+,*

现在继续来求SELECT集合:

  • Step1:对于第一个产生式,ε∉FIRST(TE‘),所以SELECT(E → TE’) = { FIRST(TE’ ) - {ε} }={ ( , id }

  • Step2:对于第二个产生式,有两种情况:

    当E’ → +TE’,ε∉FIRST(+TE`),所以SELECT(E’ → +TE’) = {FIRST(+TE’) - {ε}}= {+}

    当E’ → ε,显然 ε∈FIRST(ε),所以SELECT(E’ → ε) = FOLLOW(E’) = {#,)}

  • Step3:同理可求得SELECT(T → FT’) = {(,id}

  • Step4:SELECT(T’ → *FT’) = {*}
        ​ SELECT(T’ → ε) = {#,),+}

  • Step5:SELECT(F → id) = {id}
    ​     SELECT(F → (E)) = {(}

产生式SELECT集合
E → TE’( , id
E’ → +TE’+
E’ → ε#,)
T → FT’(,id
T’ → *FT’*
T’ → ε#,),+
F → idid
F → (E)

LL(1)文法预测分析表的构造可以参观这篇文章的大题编译原理期末复习重点


🐳实战例题

例 1 : 例1: 1:
判 断 下 列 文 法 G 是 否 是 L L ( 1 ) 文 法 E → E + T ∣ T T → T ∗ F ∣ F F → i d ∣ ( E ) \begin{aligned} &判断下列文法G是否是LL(1)文法\\ &E\rightarrow{E+T}|T\\ &T\rightarrow{T}*F|F\\ &F\rightarrow{id}|(E) \end{aligned} GLL(1)EE+TTTTFFFid(E)

  • Step1:消除左递归
    E → T E ‘ E ‘ → + T E ‘ ∣ ε T → F T ‘ T ‘ → ∗ F T ‘ ∣ ε F → i d ∣ ( E ) \begin{aligned} &E\rightarrow{TE^{`}}\\ &E^{`}\rightarrow{+TE^{`}}|\varepsilon\\ &T\rightarrow{FT^{`}}\\ & T^{`}\rightarrow*FT^{`}|\varepsilon\\ &F\rightarrow{id}|(E) \end{aligned} ETEE+TEεTFTTFTεFid(E)

  • Step2:求FIRST集合

    非终结符FIRSTFOLLOW
    E(,id
    E’+,ε
    T(,id
    T‘*, ε
    F(,id

    需要注意的是( ,) , ε 和 id 都是终结符

  • Step3:求FOLLOW集合

    非终结符FIRSTFOLLOW
    E(,id#,)
    E‘+,ε#,)
    T(,id#,),+
    T’*, ε#,),+
    F(,id#,),+,*
  • Step4:求SELECT集合

    产生式SELECT集合
    E → TE’( , id
    E’ → +TE’+
    E’ → ε#,)
    T → FT’(,id
    T’ → *FT’*
    T’ → ε#,),+
    F → idid
    F → (E)
  • Step5:对左部相同的产生式的SELECT集合进行交集运算

    SELECT(E’ → +TE’) ∩ SELECT(E’ → ε) = ε

    SELECT(T’ → *FT’) ∩ SELECT(T’ → ε) = ε

    SELECT(F → id) ∩ SELECT(F → (E)) = ε

    从上面可以知道,所有左部相同的SELECT集合的交集运算结果都是ε,所以文法G是LL(1)文法

例 2 : 求 以 下 文 法 G [ S ] 是 否 是 L L ( 1 ) 文 法 , 并 且 给 出 判 断 过 程 , 的 的 F I R S T 集 合 和 F O L L O W 集 合 :                           S → M H ∣ a H → L S o ∣ ε K → d M L ∣ ε L → e H f M → K ∣ b L M \begin{aligned} 例2:\\ &求以下文法G[S]是否是LL(1)文法,并且给出判断过程,的的FIRST集合和FOLLOW集合:~~~~~~~~~~~~~~~~~~~~~~~~~\\ &S\rightarrow{MH}|a\\ &H\rightarrow{LSo}|\varepsilon\\ &K\rightarrow{dML}|\varepsilon\\ &L\rightarrow{eHf}\\ &M\rightarrow{K}|bLM \end{aligned} 2:G[S]LL(1)FIRSTFOLLOW:                         SMHaHLSoεKdMLεLeHfMKbLM
解 : 解:

  • Step1:消除左递归。显然文法G[s]不存在左递归,故无需消除左递归

  • Step2:求FIRST集合。

    ①对于产生式1, S → M H = > F I R S T ( M ) ⊆ F I R S T ( S ) , F I R S T ( M ) S\rightarrow{MH}=>FIRST(M)⊆FIRST(S),FIRST(M) SMH=>FIRST(M)FIRST(S)FIRST(M)暂且不知道,所以先不管, S → a = > a ∈ F I R S T ( S ) S\rightarrow{a}=>a\in{FIRST(S)} Sa=>aFIRST(S)
    ②对于产生式2, H → L S o = > F I R S T ( L ) ⊆ F I R S T ( H ) , F I R S T ( L ) 暂 且 不 知 道 , 所 以 先 不 管 H\rightarrow{LSo}=>FIRST(L)\subseteq{FIRST(H)},FIRST(L)暂且不知道,所以先不管 HLSo=>FIRST(L)FIRST(H)FIRST(L) H → ε = > ε ∈ F I R S T ( H ) H\rightarrow{\varepsilon}=>\varepsilon\in{FIRST(H)} Hε=>εFIRST(H)
    ③对于产生式3, K → d M L = > d ∈ F I R S T ( K ) , K\rightarrow{dML}=>d\in{FIRST(K)}, KdML=>dFIRST(K), K → ε = > ε ∈ F I R S T ( K ) K\rightarrow\varepsilon=>\varepsilon\in{FIRST(K)} Kε=>εFIRST(K) ,所以 F I R S T ( K ) = { d , ε } ; FIRST(K)=\{d,\varepsilon\}; FIRST(K)={d,ε}
    ④对于产生式4, L → e H f = > e ∈ F I R S T ( L ) L\rightarrow{eHf}=>e\in{FIRST(L)} LeHf=>eFIRST(L),所以 F I R S T ( L ) = { e } FIRST(L)=\{e\} FIRST(L)={e},此时已知 F I R S T ( L ) FIRST(L) FIRST(L),将其回代到②中继而求得 F I R S T ( H ) = { e , ε } FIRST(H)=\{e,\varepsilon\} FIRST(H)={e,ε}
    ⑤对于产生式5, M → b L M = > b ∈ F I R S T ( M ) , M\rightarrow{bLM}=>b\in{FIRST(M)}, MbLM=>bFIRST(M) M → K = > F I R S T ( K ) ⊆ F I R S T ( M ) M\rightarrow{K}=>FIRST(K)\subseteq{FIRST(M)} MK=>FIRST(K)FIRST(M),从③可知 F I R S T ( K ) = { d , ε } FIRST(K)=\{d,\varepsilon\} FIRST(K)={d,ε},所以 F I R S T ( M ) = { b , d , ε } FIRST(M)=\{b,d,\varepsilon\} FIRST(M)={b,d,ε},此时已知 F I R S T ( M ) FIRST(M) FIRST(M),将其回代到①中继而求得 F I R S T ( S ) = { a , b , d , ε } FIRST(S)=\{a,b,d,\varepsilon\} FIRST(S)={a,b,d,ε}需要注意此时ε∈FIRST(M),所以FIRST(H)⊆FIRST(S),故 F I R S T ( S ) = { a , b , d , e , ε } FIRST(S)=\{a,b,d,e,ε\} FIRST(S)={a,b,d,e,ε}

    所以文法G[s]的FIRST集合如下表所示:

    非终结符FIRST集合
    S{a,b,d,e,ε}
    H{e,ε}
    K{d,ε}
    L{e}
    M{b,d,ε}
  • Step3:求FOLLOW集合。

    ①首先我们可以发现每个非终结符都出现在产生式的右部,故每一个非终结符的FOLLOW集中都有#
    ②求 F O L L O W ( S ) FOLLOW(S) FOLLOW(S),从产生式2: H → L S o ∣ ε H\rightarrow{LSo}|\varepsilon HLSoε 知道o∈ F O L L O W ( S ) FOLLOW(S) FOLLOW(S),即 F O L L O W ( S ) = { # , o } FOLLOW(S)=\{\#,o\} FOLLOW(S)={#,o}
    ③求 F O L L O W ( H ) FOLLOW(H) FOLLOW(H),从产生式4可以知道 f ∈ F O L L O W ( H ) f∈FOLLOW(H) fFOLLOW(H),从产生式1: S → M H ∣ a S\rightarrow{MH}|a SMHa 根据FOLLOW求解规则5.(不记得的可以回看)可以知道: F O L L O W ( S ) ⊆ F O L L O W ( H ) FOLLOW(S)⊆FOLLOW(H) FOLLOW(S)FOLLOW(H),所以 F O L L O W ( H ) = { # , f , o } FOLLOW(H)=\{\#,f,o\} FOLLOW(H)={#,f,o}
    ④求 F O L L O W ( K ) FOLLOW(K) FOLLOW(K),从从产生式5: M → K ∣ b L M M\rightarrow{K}|bLM MKbLM,通过FOLLOW求解规则5.可以知道: F O L L O W ( M ) ⊆ F O L L O W ( K ) FOLLOW(M)⊆FOLLOW(K) FOLLOW(M)FOLLOW(K),现在FOLLOW(M)暂且不知道,先不管
    ⑤求 F O L L O W ( L ) FOLLOW(L) FOLLOW(L),从产生式2根据规则3.可以知道: { F I R S T ( S ) − ε } ⊆ F O L L O W ( H ) \{FIRST(S)-ε\}⊆FOLLOW(H) {FIRST(S)ε}FOLLOW(H),同时ε∈ F O L L O W ( S ) FOLLOW(S) FOLLOW(S),满足求解规则2.,故 o ∈ F O L L O W ( L ) o∈FOLLOW(L) oFOLLOW(L),此时 F O L L O W ( L ) = { # , a , b , d , e , o } FOLLOW(L)=\{\#,a,b,d,e,o\} FOLLOW(L)={#,a,b,d,e,o}已经是最大的集合了,对于产生式5: M → K ∣ b L M M\rightarrow{K}|bLM MKbLM求不求都无所谓了
    ⑥求 F O L L O W ( M ) FOLLOW(M) FOLLOW(M),从产生式1可以知道{FIRST(H)-ε}⊆FOLLOW(M),同时ε∈FIRST(H),所以满足规则4.,即:FOLLOW(S)⊆FOLLOW(M),所以FOLLOW(M)={#,e,o},此时已经知道了FOLLOW(M),回代到④中从而求得FOLLOW(K)={#,e,o}

    所以非终结符的FOLLOW集合表为:

    非终结符FIRST集合FOLLOW集合
    S{a,b,d,e,ε}{#,o}
    H{e,ε}{#,f,o}
    K{d,ε}{#,e,o}
    L{e}{#,a,b,d,e,o}
    M{b,d,ε}{#,e,o}
  • Step4: 求SELECT集合。

    ①求 S E L E C T ( S → M H ) SELECT(S→MH) SELECT(SMH) ε ∈ F I R S T ( M H ) ε∈FIRST(MH) εFIRST(MH),所以 S E L E C T ( S → M H ) = { F I R S T ( M H ) − ε } ∪ F O L L O W ( S ) = { # , b , e , d , o } SELECT(S→MH)=\{FIRST(MH)-ε\}∪FOLLOW(S)=\{\#,b,e,d,o\} SELECT(SMH)={FIRST(MH)ε}FOLLOW(S)={#,b,e,do},其中因为ε∈FIRST(M),所以FIRST(MH)=FIRST(M)UFIRST(H)={b,d,e,ε}
    ②求 S E L E C T ( S → a ) SELECT(S→a) SELECT(Sa) ε ∉ F I R S T ( a ) ε∉FIRST(a) ε/FIRST(a),所以 S E L E C T ( S → a ) = { F I R S T ( a ) − ε } = { a } SELECT(S→a)=\{FIRST(a)-ε\}=\{a\} SELECT(Sa)={FIRST(a)ε}={a}
    ③求 S E L E C T ( H → L S o ) SELECT(H→LSo) SELECT(HLSo) ε ∉ F I R S T ( L S o ) ε∉FIRST(LSo) ε/FIRST(LSo),所以 S E L E C T ( H → L S o ) = { e } SELECT(H→LSo)=\{e\} SELECT(HLSo)={e}
    ④求 S E L E C T ( H → ε ) SELECT(H→ε) SELECT(Hε) ε ∈ F I R S T ( ε ) ε∈FIRST(ε) εFIRST(ε),所以 S E L E C T ( H → ε ) = F O L L O W ( H ) = { # , f , o } SELECT(H→ε)={FOLLOW(H)=\{\#,f,o\}} SELECT(Hε)=FOLLOW(H)={#,f,o}
    ⑤求 S E L E C T ( K → d M L ) SELECT(K\rightarrow{dML}) SELECT(KdML) ε ∉ F I R S T ( d M L ) ε∉FIRST(dML) ε/FIRST(dML),所以 S E L E C T ( K → d M L ) = { d } SELECT(K\rightarrow{dML})=\{d\} SELECT(KdML)={d}
    ⑥同理可求得: S E L E C T ( K → ε ) = { # , e , o } SELECT(K→ε)=\{\#,e,o\} SELECT(Kε)={#,e,o}
    S E L E C T ( L → e H f ) = { e } SELECT(L→eHf)=\{e\} SELECT(LeHf)={e}
    S E L E C T ( M → K ) = { # , d , e , o } SELECT(M→K)=\{\#,d,e,o\} SELECT(MK)={#,d,e,o}
    S E L E C T ( M → b L M ) = { b } SELECT(M→bLM)=\{b\} SELECT(MbLM)={b}

    所以非终结符的SELECT集合表为:

    产生式SELECT集合
    S→MH{#,b,e,d,o}
    S→a{a}
    H→LSo{e}
    H→ε{#,f,o}
    K→dML{d}
    K→ε{#,e,o}
    L→eHf{e}
    M→K{#,d,e,o}
    M→bLM{b}
  • Step5:求左部相同的产生式的SELECT集合的交集。
    从上表显然可知,左部相同的产生式的SELECT集合的交集都是空,故文法G[s]属于LL(1)文法。

……………………

参考文章:

在此感谢所有CSDN乐于分享的博主


  1. 不可达的非终结符是指经过若干次推导都不能推出非终结符的开始符号 ↩︎

  • 92
    点赞
  • 561
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 28
    评论
本程序的所用的存储结构都是string类型的,最主要的存储文法的数据结构为自定义结构,里面包括一个产生式的左部,右部以及select集合,至于非终结符的first和follow集合,则是定义了一个string类型的数组进行存储。 本程序的求first,follow,select集合的算法即为书上所介绍的方法,即求first的集合时,只看本产生式,求follow集合时,要进行递归查找一个非终结符的所有后跟字符,求select其实就是对first与follow集合的运算,最终根据所有的select集合,便可以判断文法是否为LL(1)文法。 对于不是LL(1)文法的产生式,本程序在判断后进行转换,先进行消除左递归,然后提取左公因子,在这两步的每一步结束之后,都要对产生式进行整合,去掉空存储,去掉无法到达的产生式,将select全部置空。 每进行一次非LL(1)到LL(1)的转换之后,都要对其文法性质进行判断,如果是LL(1),则跳出,不是则继续,但是当循环一定次数之后仍不是,程序判定其无法转换,也要跳出。 其中还有对第一个非终结字符的右部替换与否进行选择,原因是,有些通过替换就可以很方便的进行转换,这个要通过人为进行输入。 提取公因子中也有上一段所说的类似的判断机制,目的是为了防止文法的左公因子无法提取完的情况出现。 最终有三种结果,一种是是LL(1)文法,一种是不是LL(1),但是经过转换变成了LL(1),还有一种是经过转换也无法变成LL(1)。 输入文本格式样例: A A->ad A->Bc B->aA B->bB
LL(1)文法是指可以用LL(1)分析表进行分析的文法LL(1)文法的要求是:对于文法的每个产生式,其右部的各个候选式的FIRST集和FOLLOW集互不相交,即任意两个候选式的FIRST集和FOLLOW集的交集为空集。 下面是判断文法是否为LL(1)文法的Java实现: ```java import java.util.*; public class LL1Grammar { private Map<String, Set<String>> firstSet; //存储非终结符的FIRST集 private Map<String, Set<String>> followSet; //存储非终结符的FOLLOW集 private Map<String, List<String>> productionMap; //存储产生式 public LL1Grammar(Map<String, List<String>> productionMap) { this.productionMap = productionMap; firstSet = new HashMap<>(); followSet = new HashMap<>(); calculateFirstSet(); calculateFollowSet(); } //计算每个非终结符的FIRST集 private void calculateFirstSet() { for (String nonTerminal : productionMap.keySet()) { Set<String> first = new HashSet<>(); for (String production : productionMap.get(nonTerminal)) { char firstChar = production.charAt(0); if (Character.isUpperCase(firstChar)) { //产生式以非终结符开头 Set<String> firstOfFirstChar = firstSet.get(String.valueOf(firstChar)); first.addAll(firstOfFirstChar); } else { //产生式以终结符开头 first.add(String.valueOf(firstChar)); } } firstSet.put(nonTerminal, first); } } //计算每个非终结符的FOLLOW集 private void calculateFollowSet() { for (String nonTerminal : productionMap.keySet()) { followSet.put(nonTerminal, new HashSet<>()); } followSet.get("S").add("$"); //将结束符号$加入开始符号S的FOLLOW集 //重复计算FOLLOW集,直到不再发生变化 boolean changed = true; while (changed) { changed = false; for (Map.Entry<String, List<String>> entry : productionMap.entrySet()) { String nonTerminal = entry.getKey(); for (String production : entry.getValue()) { for (int i = 0; i < production.length(); i++) { char currentChar = production.charAt(i); if (Character.isUpperCase(currentChar)) { //处理非终结符 String currentNonTerminal = String.valueOf(currentChar); if (i == production.length() - 1) { //非终结符在产生式末尾 Set<String> follow = followSet.get(nonTerminal); if (follow.addAll(followSet.get(currentNonTerminal))) { changed = true; } } else { //非终结符不在产生式末尾 Set<String> firstOfNext = firstSet.get(String.valueOf(production.charAt(i + 1))); if (firstOfNext.contains("ε")) { //后继符号串的FIRST集包含ε Set<String> follow = followSet.get(nonTerminal); if (follow.addAll(followSet.get(currentNonTerminal))) { changed = true; } } Set<String> follow = followSet.get(String.valueOf(production.charAt(i + 1))); if (follow.addAll(followSet.get(currentNonTerminal))) { changed = true; } } } } } } } } //判断文法是否为LL(1)文法 public boolean isLL1Grammar() { boolean isLL1 = true; for (String nonTerminal : productionMap.keySet()) { List<String> productions = productionMap.get(nonTerminal); for (int i = 0; i < productions.size() - 1; i++) { String currentProduction = productions.get(i); Set<String> firstOfCurrent = new HashSet<>(); for (char ch : currentProduction.toCharArray()) { if (Character.isUpperCase(ch)) { firstOfCurrent.addAll(firstSet.get(String.valueOf(ch))); if (!firstSet.get(String.valueOf(ch)).contains("ε")) { break; } } else { firstOfCurrent.add(String.valueOf(ch)); break; } } for (int j = i + 1; j < productions.size(); j++) { String nextProduction = productions.get(j); Set<String> firstOfNext = new HashSet<>(); for (char ch : nextProduction.toCharArray()) { if (Character.isUpperCase(ch)) { firstOfNext.addAll(firstSet.get(String.valueOf(ch))); if (!firstSet.get(String.valueOf(ch)).contains("ε")) { break; } } else { firstOfNext.add(String.valueOf(ch)); break; } } if (!Collections.disjoint(firstOfCurrent, firstOfNext)) { isLL1 = false; System.out.println("产生式 " + nonTerminal + " -> " + currentProduction + " 和 " + nonTerminal + " -> " + nextProduction + " 存在 FIRST 集的交集"); } } } Set<String> follow = followSet.get(nonTerminal); for (String production : productions) { Set<String> firstOfCurrent = new HashSet<>(); for (char ch : production.toCharArray()) { if (Character.isUpperCase(ch)) { firstOfCurrent.addAll(firstSet.get(String.valueOf(ch))); if (!firstSet.get(String.valueOf(ch)).contains("ε")) { break; } } else { firstOfCurrent.add(String.valueOf(ch)); break; } } if (!Collections.disjoint(firstOfCurrent, follow)) { isLL1 = false; System.out.println("产生式 " + nonTerminal + " -> " + production + " 存在 FIRST 集和 FOLLOW 集的交集"); } } } return isLL1; } } ``` 使用示例: ```java public static void main(String[] args) { Map<String, List<String>> productionMap = new HashMap<>(); productionMap.put("S", Arrays.asList("aBA", "bBB", "c")); productionMap.put("A", Arrays.asList("d", "ε")); productionMap.put("B", Arrays.asList("e", "f")); LL1Grammar ll1Grammar = new LL1Grammar(productionMap); boolean isLL1 = ll1Grammar.isLL1Grammar(); if (isLL1) { System.out.println("该文法LL(1)文法"); } else { System.out.println("该文法不是LL(1)文法"); } } ``` 输出结果: ``` 产生式 S -> aBA 和 S -> bBB 存在 FIRST 集的交集 该文法不是LL(1)文法 ``` 以上代码实现了判断文法是否为LL(1)文法的功能,可以根据需求改变产生式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知识汲取者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值