1、编译原理 第4章课件第四章 自顶向下语法分析方法教学要求重点: LL(1)文法的定义和判别 非LL(1)文法的等价变换 预测分析方法难点:对一个文法如何判断是否是LL(1)文法,由于在判断 LL(1)文法时用到文 法符号串的开始符号集合(FIRST集)和非终结符后跟符号集合(FOLLOW集)的计算,而一般学员往往因概念不清或不够细心对这两个集合的计算常常出错,导致判断和分析结果的错误。 目录:4.1 确定的自顶向下分析思想4.2 LL(1)文法的判别4.3 非LL(1)文法的改造4.4 不确定的自顶向下分析思想4.5 确定的自顶向下分析方法语法分析方法分类自顶向下分析方法 确定的自顶向下分析方
2、法 递归子程序法预测分析方法不确定的自顶向下分析方法 带回溯的分析方法自底向上分析方法 算符优先分析LR类分析4.1 确定的自顶向下分析思想 确定的自顶向下分析方法,首先要解决从文法的开始符号出发,如何根据当前的输入符号唯一地确定选用哪个产生式替换相应非终结符往下推导,或构造一颗相应的语法树。例4.1若有文法G1S: S pA |qB A cAd|a B d B |c 识别输入串w= pccadd是否是 G1S的句子试探推导过程: S pA pcAd pccAdd pccadd试探成功。例 4.1 这个文法有以下两个特点: 每个产生式的右部都由终结符号开始。 如果两个产生式有相同的左部,那么它
3、们的右部由不同的终结符开始。对于这样的文法显然在推导过程中完全可以根据当前的输入符号决定选择哪个产生式往下推导,因此分析过程是唯一确定的。 例4.2若有文法G2S: S Ap |Bq A a|cA B b|dB识别输入串w=ccap是否是G2S的句子,那么试探推出输入串的推导过程为 :S Ap cAp ccAp ccap试探推导成功。 例4.2 文法的特点是: 产生式的右部不 全是由终结符开始。 如果两个产生式 有相同的左部,它们的右部是由不同的终结符或非终结符开始。 文法中无空产生式。对于产生式中相同左部含有非终结符开始的产生式时,在推导过程中选用哪个产生式不像例4.1文法那样直观,对于 W
4、=ccap 为输入串时,其第一个符号是c,这时从S出发选择 SAp 还是选择 SBq,需要知道,Ap或Bq它们的开始符号集合是什么,若c是包含在Ap的开始符号集合中,且不包含在Bq的开始符号集合中,则选择 SAp 往下进行推导。同样若c是包含在Bq的开始符号集合中,且不包含在Ap的开始符号集合中,则选择 SBq 往下推导,其它情况则为不确定推导或出错。 例 4.3若有文法G3S:S aA|dA bAS|识别输入串w=abd是 否是G3S的句子试探推导出abd的推导过程为: S aA abAS abS abd 试探推导成功。 例4.3 文法的特点是: 文法中含有空产生式。由此可以看出,当某一非终
5、结符的产生式中含有空产生式时,它的非空产生式右部的首符号集两两不相交,并与在推导过程中紧跟该非终结符后边可能出现的终结符集也不相交,则仍可构造确定的自顶向下分析。当我们需选用确定的自顶向下分析方法时,首先必须判别所给的文法能否是LL(1)文法。先研究三个定义: 开始符号FIRST、后跟符号FOLLOW和选择集合SELECT集定义和计算例1: SaA A Sd AbASFIRST(S)=FIRST(A)= 开始符号FIRST集的定义:设G=(VN,VT,P,S)是上下文无关文法FIRST()=a| =a,aVT, , V* 若 =则规定FRIST() 例2: SAa A Sd AbASFIRST
6、(S)=b, a , dFIRST(A)=,bFIRST(S)=FIRST(A)=例: SaA A Sd AbAS FOLLOW(A)= 后跟符号FOLLOW集的定义: FOLLOW(A)=a S = A且 aFRIST(),V*, V+ 若S = A ,且 =,则#FOLLOW(A) 选择集合SELECT:给定上下文无关文法的产生式A A VN, V* ,若 =,则: SELECT(A )=FIRST() 如果 =,则: SELECT(A )=FIRST()- FOLLOW(A)例: SaA Sd A AbASSELECT(SaA )=SELECT(Sd )=SELECT(A )=SELEC
7、T(AbAS) =FIRST( aA )=aFIRST(d)=dFOLLOW(A)=a,d,#bLL(1)文法: 一个上下文无关文法是LL(1)文法的充分必要条件是,对每个非终结符A的两个不同产生式, A 或 A 满足: SELECT(A ) SELECT(A )= 其中, 、 不能同时=LL(1)文法的含义: 第一个L:表明自顶向下分析是从左到右扫描输入串; 第二个L:表明分析过程中将用最左推导; 1:表明只需向右看一个字符便可决定如何推导即选择哪个产生式。例:文法GS:SaAS A Sb AbA 是否为LL(1)文法?SELECT(SaAS )=aSELECT(Sb)=bSELECT(Ab
8、A)=bSELECT(A)=First()-FOLLOW(A)=a,b 不难看出:SELECT(SaA)SELECT(Sb)= SELECT(AbA)SELECT(A) =由定义该文法不是LL(1)文法,不可用确定的自顶向下分析。例如:w=ab S=aAS=abAS=abS(失败) S= aAS=aS=ab(成功) 4.2 LL(1)文法的判别判别文法是否是LL(1)文法,对任何文法计算需计算FIRST、FOLLOW和SELECT集合,进而判别文法是否为LL(1)文法。举例说明判断LL(1)文法的步骤。例:若文法G E为: (1) E TE (2) E +TE (3) E (4) T FT (
9、5) T *FT (6) T (7) F (E) (8) F a判别步骤: 1.求出能推出的非终结符 计算步骤如下:1)将数组X中对应每一非终结符的标志初值置为“未定”2)扫描文法中的产生式. (a)删除所有右部含有终结符的产生式, 若这使得以某一非终结符为左部的所有产生式都被删除,则数组中对应该非终结符的标记值改为“否”.(b)若某一非终结符的某一产生式的右部为, 则则数组中对应该非终结符的标记值置为“是”,并从文法中删去该非终结符的所有产生式.3)扫描产生式右部的每一个符号.(a)若某非终结符在数组中的标志是“是”,则删去该非终结符,若这使得产生式右部为空, 则对左部非终结符在数组中标志该
10、为“是”,并删除该非终结符对应的所有产生式.(b)若某非终结符在数组中的标志是“否”,则删去该产生式,若这使得产生式左部非终结符的有关产生式都被删除,则数组中对应该非终结符的标记值改为“否”.4)重复3), 直到扫描完一遍文法的产生式,数组中非终结符对应的特征再不改变为止.非终结符能否推出空的非终结符EETTF初值第一次扫描第二次扫描未定否是未定否是否 2.计算FIRST集各非终结符的FIRST集合如下:(,i+,(,i*,(,i3.计算FOLLOW集1)对于文法的开始符号S,置#于FOLLOW(S) 中;2)若 B 是一个产生式,则把 FIRST()的非空加至FOLLOW(B)中;3).若
11、B是一个产生式,或 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
12、(T )=FOLLOW( T)= ), + SELECT(T *FT )=* SELECT(F (E) )= ( SELECT(F a )= aSELECT(E +TE)SELECT(E )= SELECT(T *FT )SELECT(T )= SELECT(F (E) ) SELECT(F a )= 以上相同左部的产生式的SELECT集交集为,所以GE是LL(1)文法。4.3 某些非LL(1)文法到LL(1)文法的等价变换有时,我们通过提取左公共因子和消除左递归等对文法进行等价变换,可以使得非LL(1)变成LL(1)文法。LL(1)文法的性质: LL(1)文法不含左公共因子 LL(1)文法不
13、含左递归一、提左公因子将产生式 | 变换为: BB |提左因子 S if C t S A A e S | C b例:S if C t S | if C t S e S C b注:1)可通过反复提取左因子,一般能把所有非终结符的所有候选首符集变为两两不相交。 2)反复提取左因子也有一定代价,因为在提取过程中会大量引入非终结符和产生式,会增加语法分析的复杂性。3)提取左公共因子变换后,有时会使某些产生式变成无用产生式,此时必须对文法重新化简。提取公共左因子一般形式为: 将某产生式A1| 2|. | n 改写为 AA A1|2|. |n 说明:1、文法中不含左公共因子只是LL(1)文法的必要条件。G
14、1SS-aSA A-bA- S- 例如:GS: S-aSb 变换后: S-aS S- SELECT(S-aSA)=aSELECT(S- )=FOLLOW(S)=#,bSELECT(A-b)=bSELECT(A- )= FOLLOW(S)=#,b 是否为LL2、某些文法不能在有限步骤内提取完左公共因子。(1)S-aApp|aBqq(2)S-dp|eq(3)A-aAp|d(4)B-aBq|e(1)提取左公共因子后变成:(1)S-aS (5) S-Appp|Bqqq(2)S- dp|eq (6)A-aAp|d(3) S-aS (7)B-aBq|e(4) S-dpp|eqq(1)S-aS (2)S-
15、dp|eq(3)S-App|Bqq(4)A-aAp|d(5)B-aBq|e用(4)(5)替换(3)后提取左公共因子后变成,变为:3、一个文法提取了左公共因子后,只解决了相同左部产生式右部的FIRST集不相交问题,当改后的文法不含空产生式,且无左递归时,则改写后的文法是LL(1)文法,否则还需要用判别方式进行判别才能确定。二、消除左递归1)什么是左递归 左递归:文法存在产生式P Pa 直接左递归: P Pa 间接左递归: P Aa , APb2)消除左递归 消除直接左递归 消除间接左递归 消除所有左递归1、消除直接左递归设有文法G=(VN, VT ,P,S),其中产生式P为P P| , V+ ,
16、 V+ 且不以P开头将它转换为等价式: P P P P| 一般地:将P P 1| P 2|. |P m|1| 2|.| n 转换为: P 1P| 2 p| n P P 1P| 2P| mP| E TE E +TE | T FT T *FT | Fi(E) 2、消除间接左递归 对于间接左递归的消除先将间接左递归变为直接左递归,再按消除直接左递归消除.例:(1)A Bb(2)B Ac(3)B d先将(1)代入(2): B Bbc再消除左递归 B dB B bc B | 3、消除文法中一切左递归要求:文法中不含回路A+=A的推导1)把文法G的所有非终结符按任意顺序排列成P1,P2,Pn,然后按此顺序
17、执行步骤2。2) For (I=1,I=n,I+) for (k=1,k ABA aA | B b | bBa a a b b.S(1) A. S AB(2) aA. A aA(3) aaA. A aA(4) aaaA. A aA (5) aaa B. A (6) aaab B baaabb.S(1) A. S AB (2) aA. A aA (3) aaA. A aA (4) aaaA. A aA (5) aaa B A (6) aaa b B B bB(7) aaabb B b 4.5 确定的自顶向下分析方法特征根据下一个输入符号为当前要处理的非终结符选择产生式 1 递归子程序法 2 预测
18、分析方法1 递归子程序法 特点: 简单直观易于构造 要求文法满足LL(1)文法 实现思想: 对应文法中每个非终结符编写一个递归过程,每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选时能够按LL(1)形式可以唯一地确定选择某个候选进行推导。 缺点: 对文法要求高 递归调用多,速度慢,占用空间多递归子程序实例:表达式的语法分析表达式的EBNF表达式=+|-项(+|-)项项=因子(*|/)因子因子=ident|number|(表达式)表达式=+|-项(+|-)项procedure expr;begin if sym in plus, minus then begin gets
19、ym; /词法分析,读取一个单词 term; /项处理 endelse term; while sym in plus, minus do begin getsym; term; endend;项=因子(*|/)因子 Procedure term; begin factor; /因子处理 while sym in times,slash do begin getsym; factor end end;因子=ident|number|(表达式)Procedure factor; begin if sym=ident then getsym else if sym=number then gets
20、ym else if sym=( then begin getsym; expr; if sym=) then getsym else error end else error end; 2 预测分析方法一个预测分析器由三个部分组成: 预测分析程序 先进后出栈 预测分析器表其中只有预测分析器表与文法有关 预测分析表可用一个矩阵M(或称二维数组)表示。矩阵元素MA,a中的下标A表示非终结符, a为终结符或句子括号“#”,矩阵元素MA,a中的内容为存放着一条关于A的产生式,表明当用非终结符A向下推导时,面临输入符号a时,应采取的候选产生式,若无产生式,元素内容转向出错处理的信息。预测分析程序的工作
21、过程图中符号说明如下:#句子括号即输入串的括号S文法的开始符号X存放当前栈顶符号的工作单元a存放当前输入符号a的工作单元BEGIN 首先把#然后把文法开始符号推入栈;把第一个输入符号读进a; FLAG:=TRUE;WHILE FLAG DO BEGIN 把栈顶符号上托出去并放在中; IF X Vt THEN IF X=a THEN 把下一个输入符号读进a ELSE ERROR ELSE IF X=# THEN IF X=a THEN FLAG:=FALSE ELSE ERROR ELSE IF X,a=X X1X2.XK THEN 把XK,X K-1,.,X1一一推进栈 ELSEERROR E
22、ND OF WHILE;STOP/*分析成功,过程完毕*END分析算法 预测分析表构造算法1.对文法G的每个产生式 ,每个终结符或“#”用a表示; 若aSELECT( ),把 加至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 (2) E +TE (3) E (4) T FT
23、 (5) T *FT (6) T (7) F (E) (8) F a 1.可推出的非终结符表为:EETTF否是否是否2.各非终结符的FIRST集合如下:FIRST(E)=(,aFIRST(E)=+, FIRST(T)=(,aFIRST(T)=*, FIRST(F)=(,a3.各非终结符的集合如下:FOLLOW (E)=(, #FOLLOW(E)=), #FOLLOW(T)=+,), #FOLLOW (T)=+,), # FOLLOW (F)=*,+,),# SELECT( E TE)=(,a SELECT( E +TE)=+SELECT( E )= ) , # SELECT(T FT )=(,a SELECT(T *FT )=* SELECT(T )= +,) ,#SELECT(F (E) )=( SELECT(F a )=a a + * ( ) # E TETE E+TE T FT FT T *FT F a (E) 分析输入串#a+a#栈内容 栈顶符号 当前输入 余留串 MX,b 1 #E E a +a# E TE2 #ET T a +a# T FT3 #ETF F a +a# F a4 #ETa a a +a#5 # ET T + a# T 6 #E E + a# E +TE
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1