510 likes | 710 Views
确定的自顶向下分析思想 LL(1) 文法的判别 某些非 LL(1) 文法到 LL(1) 文法的等 价变换 不确定的自顶向下分析思想 确定的自顶向下分析方法. 第5章 自顶向下语法分析方法. 返回目录. 文法 G1[S]: S→pA S→qB A→cAd A→a B→dB B→b. 确定的自顶向下分析思想. W=pccadd 自顶向下的推导过程: S pA pcAd pccAdd pccadd. 语法树:. S. S. S. S. p. A. p. A. p. A. p. A. c. A. d. c.
E N D
确定的自顶向下分析思想 LL(1)文法的判别 某些非LL(1)文法到LL(1)文法的等 价变换 不确定的自顶向下分析思想 确定的自顶向下分析方法 第5章 自顶向下语法分析方法 返回目录
文法G1[S]:S→pAS→qBA→cAdA→aB→dBB→b 确定的自顶向下分析思想 W=pccadd自顶向下的推导过程: S pA pcAd pccAdd pccadd 语法树: S S S S p A p A p A p A c A d c A d c A d c A d c A d a
这个文法的特点: 每个产生式的右部都由终结符号开始。 如果两个产生式有相同的左部,那么它们的右部由不同的终结符开始。 • 文法G1[S]:S→pAS→qBA→cAdA→aB→dBB→b
文法G2[S]:S→ApS→BqA→aA→cAB→bB→dB W=ccap自顶向下的推导过程: S Ap cAp ccAp ccap 语法树: S S S S A p A p A p A p c A c A c A c A c A a
这个文法的特点: 每个产生式的右部不全是由终结符号开始。 如果两个产生式有相同的左部,那么它们的右部由不同的终结符或非终结符开始。 文法中无空产生式。 • 文法G1[S]:S→ApS→BqA→aA→cAB→bB→dB
定义: 设 G = (VT ,VN , S , P) 是上下文无关文法,FIRST(α) = {a|α aβ,a∈ VT,α ∈ V+, β ∈ V*,}若α ε,则规定ε∈FIRST(α) * * 调用返回
FIRST(Ap)={a,c} FIRST(Bq)={b,d} • 文法G2[S]:S→ApS→BqA→aA→cAB→bB→dB
文法G3[S]:S→aAS→dA→bASA→ε W=abd试图推导的过程: S aA abAS abS abd
定义:设 G = (VT ,VN , S , P) 是上下文无关文法,A∈VN , S是开始符号。 FOLLOW(A) = {a|SA且a∈FRIST(), ∈VT*,∈V+ }若S A,且ε,则规定 #∈FOLLOW(A) 即:FOLLOW(A)={a|S …Aa… ,a∈VT}若S …A,则规定 #∈FOLLOW(A) #作为输入串的结束符,或称为句子括号,如:#输入串# * * * * * 调用返回
对A→α,A→β其中A∈VN , α, β ∈VN*,当α和β不同时推导出空时(设α不推导出空,β推导出空),则当FIRST(α)∩(FIRST(β)∪FOLLOW(A))=Φ时,对于非终结符A的替换仍可唯一地确定候选。
定义:给定上下文无关文法的产生式A→α,A∈VN , α∈V*,若α ε,则SELECT(A→α)=FIRST(α)如果α ε,则SELECT(A→α)=FIRST(α)∪FOLLOW(A) * * 调用返回
定义:一个上下文无关文法是LL(1)文法的充要条件是:对每个非终结符A的两个不同产生式A→α和A→β,满足SELECT(A→α)∩SELECT(A→β)=Φ其中α,β不同时能 ε。 *
第一个L表示:自顶向下分析是从左向右扫描输入串。第一个L表示:自顶向下分析是从左向右扫描输入串。 第二个L表示:分析过程中将用最左推导。 1表示:只需向右看一个符号便可决定如何推导(即选择哪个产生式进行推导)。 类似也可以有LL(K)文法:需向前查看K个符号才可确定选用哪个产生式。 LL(1)文法的含义:
文法G[S]是否是LL(1)文法:S→aAS→dA→bASA→ε SELECT(S→aA) ={a}SELECT(S→d) ={d}SELECT(A→bAS) ={b}SELECT(A→ε) ={a,d,#,ε} SELECT(S→aA) ∩ SELECT(S→d)={a}∩{d}=ΦSELECT(A→bAS)∩SELECT(A→ε)={b}∩{a,d,#, ε}=Φ 所以该文法是LL(1)文法。
设文法G[S] 为:S→aASS→bA→bAA→ε SELECT(S→aAS) ={a}SELECT(S→b) ={b}SELECT(A→bA) ={b}SELECT(A→ε) ={a,b,ε} SELECT(S→aAS) ∩ SELECT(S→b)={a}∩{b}=ΦSELECT(A→bA)∩SELECT(A→ε)={b}∩{a,b,ε}≠Φ 所以该文法不是LL(1)文法。
G[S]:S→aASS→bA→bAA→ε 对输入串W=ab进行推导: S aAS abAS abS 出错 S aAS aS ab
求出能推出ε的非终结符 计算FIRST集 计算FOLLOW集 计算SELECT集 判别是否是LL(1)文法 LL(1)文法的判别
例:设文法G[S] 为:S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c判断它是否是LL(1)文法。
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c 1.求出能推出ε的非终结符
1.若XV,则FIRST(X)={X} 2.若XVN,且有产生式Xa…,则a∈FIRST(X);若X也是一条产生式,则∈FIRST(X). 3.若XY…是一个产生式且YVN,则把FIRST(Y)中的所有非元素都加到FIRST(X)中;若X Y1Y2…YK是一个产生式,Y1,Y2,…,Y(i-1)都是非终结符,而且,对于任何j,1≤j ≤i-1,FIRST(Yj)都含有(即Y1..Y(i-1) ),则把FIRST(Yj)中的所有非元素都加到FIRST(X)中;特别是,若所有的FIRST(Yj ,j=1,2,…,K)均含有,则把加到FRIST(X)中. 2.计算FIRST集 *
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c FIRST(S)=(FIRST(A)-{ε})∪FIRST(B)-{ε})∪{ε}∪{b}={a,b,ε} FIRST(A)={b, ε} FIRST(B)={a, ε} FIRST(C)={a,b,c} FIRST(D)={a,c} FIRST(AB)={a,b,ε} FIRST(AD)={a,b,c}
1.对于文法的开始符号S,置#于FOLLOW(S)。; 2.若A→αBβ是一个产生式,则把 FIRST(β)\{}加至FOLLOW(B)中; 3.若A→αB是一个产生式,或A→αBβ是 一个产生式而β(即FIRST(β)),则把FOLLOW(A),加至FOLLOW(B)中. 3.计算FOLLOW集 *
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c FOLLOW(S)={#}∪FOLLOW(D) FOLLOW(A)={a}∪{a,c}∪FOLLOW(S) FOLLOW(B)=FOLLOW(S) FOLLOW(C)=FOLLOW(S) FOLLOW(D)=FOLLOW(B)∪FOLLOW(C) FOLLOW(S)= {#} FOLLOW(A)= {a,c,#} FOLLOW(B)= {#} FOLLOW(C)= {#} FOLLOW(D)= {#}
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c 4.计算SELECT集 FIRST(S)={a,b,ε} FIRST(A)={b, ε} FIRST(B)={a, ε} FIRST(C)={a,b,c} FIRST(D)={a,c} FIRST(AB)={a,b,ε} FIRST(AD)={a,b,c} SELECT(S→AB)={a,b,ε,#} SELECT(S→bC)={b} SELECT(A→ε)={a,c,#,ε} SELECT(A→b)={b} SELECT(B→ε)={#,ε} SELECT(B→aD)={a} SELECT(C→AD)={a,b,c} SELECT(C→b)={b} SELECT(D→aS)={a} SELECT(D→c)={c} FOLLOW(S)= {#} FOLLOW(A)= {a,c,#} FOLLOW(B)= {#} FOLLOW(C)= {#} FOLLOW(D)= {#} 该文法不是LL(1)文法。
提取左公共因子 消除左递归 某些非LL(1)文法到LL(1)文法的等价变换
A→αβ|αγ导致SELECT(A→αβ)∩ SELECT(A→αγ)≠Φ,因此非LL(1)文法。 等价变换为A→α(β|γ),然后:A→αA'A' → β|γ A→αβ1|αβ2|…|αβn 变换为A→α(β1|β2|…|βn),然后:A→αA'A' → β1|β2|…|βn 提取左公共因子
例:文法G1[S] 为:S→aSbS→aSS→ε 化为:S→aS(b|ε)S→ε 进一步化为:S→aSA A→b A→ε S→ε w=aabb S=>aSA =>aaSAA =>aaAA =>aabA (aaA) 结果仍然不是LL(1)文法。因此,文法中不含左公共因子只是LL(1)文法的必要条件。
例:文法G2为:A→adA→BcB→aAB→bB 2.化为: A→a(d|Ac) A→bBc B→aAB→bB 3.化为: A→aA' A→bBc A'→d A'→Ac B→aAB→bB 1.化为:A→ad A→aAc A→bBc B→aAB→bB 结果是LL(1)文法。
例:文法G3[S] 为:S→aSd S→Ac A→aS A→b 3.化为: S→aSA' S→bc A'→d A'→c A→aSA→b 1.化为:S→aSdS→aSc S→bc A→aSA→b 2.化为: S→aS(d|c)S→bc A→aSA→b 结果中A是不可达到的符号。
例:文法G4[S] 为:S→Ap|BqA→aAp|dB→aBq|e 3.化为: S→aS' S→dq|eq S'→App|BqqA→aAp|dB→aBq|e 1.化为:S→aApp|aBqq|dq|eqA→aAp|dB→aBq|e 4.化为: S→aS' S→dq|eq S'→ aAppp|aBqqq|dpp|eqqA→aAp|dB→aBq|e 2.化为: S→a(App|Bqq)S→dq|eq A→aAp|dB→aBq|e 利用提取左公共因子无法在有限步骤内替换成无左公共因子的文法。
不一定每个文法的左公共因子都能在有限的步骤内替换成无左公共因子的文法。不一定每个文法的左公共因子都能在有限的步骤内替换成无左公共因子的文法。 一个文法提取了左公共因子后,只解决了相同左部产生式右部的FIRST集不相交问题,当改写后的文法不含空产生式,且无左递归时,则改写后的文法是LL(1)文法,否则还需用LL(1)文法的判别方式进行判断才能确定是否为LL(1)文法。 结论
直接左递归:A→Aβ AVN, β V* 间接左递归:A→BβB→Aα A,BVN, α,β V* 消除左递归
文法G5含有直接左递归:S→SaS→b所能产生的语言L={ban|n≥0}输入串baaaa#是该语言的句子,但如何用自顶向下分析呢?文法G5含有直接左递归:S→SaS→b所能产生的语言L={ban|n≥0}输入串baaaa#是该语言的句子,但如何用自顶向下分析呢?
文法G6含有间接左递归:A→aBA→BbB→AcB→d输入串adbcbcbc#A→aB→adA→aB→aAc→aBbc→aAcbc…文法G6含有间接左递归:A→aBA→BbB→AcB→d输入串adbcbcbc#A→aB→adA→aB→aAc→aBbc→aAcbc…
把直接左递归改写为右递归。 如G5:S→SaS→b(L={ban|n≥0}) 改为:S→bS'S'→aS'|ε 消除直接左递归
消除直接左递归的一般方法: A→Aα1| Aα2|…| Aαm|β1|β2|…|βn其中: αi 不等于ε , βj不以A开头。 改为: A→ β1A'| β2A' |…| βnA' A'→ α1A' | α2A' |…| αmA' |ε
将间接左递归变为直接左递归,然后消除直接左递归。如文法G6含有间接左递归:A→aBA→BbB→AcB→d将间接左递归变为直接左递归,然后消除直接左递归。如文法G6含有间接左递归:A→aBA→BbB→AcB→d 消除间接左递归 B→aBcB→BbcB→d B→aBcB' | dB' B'→bcB'| ε
1.无回路(A(A (A) 2.无空产生式 (1) 以某种顺序将文法非终结符排列A1 ,A2 …An (2) for i:=1 to n do begin for j:=1 to i-1 do 用Ai-->1| 2r…| k r替代 形如Ai--> Ajr的规则,其中 Aj--> 1| 2…| k是关于Aj的全部产生式; 消除Ai规则的直接左递归; end; (3)化简由2得到的文法 消除文法中一切左递归的算法 +
文法G:S→Qc|cQ→Rb|bR→Sa|a 例: R→ Qca|ca|a R→ Rbca|bca|ca|a R→ (bca|ca|a)R' R' → bcaR'|ε
1.由于相同左部的产生式的右部FIRST集交集不为空引起回溯。1.由于相同左部的产生式的右部FIRST集交集不为空引起回溯。 设文法G[S] 为:S→xAy A→ab|a 不确定的自顶向下分析思想 w=xay S S S x A y x A y x A y a a b 试探 回溯 试探
2.由于相同左部非终结符的右部能 ε 且该非终结符FOLLOW集中含有其右部FIRST集的元素。 设文法G[S] 为:S→aASS→bA→bASA→ε * w=ab# S S S a A S a A S a A S ε b b A S 试探再试探 回溯
3.由于文法含有左递归而引起回溯。 设文法G[S] 为:S→SaS→b w=baa# S S S S S S a S a S a S a b S a S a b b
1.递归子程序法 实现思想:对文法中每个非终结符编写一个递归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选时能够按LL(1)形式可唯一地确定选择某个候选进行推导。 限制:对文法要求高,必须满足LL(1)文法;由于递归调用多,速度慢,占用空间多。 确定的自顶向下分析方法
预测分析器: 预测分析程序(P.88) 先进后出栈 预测分析表 2.预测分析法
表达式文法: E →E+T | T T →T*F | F F → i | ( E ) 预测分析表的构造
1.判断文法是否为LL(1)文法 消除左递归: 构造过程 E →TE'E' → +TE' | ε T →FT'T' → *FT' | ε F → i | ( E ) E →E+T | T T →T*F | F F → i | ( E )
E →TE'E' → +TE' | ε T →FT'T' → *FT' | ε F → i | ( E ) 可推出 ε 的非终结符表:
FIRST(E)={ ( , i } FIRST(E')={ + , ε } FIRST(T)={ ( , i } FIRST(T')={ * , ε } FIRST(F)={ ( , i } FOLLOW(E)={ ) , # } FOLLOW(E')={ ) , # } FOLLOW(T)={ + , ) , # } FOLLOW(T')={ + , ) , # } FOLLOW(F)={ * , + , ) , # } 各非终结符的FIRST集和FOLLOW集: E →TE'E' → +TE' | ε T →FT'T' → *FT' | ε F → i | ( E ) 查看FIRST定义 查看FOLLOW定义
SELECT(E →TE') ={( , i} SELECT(E' → +TE' ) ={+} SELECT(E' → ε) ={ε, ) , #} SELECT(T →FT') ={( , i } SELECT(T' → *FT' ) ={*} SELECT(T' → ε) ={ε, + , ) , #} SELECT(F → ( E )) ={(} SELECT(F → i) ={ i} 各产生式的SELECT集: FOLLOW(E)={ ) , # } FOLLOW(E')={ ) , # } FOLLOW(T)={ + , ) , # } FOLLOW(T')={ + , ) , # } FOLLOW(F)={ * , + , ) , # } E →TE'E' → +TE' | ε T →FT'T' → *FT' | ε F → i | ( E ) FIRST(E)={ ( , i } FIRST(E')={ + , ε } FIRST(T)={ ( , i } FIRST(T')={ * , ε } FIRST(F)={ ( , i } 是LL(1)文法。 查看SELECT定义
SELECT(E →TE') ={( , i} SELECT(E' → +TE' ) ={+} SELECT(E' → ε) ={ε, ) , #} SELECT(T →FT') ={( , i } SELECT(T' → *FT' ) ={*} SELECT(T' → ε) ={ε, + , ) , #} SELECT(F → ( E )) ={(} SELECT(F → i) ={ i} 2.构造预测分析表