230 likes | 343 Views
ay, a V T , yV * } ,. First(x)={a |x. 若 x. , 则 First(x). *. *. *. . . . a…, a V T } ,. First(x)={a |x. 第四章 自顶向下语法分析方法. 语法分析 是整个编译过程的核心部分,它完成的任务是: 按照文法从源程序单词串 ( 符号串 ) 中识别各类语法成分,判断所给出的单词串是否是给定文法的正确句子 ,并为语义分析和代码生成做准备。.
E N D
ay, aVT, yV*}, First(x)={a |x 若x , 则First(x). * * * a…, aVT}, First(x)={a |x 第四章 自顶向下语法分析方法 语法分析是整个编译过程的核心部分,它完成的任务是:按照文法从源程序单词串(符号串)中识别各类语法成分,判断所给出的单词串是否是给定文法的正确句子,并为语义分析和代码生成做准备。 例如:有如下文法G[E]:EE+T | TTT*F | FF(E) | i 则有:First(E+T)={(, i} First(T)={(, i} First(i*i)={i} 4.1 几个重要集合 一、首符号集: 设有文法G=(VT, VN, S, P)是上下文无关文法,则符号串x的首符号集合定义为:
…Ua…, aVT}, Follow(U)={a | S 若S …U, 则#Follow(U). * * * * * * * 因有E 因有E T E 因有E 因有E 因有E 因有E 因有E (E) T*T (T) E+T T+T 同理, * * 二、后继符号集: #是指输入串的括号,如#abcd# 设有文法G=(VT, VN, S, P)是上下文无关文法,UVN, 则非终结符号U的后继符号集定义为: 所以有:#Follow(E) 例如:有文法G[E]:EE+T | TTT*F | FF(E) | i 所以有:+Follow(E) 所以有:)Follow(E) 故,Follow(E)={#, +, ) } 所以有:#Follow(T) 所以有:+Follow(T) 所以有:*Follow(T) 所以有:)Follow(T) 故,Follow(T)={#, +, *, ) }
LL(1)文法: 如果一个文法满足以下条件: 1、文法不含左递归。 2、对文法中每一个非终结符A的各个产生式的候选首 符集两两不相交。 3、对文法中每一个非终结符A,若存在某个候选首 符集包含,则 First(A) Follow(A)= LL(1)中第一个L表明自左(Left)向右扫描输入串,第二个 L表明分析过程采用最左(Left)推导,括号中的1表明只需向右 看一个符号便可决定选择哪个产生式进行推导。
First(u) u Select(Uu) = * * First(u)Follow(U) u 二、可选集: 设有文法上下文无关文法G[S],并有产生式Uu, UVN, u V*, 则该产生式的可选集定义为: 由定义知: 例如:有文法G[S]:SaBc | bBBbB | d | Select(SaBc)=First(aBc )={ a } Select(SbB)=First(bB )={ b } Select(BbB)=First(bB )={ b } Select(Bd)=First(d)={ d } Select(B)=First()Follow(B) ={ } {c, #}={, c, #}
第四章 自顶向下语法分析方法 语法分析是整个编译过程的核心部分,它完成的任务是:按照文法从源程序单词串(符号串)中识别各类语法成分,判断所给出的单词串是否是给定文法的正确句子,并为语义分析和代码生成做准备。 4.1语法分析器的功能: p66
(1)据识别符号产生根结点S, 并让读指针指向输入串首符号c (2)据S的产生式发展语法树 S cad S cad (4)A有两个选择,选择第一个进行试探,发展语法树。 (3)用S的子结点(cAd)匹配输入串,首符号匹配,读指针向下移动 c A d S cad S cad c A d c A d a b 4.2 不确定的自顶向下分析 一、算法思想: 对于任一输入符号串,试用一切可能的办法从树根结点出发根据文法自上向下的为输入串建立一棵语法树。 二、举例:设有文法G[S]:(1) ScAd(2) Aab|a 给定输入串w=cad,试给出分析过程
(5)子树A的最左子结点与指针所指符号匹配,指针移动,与A的第二个结点匹配,失败!回溯。(5)子树A的最左子结点与指针所指符号匹配,指针移动,与A的第二个结点匹配,失败!回溯。 (6)回溯要把A的第一个选择所生长的子树销掉,并把分析指针恢复到进入A时的值。 S cad S cad c A d c A d (8)A的子结点与当前符号匹配,指针移动,S的第三结点d进入工作,匹配成功 (7)用A的第二个选择生成语法树 a b S cad S cad c A d c A d a a
三、对应最左推导: 以上为输入符号串建立语法树的过程,实际上也是一个建立最左推导序列的过程,显然有:ScAdcad,之所以使用最左推导,是因为我们对输入串是从左到右扫描的,只有使用最左推导,才能按扫描顺序去匹配输入串。 四、存在问题:p68 1.左递归问题:自顶向下分析方法,在匹配过程中,假若用到非终结符号U去匹配输入串,而U为左递归的(例如:UU…),那么为了用它的右部匹配输入串,又要用到非终结符号U,循环往复,没有终止。若文法存在间接递归,也有相同问题发生。 2.回溯问题:对某个非终结符,当有多条规则时,需采用逐个选择的方法,若不能匹配需要回溯,代价高,效率低。
S p A c A d c A d a 4.3 确定的自顶向下分析思想 文法特点: (1)每个产生式的右部都由终结符号开始;(2)两个产生式若左部相同,则其右部以不同的终结符号开始;(3)无空产生式U 一、算法思想: 对于任一输入符号串,从文法的识别符号出发,根据当前的输入符号,唯一的确定一个产生式,用产生式的右部的符号串替代相应的非终结符往下推导,或构造一棵语法树。若能推导出输入串或构造语法树成功则输入串是句子,否则不是。 对应最左推导: 二、举例:(1)文法G[S]:SpA |qB AcAd|a 输入串w=pccadd SpApcAdpccAddpccadd 方法:根据产生式右部的首符号选择产生式。
c c A A a S S A a p A b A S d (2)文法G[S]:SAp | Bq AcA | aBdB | b 输入串w=ccap 文法特点: (1)每个产生式的右部并非都由终结符号开始;(2)两个产生式若左部相同,则其右部以不同的终结符号或非终结符号开始,且首符号集不相交;(3)无空产生式U 对应最左推导: SApcApccApccap 例题(1)(2)(3)的共同特点: 1)每个非终结符号的两个产生式的可选集不相交;2)在每一步推导中,都可以根 据输入串的当前符号和产生式 的可选集唯一的确定一个产生 式去匹配。 方法:根据产生式右部的首符号选择产生式。 文法特点: (1)有空产生式U;(2)两个产生式若左部相同,则其对应的可选集不相交; (3)文法G[S]:SaA | d AbAS | 输入串w=abd 对应最左推导: SaAabASabSabd 方法:根据产生式的可选集选择产生式。
= Ф = Ф 4.4 LL(1)文法 一、定义: 上下文无关文法G是LL(1)文法的充要条件是对每个U∈VN,若有产生式U→u|v,u,v ∈V*,则有 : Select(Uu)Select(Uv)=Ф 二、“LL(1)”的含义: LL(1)中第一个L表明自左(Left)向右扫描输入串,第二个L表明分析过程采用最左(Left)推导,括号中的1表明只需向右看一个符号便可决定选择哪个产生式进行推导。 所以:G[S]是LL(1)文法。 重要结论:若能使用自顶向下 分析方法进行确定的分析,则 文法必须是LL(1)文法。 三、举例: Select(SaA)=First(aA)={a} Select(Sd)=First(d)={d} 对于前例文法G[S]:SaA | d AbAS | Select(AbAS)=First(bAS)={b} Select(A)=Follow(A)First() ={a,d,#} {}={a,d,#, }
4.5 非LL(1)文法转换为LL(1)文法 对某个语言来说其文法不一定是LL(1)文法,而非LL(1)文法将无法采用确定的自顶向下分析方法进行分析,但我们可以通过对文法进行等价变换,在有些情况下使其成为LL(1)文法。 一、提取左公共因子: 设文法中有Uxy|xw( UVN, x,y,wV*)形式的产生式,从而导致了: First(xy)First(xw)=First(x)Ф因而使: Select(Uxy) Select(Uxw) Ф 若在y,w,…,z中仍然有左公共因子,可以再次提取。注意,若有:Uxy|x则提取后:Ux(y|) 1.方法:若有产生式Uxy|xw|…|xz , 则提取左公共因子并用EBNF表示为: Ux(y|w|…|z) 再引入另一个非终结符号V,将产生式变为:UxVV y|w|…|z
2.举例: 设有产生式:S→if B then S1 else S2 | if B then S1 其中,S表示两种类型的条件语句。 提取公因子,改成: S→if B then S1 ( else S2 | ) 引入非终结符号R:S→if B then S1 R R→else S2 |ε 文法中,if , then, elseVT 3.说明: 文法提取左公共因子后,只能使相同左部的产生式右部的First集不相交,不能保证相同左部产生式的Select集不相交。 文法提取左公共因子后,若文法中无空产生式,且无左递归,则改写后的文法为LL(1)文法。 有些文法,不能在有限步骤内改写为无左公共因子的文法。
U(x|y|…|z|) U ’ 或改为右递归的形式: U ’ v U ’ | E→TE’E’→+TE’| T→FT’T’→*FT’| 或 或 二、消除左递归: 左递归文法的分析程序可能进入死循环,可以证明,左递归文法不可能是LL(1)文法。 1.消除直接左递归:若有产生式Ux|y|…|z|Uv, UVN, x,y,z,vV*, 则改写并用EBNF表示为: U(x|y|…|z|){v} 举例:设有文法G[E]E→E+T|TT→T*F|F F→(E)|i E→T{+T} E→T|E+T T→F|T*F T→F{*F}
将(3)(4)带入(1) 若文法中没有回路(A A), 则: 2.消除间接左递归:先将间接左递归变为直接左递归,再按消除直接左递归的方法进行。 举例:设有文法G[A](1)A→Bc(2)A→d(3)B→aA(4)B→Ab A→aAc|d|Abc 直接左递归 A→aAcA→Abc A→d A→(aAc|d){bc} 3.消除文法中全部左递归的算法: (1)把文法中的非终结符,按某种顺序进行排列 (顺序任意),如,A1, A2, …, An ;
消除一切左递归的方法:(1)把文法中的非终结符,按某种顺序进行排列 (顺序任意),如,A1, A2, …, An ; (2)对每个非终结符号用排在它前面的其它非终结符号的产生式表示出来,并消除产生式中的直接左递归。 for i:=1 to n do begin for j:=1 to i-1 do begin 把行如Pi→Pjγ的产生式改成Pi→δ1γ|δ2γ|…|δkγ 其中Pj→δ1|δ2|…|δk是关于Pj的所有产生式。 end 消除关于Pi产生式的直接左递归 end (3)化简由(2)所得文法,即去掉多余产生式。
Q→Sab|ab|b R→Sa|a 所以文法成为: 注意:对非终结符号的排序是任意的(但要保证识别符号不变),不同的排序最后所得文法得形式可能不同,但它们是等价的。 举例:有文法G[S]: S→Qc|c Q→Rb|b R→Sa|a 该文法无直接左递归,但,SQcRbcSabc,故有间接左递归,所以文法G[S]为左递归文法。 (1)对非终结符号排序:R, Q, S (2)逐个消除直接左递归: R: R→Sa|a 无直接左递归 Q: 将R带入Q中:Q→Sab|ab|b 无直接左递归 S: 将R,Q带入S中:S→Sabc|abc|bc|c 消除S的直接左递归:S→(abc|bc|c) S’ S’→abcS’| (3)去掉多余产生式: S→(abc|bc|c) S’ S’→abcS’|
4.4 确定的自顶向下分析方法举例 一、递归子程序法 递归子程序法是比较简单直观易于构造的一种语法分析方法,其方法思想是对源程序中每个语法成分编制一个处理子程序,即对每个非终结符号编制一个递归过程,每个子程序的功能是识别由该非终结符号推出的串。它要求文法满足LL(1)文法,以便当某个非终结符号有多条产生式时,可以根据当前的输入符号唯一地确定选择某个产生式进行匹配。 文法G[E]: E→TE’ E’→+TE’|ε T→FT’ T’→*FT’|ε F→(E)|i
4.5 预测分析程序——LL(1)分析器: 预测分析程序也是一种自顶向下分析程序,预测分析要求文法是LL(1)文法,它由分析栈、分析表和分析程序三部分组成,其中分析表的构成与文法有关。下面举例说明分析器的构造过程: 设有文法G[E]:E→E+T|TT→T*F|FF→(E)|i (2)找出能推出ε的非终结符号:E’, T’ (3)求非终结符号的First集:p78First(E)={(,i}First(E’)={+,ε}First(T)={(,i}First(T’)={*,ε}First(F)={(,i} 1.判断是否LL(1)文法 (1)消除左递归:E→TE’ E’→+TE’|ε T→FT’ T’→*FT’|ε F→(E)|i
(4)求非终结符号的Follow集:详见p79Follow(E)={),#}Follow(E’)={),#}Follow(T)={+,),#}Follow(T’)={+,),#}Follow(F)={*,+,),#}(4)求非终结符号的Follow集:详见p79Follow(E)={),#}Follow(E’)={),#}Follow(T)={+,),#}Follow(T’)={+,),#}Follow(F)={*,+,),#} 文法是LL(1)文法。
i + * ( ) # E E→TE’ E→TE’ E’ E’→+TE’ E’→ε E’→ε T T→FT’ T→FT’ T’ T’→ε T’→*FT’ T’→ε T’→ε F F→i F→(E) 2.构造预测分析表 定义:预测分析表与文法有关,它说明当某个非终结符号U向下推导时,面临输入符号a时,所应选用的产生式。 (2)表示:预测分析表可用一矩阵M表示,矩阵的行表示非终结符号,矩阵的列表示输入符号或#,矩阵的元素M[U,a]表示对非终结符号,当面临输入符号a时,它向下推导所应采取的产生式。 当元素内无产生式时,表明用非终结符号U向下推导时,遇到了不该出现的输入符号。所以元素内容可以存放转向出错处理的错误信息. (3)构造方法:对每个终结符号a(包括#)若 aSelect(U→u),则把产生式U→u放入预测分析表M[U,a]中。(详见p79下) 例,对于上例中的文法G[E],预测分析表为:
#为输入串括号,S为文法开始符号 3. 分析过程: X用于保存分析栈栈顶元素 为什么逆序? a当前输入符号 什么情况出错? 分析栈到栈底 输入串到右括号#
i + * ( ) # E TE’ TE’ E’ +TE’ ε ε T FT’ FT’ T’ ε *FT’ ε ε F i (E) 举例:分析输入串i+i是否为文法G[E](上例)的句子。 首先为输入串i+i加上括号,即被分析的串变为#i+i#,分析过程如下: 步骤 分析栈 当前输入a 剩余输入串 所用产生式 X=E 1 #E i i+i# ETE’ 2 #E’T i i+i# TFT’ X=i=a 匹配 3 #E’T’F i i+i# Fi 4 #E’T’i i i+i# 5 #E’T’ + +i# T’ X=+=a 匹配 #E’ + E’+TE’ 6 +i# 7 #E’T+ + +i# 8 #E’T TFT’ i i# X=i=a 匹配 #E’T’F i# 9 i Fi 10 #E’T’i i i# 11 #E’T’ # # T’ #E’ # # E’ 12 X=a=# 13 # # # 分析成功