编译原理 第4章课件Word下载.docx
《编译原理 第4章课件Word下载.docx》由会员分享,可在线阅读,更多相关《编译原理 第4章课件Word下载.docx(21页珍藏版)》请在冰豆网上搜索。
对于产生式中相同左部含有非终结符开始的产生式时,在推导过程中选用哪个产生式不像例4.1文法那样直观,对于W=ccap为输入串时,其第一个符号是c,这时从S出发选择S→Ap还是选择S→Bq,需要知道,Ap或Bq它们的开始符号集合是什么,若c是包含在Ap的开始符号集合中,且不包含在Bq的开始符号集合中,则选择S→Ap往下进行推导。
同样若c是包含在Bq的开始符号集合中,且不包含在Ap的开始符号集合中,则选择S→Bq往下推导,其它情况则为不确定推导或出错。
例4.3若有文法G3[S]:
S→aA|d
A→bAS|ε
识别输入串w=abd是
否是G3[S]的句子
试探推导出abd的推
导过程为:
SaAabASabSabd
试探推导成功。
例4.3文法的特点是:
文法中含有空产生式。
由此可以看出,当某一非终结符的产生式中含有空产生式时,它的非空产生式右部的首符号集两两不相交,并与在推导过程中紧跟该非终结符后边可能出现的终结符集也不相交,则仍可构造确定的自顶向下分析。
当我们需选用确定的自顶向下分析方法时,首先必须判别所给的文法能否是LL
(1)文法。
先研究三个定义:
开始符号FIRST、后跟符号FOLLOW和选择集合SELECT集定义和计算
例1:
S→aAA→ε
S→dA→bAS
FIRST(S)=
FIRST(A)=
开始符号FIRST集的定义:
设G=(VN,VT,P,S)是上下文无关文法
FIRST()={a|=>
a,a∈VT,,∈V*}
若=>
ε则规定ε∈FRIST()
例2:
S→AaA→ε
FIRST(S)={b,a,d}
FIRST(A)={ε,b}
例:
FOLLOW(A)=
后跟符号FOLLOW集的定义:
FOLLOW(A)={aS=>
A且
a∈FRIST(),∈V*,∈V+}
若S=>
A,且=>
ε,则#∈FOLLOW(A)
选择集合SELECT:
给定上下文无关文法的产生式A→α
A∈VN,α∈V*,若=>
ε,则:
SELECT(A→α)=FIRST(α)
如果=>
SELECT(A→α)=FIRST(α)-{ε}∪FOLLOW(A)
S→aAS→dA→εA→bAS
SELECT(S→aA)=
SELECT(S→d)=
SELECT(A→ε)=
SELECT(A→bAS)=
FIRST(aA)={a}
FIRST(d)={d}
FOLLOW(A)={a,d,#}
{b}
LL
(1)文法:
一个上下文无关文法是LL
(1)文法的充分必要条件是,对每个非终结符A的两个不同产生式,A→α或A→满足:
SELECT(A→α)∩SELECT(A→)=其中,α、不能同时=>
ε
LL
(1)文法的含义:
第一个L:
表明自顶向下分析是从左到右扫描输入串;
第二个L:
表明分析过程中将用最左推导;
1:
表明只需向右看一个字符便可决定如何推导即选择哪个产生式。
文法G[S]:
S→aASA→ε
S→bA→bA是否为LL
(1)文法?
SELECT(S→aAS)={a}
SELECT(S→b)={b}
SELECT(A→bA)={b}
SELECT(A→ε)=First(ε)-{ε}∪FOLLOW(A)={a,b}
不难看出:
SELECT(S→aA)∩SELECT(S→b)=
SELECT(A→bA)∩SELECT(A→ε)=
由定义该文法不是LL
(1)文法,不可用确定的自顶向下分析。
例如:
w=ab
S=>
aAS=>
abAS=>
abS(失败)
aAS=>
aS=>
ab(成功)
判别文法是否是LL
(1)文法,对任何文法计算需计算FIRST、FOLLOW和SELECT集合,进而判别文法是否为LL
(1)文法。
举例说明判断LL
(1)文法的步骤。
若文法G[E]为:
(1)E–>
TE’
(2)E’–>
+TE’
(3)E’–>
(4)T–>
FT’
(5)T’–>
*FT’
(6)T’–>
(7)F–>
(E)
(8)F–>
a
判别步骤:
1.求出能推出的非终结符
计算步骤如下:
1)将数组X[]中对应每一非终结符的标志初值置为“未定”
2)扫描文法中的产生式.
(a)删除所有右部含有终结符的产生式,若这使得以某一非终结符为左部的所有产生式都被删除,则数组中对应该非终结符的标记值改为“否”.
(b)若某一非终结符的某一产生式的右部为,则则数组中对应该非终结符的标记值置为“是”,并从文法中删去该非终结符的所有产生式.
3)扫描产生式右部的每一个符号.
(a)若某非终结符在数组中的标志是“是”,则删去该非终结符,若这使得产生式右部为空,则对左部非终结符在数组中标志该为“是”,并删除该非终结符对应的所有产生式.
(b)若某非终结符在数组中的标志是“否”,则删去该产生式,若这使得产生式左部非终结符的有关产生式都被删除,则数组中对应该非终结符的标记值改为“否”.
4)重复3),直到扫描完一遍文法的产生式,数组中非终结符对应的特征再不改变为止
.
非终结符能否推出空的
非终结符
E
E’
T
T’
F
初值
第一次扫描
第二次扫描
未定
否
是
2.计算FIRST集
各非终结符的FIRST集合如下:
{(,i}
{+,ε}
{*,ε}
3.计算FOLLOW集
1)对于文法的开始符号S,置#于FOLLOW(S)中;
2)若AαBβ是一个产生式,则把FIRST(β)的非空{}加至FOLLOW(B)中;
3).若AαB是一个产生式,或AαBβ是一个产生式而β=>
(即FIRST(β)),则把FOLLOW(A)加至FOLLOW(B)中.
4)反复使用2)和3)直到每个非终结符的FOLLOW集不再增大为止。
各非终结符的FOLLOW集合为:
各非终结符的FOLLOW集合为:
FOLLOW(E)={),#}
FOLLOW(E′)=FOLLOW(E)
FOLLOW(T)={+}+FOLLOW(E)
FOLLOW(T′)=FOLLOW(T)
FOLLOW(F)={*}+FOLLOW(T)
4.产生式选择集合计算
SELELECT(E–>
TE’)={(,a}
SELECT(E’–>
+TE’)={+}
SELECT(E′–>
)=FOLLOW(E′)={),#}
SELECT(T’–>
)=FOLLOW(T’)={),#+}
*FT’)={*}
SELECT(F–>
(E))={(}
a)={a}
SELECT(E’–>
+TE’)∩SELECT(E′–>
)=
SELECT(T’–>
*FT’)∩SELECT(T’–>
SELECT(F–>
(E))∩SELECT(F–>
a)=
以上相同左部的产生式的SELECT集交集为,所以G[E]是LL
(1)文法。
4.3某些非LL
(1)文法到LL
(1)文法的等价变换
有时,我们通过提取左公共因子和消除左递归等对文法进行等价变换,可以使得非LL
(1)变成LL
(1)文法。
LL
(1)文法的性质:
LL
(1)文法不含左公共因子
LL
(1)文法不含左递归
一、提左公因子
将产生式Aβ|变换为:
ABBβ|
提左因子S→ifCtSA
A→eS|C→b
S→ifCtS|ifCtSeS
C→b
注:
1)可通过反复提取左因子,一般能把所有非终结符的所有候选首符集变为两两不相交。
2)反复提取左因子也有一定代价,因为在提取过程中会大量引入非终结符和产生式,会增加语法分析的复杂性。
3)提取左公共因子变换后,有时会使某些产生式变成无用产生式,此时必须对文法重新化简。
提取公共左因子一般形式为:
将某产生式A1|2|….|n
改写为AA`
A`1|2|….|n
说明:
1、文法中不含左公共因子只是LL
(1)文法的必要条件。
G1[S]
S->
aSA
A->
b
G[S]:
S->
aSb变换后:
aS
SELECT(S->
aSA)={a}
)=FOLLOW(S)={#,b}
SELECT(A->
b)={b}
)=FOLLOW(S)={#,b}
是否为LL
2、某些文法不能在有限步骤内提取完左公共因子。
(1)S->
aApp|aBqq
(2)S->
dp|eq
(3)A->
aAp|d
(4)B->
aBq|e
(1)提取左公共因子后变成:
aS’(5)S’’->
Appp|Bqqq
dp|eq(6)A->
(3)S->
aS’’(7)B->
(4)S’->
dpp|eqq
aS’
dp|eq
(3)S’->
App|Bqq
(4)A->
(5)B->
用(4)(5)替换(3)后提取左公共因子后变成,变为:
3、一个文法提取了左公共因子后,只解决了相同左部产生式右部的FIRST集不相交问题,当改后的文法不含空产生式,且无左递归时,则改写后的文法是LL
(1)文法,否则还需要用判别方式进行判别才能确定。
二、消除左递归
1)什么是左递归左递归:
文法存在产生式PPa直接左递归:
PPa
间接左递归:
PAa,APb
2)消除左递归消除直接左递归消除间接左递归消除所有左递归
1、消除直接左递归
设有文法G=(VN,VT,P,S),其中产生式P为
PP|,V+,V+且不以P开头
将它转换为等价式:
PP’P’P’|
一般地:
将PP1|P2|….|Pm|1|2|….|n
转换为:
P1P`|2p`|……|nP`P`1P`|2P`|……|mP`|
E–>
TE’
E’–>
+TE’|
T–>
T’–>
*FT’|
F→i|(E)
2、消除间接左递归
对于间接左递归的消除先将间接左递归变为直接左递归,再按消除直接左递归消除.例:
(1)A–>
Bb
(2)B–>
Ac
(3)B–>
d
先将
(1)代入
(2):
B–>
Bbc再消除左递归
dB’
B’–>
bcB’|
3、消除文法中一切左递归
要求:
文法中不含回路A+=>
A的推导
1)把文法G的所有非终结符按任意顺序排列成P1,P2,…,Pn,然后按此顺序执行步骤2。
2)For(I=1,I<
=n,I++)
{for(k=1,k<
=I-1,k++)
{把形如PiPk的规则改写为
Pi1|2|……|,n,其中Pk1|2|……|,n}
消除Pi规则的直接左递归;
}
3)删去从文法开始符号不可达的非终结符产生式。
1)此算法适用于消除不含形如PP的产生式,也不含以为右部的产生式的文法
2)这里第二步所做的工作是:
a)若产生式出现直接左递归则用消除直接左递归的方法消除掉。
b)若产生式右部最左符号是非终结符且其序号大于左部的非终结符,则不处理。
c)若序号小于左部的非终结符,则将这序号小的非终结符用其右部串来取代,然后消除新的直接左递归。
解:
1)对非终结符重新排序:
R、Q、S
2)对R:
S的序号大于R的序号,不处理。
对Q:
R的序号1小于Q的序号2,所以改写
QRb|b,将RSa|a的右部取代R,得到:
QSab|ab|b,记为:
(2`)式;
此时,S的序号大于Q的序号,不再处理。
对S:
Q的序号2小于S的序号3,所以改写
SQc|c,将QSab|ab|b的右部取代Q,得到
SSabc|abc|bc|c;
出现直接左递归,变换为:
S(abc|bc|c)S`
S`abcS`|
3)由于RSa|a和QSab|ab|b中的R,Q对开始符号S来说都是不可达非终结符,所有删除它们。
故最后消除左递归后文法为:
S`abcS`|
1)若非终结符排列顺序不同,改写后的文法也不同,但它们是等价的。
2)开始符号不能改变。
4.4不确定的自上而下分析
引起回溯的原因
由于相同左部的产生式的右部FIRST集交集不为空而引起回溯
由于相同左部非终结符的右部都能,且该非终结符的FOLLOW集中含有其
右部FIRST集元素
由于文法含有左递归而引起回溯
S–>
AB
A–>
aA|
B–>
b|bB
aaabb.
S
(1)A...S–>
(2)aA...A–>
aA
(3)aaA...A–>
(4)aaaA...A–>
aA(5)aaaB...A–>
(6)aaabB–>
b
aaabb.
(2)aA...A–>
(3)aaA...A–>
(4)aaaA...A–>
(5)aaaBA–>
(6’)aaabBB–>
bB
(7)aaabbB–>
b
特征——根据下一个输入符号为当前要处理的非终结符选择产生式
1递归子程序法
2预测分析方法
1递归子程序法
•特点:
–简单直观易于构造
–要求文法满足LL
(1)文法
•实现思想:
–对应文法中每个非终结符编写一个递归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选时能够按LL
(1)形式可以唯一地确定选择某个候选进行推导。
•缺点:
–对文法要求高
–递归调用多,速度慢,占用空间多
递归子程序实例:
表达式的语法分析
表达式的EBNF
〈表达式〉∷=[+|-]〈项〉{(+|-)〈项〉}
〈项〉∷=〈因子〉{(*|/)〈因子〉}
〈因子〉∷=ident|number|‘(’〈表达式〉‘)’
procedureexpr;
begin
ifsymin[plus,minus]then
begin
getsym;
//词法分析,读取一个单词
term;
//项处理
end
elseterm;
whilesymin[plus,minus]do
end;
Procedureterm;
begin
factor;
//因子处理
whilesymin[times,slash]do
factor
end;
Procedurefactor;
beginifsym=ident
thengetsym
else
ifsym=number
ifsym=‘(‘
thenbegin
expr;
ifsym=‘)’
elseerror
2预测分析方法
一个预测分析器由三个部分组成:
预测分析程序
先进后出栈
预测分析器表
其中只有预测分析器表与文法有关
预测分析表可用一个矩阵M(或称二维数组)表示。
矩阵元素M[A,a]中的下标A表示非终结符,a为终结符或句子括号“#”,矩阵元素M[A,a]中的内容为存放着一条关于A的产生式,表明当用非终结符A向下推导时,面临输入符号a时,应采取的候选产生式,若无产生式,元素内容转向出错处理的信息。
预测分析程序的工作过程
图中符号说明如下:
"
#"
句子括号即输入串的括号
S"
文法的开始符号
X"
存放当前栈顶符号的工作单元
a"
存放当前输入符号a的工作单元
BEGIN
首先把’#‘然后把文法开始符号推入栈;
把第一个输入符号读进a;
FLAG:
=TRUE;
WHILEFLAGDO
BEGIN
把栈顶符号上托出去并放在X中;
IFXVtTHENIFX=aTHEN
把下一个输入符号读进aELSEERROR
ELSEIFX=‘#’THEN
IFX=aTHENFLAG:
=FALSEELSEERROR
ELSEIF[X,a]={X–>
X1X2..XK}
THEN把XK,XK-1,..,X1一一推进栈ELSE ERROR
ENDOFWHILE;
STOP/*分析成功,过程完毕*/
END
分析算法
预测分析表构造算法
1.对文法G的每个产生式A,每个终结符或“#”用a表示;
若aSELECT(A),把A加至[A,a]中,
2.把所有无定义的[A,a]标上“出错标志”。
为了使表简化,其产生式左部可以不写入表中,表中空白处为出错。
可以证明,一个文法G的予测分析表不含多重入口,当且仅当该文法是LL
(1)的
G[E]:
E–>
E+T|T
T–>
T*F|F
F–>
a|(E)
(1)判断文法是否为LL
(1)文法
由于文法中含有左递归,所与必须先消除左递归,使文法变为:
G[E]:
(1)E–>
+TE’
FT’
*FT’
(E)
a
1.可推出的非终结符表为:
E`
T`
2.各非终结符的FIRST集合如下:
FIRST(E)={(,a}
FIRST(E`)={+,}
FIRST(T)={(,a}
FIRST(T`)={*,}
FIRST(F)={(,a}
3.各非终结符的集合如下:
FOLLOW(E)={(,#}
FOLLOW(E`)={),#}
FOLLOW(T)={+,),#}
FOLLOW(T`)={+,),#}
FOLLOW(F)={*,+,),#}
SELECT(E–>
TE’)={(,a}SELECT(E’–>
+TE’)={+}
SELECT(E’–>
)={),#}SELECT(T–>
FT’)={(,a}
*FT’)={*}SELECT(T’–>
)={+,),#}
(E))={(}SELECT(F–>
a)={a}
+
*
(
)
#
E
→TE’
→TE’
E’
→+TE’
–>
T
T’
*FT
F
–>
分析输入串#a+a#
栈内容栈顶符号当前输入余留串M[X,b]
1#EEa+a#E–>
2#E’TTa+a#T–>
3#E’T’FFa+a#F–>
4#E’T’aaa+a#
5#E’T’T’+a#T’–>
6#E’E’+a#E’–>
+TE