第5章 自顶向下语法分析方法
DESCRIPTION
确定的自顶向下分析思想 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. - PowerPoint PPT PresentationTRANSCRIPT
编译原理编译原理
第 5 章 自顶向下语法分析方法
确定的自顶向下分析思想 LL(1) 文法的判别 某些非 LL(1) 文法到 LL(1) 文法的等
价变换 不确定的自顶向下分析思想 确定的自顶向下分析方法
返回目录
编译原理编译原理
确定的自顶向下分析思想
• 文法G1[S]:S→pAS→qBA→cAdA→aB→dBB→b
W=pccadd 自顶向下的推导过程:
S pA pcAd pccAdd pccadd
语法树:
S
p A
S
p A
c A d
S
p A
c A d
c A d
S
p A
c A d
c A d
a
编译原理编译原理
这个文法的特点:1. 每个产生式的右部都由终终
结符号结符号开始。2. 如果两个产生式有相同的
左部,那么它们的右部由不同的不同的终结符开始。
• 文法 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
A p
S
A p
c A
S
A p
c A
c A
S
A p
c A
c A
a
编译原理编译原理
这个文法的特点:1. 每个产生式的右部不全是
由终结符号终结符号开始。2. 如果两个产生式有相同的
左部,那么它们的右部由不同的不同的终结符或非终结符开始。
3. 文法中无空产生式。
• 文法 G1[S]:S→ApS→BqA→aA→cAB→bB→dB
编译原理编译原理
定义: 设 G = (VT ,VN , S , P) 是上下文无关文法,
FIRST(α)FIRST(α) = {a|α α aaββ,a V∈ T,α 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 V∈ N , S 是开始符号。 FOLLOW(FOLLOW(AA)) = {a|S A 且 a∈FRIST(),
∈VT*,∈V+
} 若 S A, 且 ε ,则规定 # FOLLOW(A)∈
即: FOLLOW(A)={a|S …FOLLOW(A)={a|S …AaAa… ,a… ,a∈V∈VTT}}若 S …A ,则规定 # FOLLOW(A)∈# 作为输入串的结束符,或称为句子括号,如:# 输入串 #
*
* ***
*
调用返回
编译原理编译原理
对 A→α , A→β 其中 A V∈ N , α, β V∈ N* ,当α 和 β 不同时推导出空时(设 α 不推导出空,β 推导出空),则当FIRST(α)∩(FIRST(β) FOLLOW(A))=∪ Φ 时,对于非终结符 A 的替换仍可唯一地确定候选。
编译原理编译原理
定义:给定上下文无关文法的产生式A→α , A∈VN , α V*∈ ,若 α ε ,则 SELECT(A→SELECT(A→α)α)=FIRST(α)如果 α ε ,则SELECT(A→α)SELECT(A→α)=FIRST(α) FOLLOW(A)∪
**
调用返回
编译原理编译原理
定义:一个上下文无关文法是 LL(1)LL(1) 文文法法的充要条件是:对每个非终结符 A 的两个不同产生式A→α 和 A→β ,满足SELECT(A→α)∩SELECT(A→β)=Φ其中 α,β 不同时能 ε 。
*
编译原理编译原理
LL(1) 文法的含义:
第一个 LL 表示:自顶向下分析是从左向右扫描从左向右扫描输入串输入串。第二个 LL 表示:分析过程中将用最左推导最左推导。 11 表示:只需向右看一个符号向右看一个符号便可决定如何推导(即选择哪个产生式进行推导)。类似也可以有 LL(K)LL(K) 文法:需向前查看 K 个符号才可确定选用哪个产生式。
编译原理编译原理
• 文法 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
编译原理编译原理
LL(1) 文法的判别
1. 求出能推出 ε 的非终结符2. 计算 FIRST 集3. 计算 FOLLOW 集4. 计算 SELECT 集5. 判别是否是 LL(1) 文法
编译原理编译原理• 例:设文法 G[S] 为 :
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c判断它是否是 LL(1) 文法。
编译原理编译原理
1. 求出能推出 ε 的非终结符
S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c
非终结符 S A B C D
初值 未定 未定 未定 未定 未定第一次扫描 是 是 否第二次扫描 是 否
编译原理编译原理2. 计算 FIRST 集• 1. 若 XXVV, 则 FIRST(X)={X}• 2. 若 XVN, 且有产生式 XXa…a… ,则
a∈FIRST(X);若 XX 也是一条产生式 , 则∈ FIRST(X).
• 3. 若 XXY…Y… 是一个产生式且 YVN, 则把FIRST(Y) 中的所有非元素都加到 FIRST(X)中 ; 若 X X Y Y11YY22…Y…YKK 是一个产生式 ,Y1,Y2,…,Y(i-1) 都是非终结符 , 而且 , 对于任何 j,1≤j ≤i-1,FIRST(Yj) 都含有 ( 即 YY11..Y..Y(i-1)(i-1) ), 则把FIRST(Yj) 中的所有非元素都加到 FIRST(X)中 ; 特别是 , 若所有的 FIRST(Yj , j=1,2,…,K)均含有 , 则把加到 FRIST(X) 中 .
**
编译原理编译原理
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}
编译原理编译原理
3. 计算 FOLLOW 集
• 1. 对于文法的开始符号 S, 置 # 于FOLLOW(S) 。 ;
• 2. 若A→ αBβ 是一个产生式 , 则把 FIRST(β)\{} 加至 FOLLOW(B) 中 ;
• 3. 若A→ αB 是一个产生式 , 或A→ αBβ 是 一个产生式而 β ( 即 FIRST(β) ),则把FOLLOW ( A ),加至 FOLLOW ( B )中.
**
编译原理编译原理
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)= {#}
编译原理编译原理4. 计算 SELECT 集S→ABS→bCA→εA→bB→εB→aDC→ADC→bD→aSD→c
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→aSAA→bA→εS→ε
结果仍然不是 LL(1) 文法。因此,文法中不含左公共因子只是 LL(1) 文法的必要条件。
w=aabb
S=>aSA =>aaSAA =>aaAA =>aabA (aaA)
编译原理编译原理
• 例:文法 G2 为 :A→adA→BcB→aAB→bB
1. 化为:A→adA→aAcA→bBcB→aAB→bB
2. 化为:A→a(d|Ac)A→bBcB→aAB→bB
3. 化为:A→aA' A→bBcA'→dA'→AcB→aAB→bB
结果是 LL(1) 文法。
编译原理编译原理
• 例:文法 G3[S] 为 :S→aSd S→Ac A→aS A→b
1. 化为:S→aSdS→aScS→bc A→aSA→b
2. 化为:S→aS(d|c)S→bc A→aSA→b
3. 化为:S→aSA' S→bcA'→dA'→cA→aSA→b
结果中 A 是不可达到的符号。
编译原理编译原理• 例:文法 G4[S] 为 :
S→Ap|BqA→aAp|dB→aBq|e1. 化为:S→aApp|aBqq|dq|eqA→aAp|dB→aBq|e
2. 化为:S→a(App|Bqq)S→dq|eqA→aAp|dB→aBq|e
3. 化为:S→aS' S→dq|eqS'→App|BqqA→aAp|dB→aBq|e4. 化为:S→aS' S→dq|eqS'→ aAppp|aBqqq|dpp|eqqA→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# 是该语言的句子,但如何用自顶向下分析呢?
编译原理编译原理
文法 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
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 集交集不为空引起回溯。设文法 G[S] 为 : S→xAy
A→ab|a
w=xay
S
x A y
S
x A y
a b
S
x A y
a
试探 回溯 试探
编译原理编译原理
2. 由于相同左部非终结符的右部能 ε 且该非终结符 FOLLOW 集中含有其右部 FIRST 集的元素。 设文法 G[S] 为 :S→aASS→bA→bASA→ε
*
w=ab#
S
a A S
S
a A S
b A S
S
a A S
ε b
试探再试探 回溯
编译原理编译原理
3. 由于文法含有左递归而引起回溯。设文法 G[S] 为 :S→SaS→b w=baa#
S
b
S
S a
S
S a
b
S
S a
S a
S
S a
S a
b
编译原理编译原理
确定的自顶向下分析方法
1. 递归子程序法 实现思想:对文法中每个非终结符编写一个递
归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选时能够按 LL(1) 形式可唯一地确定选择某个候选进行推导。
限制:对文法要求高,必须满足 LL(1) 文法;由于递归调用多,速度慢,占用空间多。
编译原理编译原理
2. 预测分析法
预测分析器:预测分析程序( P.88 )先进后出栈预测分析表
编译原理编译原理
预测分析表的构造
• 表达式文法:E →E+T | T
T →T*F | F
F → i | ( E )
编译原理编译原理
构造过程1. 判断文法是否为 LL(1) 文法 消除左递归:
E →E+T | T
T →T*F | F
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 )
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
编译原理编译原理可推出 ε 的非终结符表:
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
E E' T T' F
否 是 否 是 否
编译原理编译原理
各非终结符的 FIRST 集和 FOLLOW 集:FIRST(E)={ ( , i }
FIRST(E')={ + , ε }
FIRST(T)={ ( , i }
FIRST(T')={ * , ε }
FIRST(F)={ ( , i }
FOLLOW(E)={ ) , # }
FOLLOW(E')={ ) , # }
FOLLOW(T)={ + , ) , # }
FOLLOW(T')={ + , ) , # }
FOLLOW(F)={ * , + , ) , # }
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
查看 FOLLOW 定义
查看 FIRST 定义
编译原理编译原理各产生式的 SELECT 集:
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
E →TE'E' → +TE' | ε
T →FT'T' → *FT' | ε
F → i | ( E )
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 }
FIRST(E)={ ( , i }FIRST(E')={ + , ε }FIRST(T)={ ( , i }FIRST(T')={ * , ε }FIRST(F)={ ( , i }
FIRST(E)={ ( , i }FIRST(E')={ + , ε }FIRST(T)={ ( , i }FIRST(T')={ * , ε }FIRST(F)={ ( , i }
FOLLOW(E)={ ) , # }FOLLOW(E')={ ) , # }FOLLOW(T)={ + , ) , # }FOLLOW(T')={ + , ) , # }FOLLOW(F)={ * , + , ) , # }
FOLLOW(E)={ ) , # }FOLLOW(E')={ ) , # }FOLLOW(T)={ + , ) , # }FOLLOW(T')={ + , ) , # }FOLLOW(F)={ * , + , ) , # }
查看 SELECT 定义
是 LL(1) 文法。是 LL(1) 文法。
编译原理编译原理2. 构造预测分析表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 }
i + * ( ) #
E →TE' →TE'
E' +TE' → ε → ε
T →FT' →FT'
T' → ε → *FT' → ε
F → i → ( E )
运行:
i + * ( ) #
E →TE'
→TE'
E' → +TE'
→ ε → ε
T →FT'
→FT'
T' → ε → *FT'
→ ε
F → i → ( E )
分析栈#E#E'T#E'T'F#E'T'i#E'T'#E'#E'T+#E'T#E'T'F#E'T'i#E'T'#E'T'F*#E'T'F#E'T'i#E'T'#E'#
剩余串i+i*i#i+i*i#i+i*i#i+i*i#+i*i#+i*i#+i*i#
i*i#i*i#i*i#*i#*i#i#i####
产生式E→TE'T→FT'F → ii i 匹配匹配T' → εE' → +TE'+ + 匹配匹配T →FT'F → ii i 匹配匹配T → *FT'* * 匹配匹配F → ii i 匹配匹配T' → εE' → ε接受接受
例:输入 i+i*i