1.73k likes | 1.86k Vues
第五章. 语法分析 —— 自下而上分析. 5.1 自下而上分析基本问题. 所谓 自下而上分析法 就是从输入串开始,逐步进行 “ 归约 ” ,直至归约到文法的开始符号;或者说从语法树的末端开始,步步向上 “ 归约 ” ,直到根结。. 5.1.1 归约 实现思想 从输入符号串开始,从左到右进行扫描,将输入符号逐个移入一个栈中,边移入边分析,一旦栈顶符号串形成某个产生式的右部时,就用该产生式的左部非终结符代替,称为 归约 。重复这一过程,直到归约到栈中只剩下文法的开始符号时,则分析成功, 称为 “ 移进 - 归约 ” 方法 。. 例: G[S]: S→aAcBe
E N D
第五章 语法分析 ——自下而上分析
5.1 自下而上分析基本问题 所谓自下而上分析法就是从输入串开始,逐步进行“归约”,直至归约到文法的开始符号;或者说从语法树的末端开始,步步向上“归约”,直到根结。 5.1.1 归约 • 实现思想 从输入符号串开始,从左到右进行扫描,将输入符号逐个移入一个栈中,边移入边分析,一旦栈顶符号串形成某个产生式的右部时,就用该产生式的左部非终结符代替,称为归约。重复这一过程,直到归约到栈中只剩下文法的开始符号时,则分析成功, 称为“移进-归约”方法。
例:G[S]: S→aAcBe A→b A→Ab B→d 输入串为abbcde,判断是否归约到S? 设立一个符号栈,统一符号“#”作为待分析的符号串的左右分界符。 作为初始状态,先将符号串的分界符推进符号栈,作为栈底符号。
例:G[S]: S→aAcBe A→b A→Ab B→d 步骤 符号栈 输入符号串 动作 1 # abbcde# 准备.初始化 2 #a bbcde# 移进 3 #ab bcde# 移进 4 #aA bcde# 归约(A→b) 5 #aAb cde# 移进 6 #aA cde# 归约(A→Ab) 7 #aAc de# 移进 8 #aAcd e# 移进 9 #aAcB e# 归约(B→d) 10 #aAcBe # 移进 11 #S # 归约(S→aAcBe) 12 #S # 成功
步骤 符号栈 输入符号串 动作 1 # abbcde# 准备.初始化 2 #a bbcde# 移进 3 #ab bcde# 移进 4 #aA bcde# 归约(A→b) 5 #aAb cde# 移进 6 #aAA cde# 归约(A→b) 7 #aAAc de# 移进 8 #aAAcd e# 移进 9 #aAAcB e# 归约(B→d) 10 #aAAcBe # 移进 例:G[S]: S→aAcBe A→b A→Ab B→d 自下而上分析的中心问题是: 怎样判断栈顶的符号串的可归约性,以及如何归约?
S A c e a B A b b d 例:G[S]: S→aAcBe A→b A→Ab B→d S 语法分析树 aAcBe aAcde aAbcde abbcde • 从语法树的角度看:从语法树的树叶开始,逐步向上归约构造分析树,直到形成根结。是最右推导的逆过程。
5.1.2 规范归约简述 掌握短语和直接短语和句柄三个重要概念 令G是一个文法,S是文法的开始符号,假定是文法G的一个句型,如果有: S*A 且 A + 则称是句型相对于非终结符A的短语。特别是,如果有 A 则称是句型相对于规则A 的直接短语,一个句型的最左直接短语称为该句型的句柄。 注意:短语的两个条件是:S*A 且 A +
EE+T T+T T*F+T F*F+T i*F+T i*i+F i*i+i 例:文法G: E T|E+T T F|T*F F i | (E) (5.2) 的一个句型i1*i2+i3。 分析:∵E*F* i2+i3且Fi1,则称i1是句型i1*i2+i3的相对于非终结符F的短语,也是相对于规则F→i的直接短语。 又∵E * i1*F+i3且F i2,则i2是句型i1*i2+i3的相对于F的短语,也是相对于规则F→i的直接短语, 同样地,E*i1*i2+F且Fi3,则i3也是句型i1*i2+i3的相对于F的短语,也是相对于规则F→i的直接短语。
∵E * T*i2+i3,且T+i1,则i1是句型i1*i2+i3的相对于T的短语。 ∵E *i1*i2+T 且T +i3,则i3是句型i1*i2+i3的相对于T的短语。 ∵E *T+i3且T +i1*i2,则i1*i2是句型i1*i2+i3的相对于T的短语。 ∵E *E+i3且E +i1*i2,则i1*i2是句型i1*i2+i3的相对于E的短语。 ∵E *E 且E +i1*i2+i3,则i1*i2+i3是句型i1*i2+i3相对于E的短语。 即i1,i2,i3,i1*i2和i1*i2+i3都是句型i1*i2+i3的短语,而且i1,i2,i3均为直接短语,其中i1是最左直接短语,即句柄。
尽管有E +i2+i3,但是 i2+i3并不是i1*i2+i3句型的一个短语,因为不存在从E(文法开始符)到i1*E的推导。 注意:短语的两个条件是:S*A 且 A +
例:设文法G: S(T)|a|ε TS|T,S 找出句型(a,(T),(T,S))所有的直接短语。 分析: ∵S+(S,(T),(T,S)),Sa ∴a是该句型相对于S的直接短语。 ∵S+(a,S,(T,S)),S(T) ∴(T)是该句型相对于S的直接短语。 ∵S+(a,(T),(T)),TT,S ∴T,S是该句型相对于T的直接短语。 其中a是该句型的句柄。
语法树的子树是由该树的某个结点(称为子树的根)及其所有分枝构成的部分树称为原树的一颗子树。语法树的子树是由该树的某个结点(称为子树的根)及其所有分枝构成的部分树称为原树的一颗子树。 • 语法树的简单子树是只有单层分枝的子树——这颗子树只有且必须有父子两代,没有第三代,由此,引出下述结论: • 每个句型(句子)都对应一颗语法树; • 每颗语法树的端末结点自左至右排列构成一个句型(句子); • 每颗子树的端末结自左至右排列构成一短语; • 每颗简单子树的端末结自左至右排列构成一直接短语; • 最左简单子树的端末结自左至右排列构成一句柄。 从句型的语法树上很容易找出句型的短语和直接短语。
E E + T T F T * F i F i i E T|E+T T F|T*F F i | (E) 例:i*i+i 的短语、直接短语和句柄 短语: i1,i2,i3,i1*i2和i1*i2+i3 直接短语:i1,i2,i3 句柄:i1
S ( ) T T S , S S ( T ) , T ( T ) T S , a 例:句型= (a,(T),(T,S))的语法树如右图所示。短语是: ① (a,(T),(T,S)) ② a,(T),(T,S) ③ a,(T) ④ (T,S) ⑤ a ⑥ (T) ⑦ T,S
S ( ) T T S , S S ( T ) , T ( T ) T S , a • 句型的语法树有3棵简单子树。由这3棵简单子树的叶子结点组成的符号串,则是句型的3个直接短语: ① a ② (T) ③ T,S • 句型的语法树的最左简单子树的叶子结点a便是句型的句柄。
E E + T F E + T i T * F ET | E+T TF | T*F Fi | (E) 例:文法(5.2)的另一个句型E+T*F+i , 其短语、直接短语、句柄分别是? 解:EE+T E+T+T E+T*F+T E+T*F+F E+T*F+i 短语有:i, T * F, E+T * F, E + T * F + i 直接短语有: i, T * F 句柄是:T * F
例:文法: E→E+T|T T→T*F|F F→id 句型:id1+id2*id3, 分析树: 短语: id1+id2*id3 (E1) id2*id3 (T1) id1 (E2, T2, F1) id2 (T3, F3) id3 (F2) 直接短语: id1 (F1) id2 (F3) id3 (F2) 句柄: id1 (F1) ①短语:以非终结符为根子树中所有从左到右排列的叶子; ②直接短语:只有父子关系的树中所有从左到右排列的叶子(树高为2); ③句柄:最左边父子关系树中所有从左到右排列的叶子(句柄是唯一的)。
问题:id1+id2是句型id1+id2*id3的短语吗? 答案:不是。 ①没有一个E的子树,它的全部叶子是id1+id2;或者 ②找不到某个E,使得 E*E*id3, E +id1+id2
假定是文法G的一个句子,称序列 n ,n-1 , n-2, …, 0 是的一个规范归约,如果此序列满足: (1) n = ; (2) 0为文法的开始符,即 0 =S; (3)对于任何的i, 0<i≤n, i-1是从i经把句柄替换为相应产生式的左部符号而得到的。 容易看到,规范归约是关于的一个最右推导的逆过程。因此规范归约也称最左归约。 在形式语言中,最右推导常被称为规范推导。由规范推导所得的句型称为规范句型。如果文法G是无二义的,那么规范推导的逆过程必是规范归约。 • 一个规范句型的句柄的右边只包含终结符号。
S A c e a B A b b d 修剪语法树 Ab是句型aAbcde的句柄 d是句型aAcde的句柄 b是句型abbcde的句柄
5.1.3 符号栈的使用与语法树的表示 例:对于文法(5.2)输入串i1*i2+i3 的分析(规范归约)步骤可表示如下: 步骤 符号栈输入串动作 0 # i1*i2+i3# 预备 • #i1 *i2+i3# 移进i1 • #F *i2+i3# 归约,Fi • #T *i2+i3 # 归约,T F • #T* i2+i3# 移进 • #T*i2 +i3# 移进 • #T*F +i3# 归约,F i • #T +i3# 归约,T T*F • #E +i3# 归约,E T • #E+ i3# 移进 • #E+i3 # 移进 • #E+F # 归约, F i • #E+T # 归约, T F • #E # 归约,E E+T • #E # 接受
四类操作(action) • 移进(shift)-将当前输入符号移入栈顶top • 归约(reduce)-当“句柄”出现在栈顶(从栈中某处到栈顶top),则将“句柄”从栈顶弹出,并将相应产生式左部非终结符置入栈顶top。 • 接受(accept)-分析成功! • 报错(error)-出现语法错误,调错误恢复例程
分析技术的关键--句柄的识别 什么是句柄(handle)? 简单讲,句柄是一个产生式的右部;自下而上分析(移进-归约分析)过程,其实就是发现句柄并将句柄(产生式右部)替换成相应左部非终结符的过程。 如何寻找或确定一个句型的句柄,在后续章节介绍。
小结: 重要概念 自下而上分析法——移进-归约法 短语、直接短语、句柄 规范归约
5.2 算符优先分析 • 算符优先分析法的思想源于表达式的分析,即利用相邻终结符号之间的关系来寻找可归约串。 • 将句型中的终结符号当作“算符”,借助于算符之间的优先关系确定句柄。 • 显然,在一个符号串中,任意两个相邻终结符号a和b之间,只可能存在以下三种优先关系:(1) a, b优先性相同,记作a b。(2) a优先性高于b, 记作a b。(3) a优先性低于b ,记作a b。 如果以上三种关系中的任意两种都不会同时成立,则可以根据终结符号之间的关系进行语法分析。
5.2.1 算符优先文法及优先表的构造 一个文法,如果它的任何产生式的右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部: …QR… 则称该文法为算符文法。 在后面的定义中,a、b代表任意终结符;P、Q、R代表任意非终结符;‘…’代表有终结符和非终结符组成的任意序列,包括空字。
假定G是一个不含--产生式的算符文法。对于任何一对终结符a、b,我们说:假定G是一个不含--产生式的算符文法。对于任何一对终结符a、b,我们说: (1) a b 当且仅当文法G中含有形如P …ab…或P …aQb…的产生式; (2) a b当且仅当G中含有形如P …aR…的产生式,而 R+b…或R +Qb…; (3) ab当且仅当G中含有形如P …Rb…的产生式,而R+…a或R +…aQ; 如果一个文法G中的任何终结符对(a, b )至多只满足下述三关系之一: a b, a b, a b 则称G是一个算符优先文法。 算符优先文法是无二义性的
以上三种关系也可由语法树来说明 注:δ为ε或Q
a b 不一定 b a • 允许a b, b a; • 不允许 a b, a b, a b中任两个 同时存在。 • < • • • > > > 注意:3种关系与数学中的=、>、<不同。它们是有序的。 例如:E→E+E|E*E|(E)|i 不是算符优先文法。 +、* 的优先关系不唯一,所以该表达式的文法仅是算符文法而不是算符优先文法
通过检查G的每个产生式的每个候选式,可以找出满足a b的终结符对。 为了找出所有满足关系 和 的终结符对,需要对G的每个非终结符P 构造两个集合FIRSTVT(P)和LASTVT(P): FIRSTVT(P)={a | P+a…或P +Qa…,aVT而 Q VN } LASTVT(P)={a | P+…a或P +…aQ,aVT而 Q VN } 有了这两个集合后,就可以通过检查每个产生式的候选式确定满足关系 和 的所有终结符对。
例如:假定有个产生式的一个候选式为 …aP… 那末,对任何bFIRSTVT(P), 有a b。 假定有产生式的一个候选式为 …Pb… 那末,对任何aLASTVT(P), 有a b. 构造集合FIRSTVT(P)的算法。依据下面两条规则: (1)若有产生式Pa…或P Qa…,则aFIRSTVT(P) (2)若aFIRSTVT(Q),且有产生式P Q… 则aFIRSTVT(P) 说明:因为Qa…或QWa…,所以有PQ…a…或 PQ…Wa…
构造LASTVT(P)的算法 (1)若有产生式P … a或P …aQ,则aLASTVT(P) (2)若aLASTVT(Q),且有产生式P … Q 则aLASTVT(P)
例:文法G: Sa|^|(T) TS,T|S 计算各非终结符的FIRSTVT和LASTVT. 解:FIRSTVT(S)={a^(} Pa… LASTVT(S)={a^)} P … a FIRSTVT(T)={,a^(} PQa…规则2 LASTVT(T)={,a^)} P …aQ 规则2 构造集合FIRSTVT(P)的算法。依据下面两条规则: (1)若有产生式Pa…或P Qa…,则aFIRSTVT(P) (2)若aFIRSTVT(Q),且有产生式P Q…, 则aFIRSTVT(P) 构造LASTVT(P)的算法 (1)若有产生式P … a或P …aQ,则aLASTVT(P) (2)若aLASTVT(Q),且有产生式P … Q, 则aLASTVT(P)
说明:E′→#E#为对原文法的扩充,‘#’表示句子括号,说明:E′→#E#为对原文法的扩充,‘#’表示句子括号, 所描述的语言和扩充前完全相同。为了分析过程的确切,把'#'号也作为终结符对待。 例:表达式文法为:(0) E′→#E#(1) E→E+T(2) E→T(3) T→T*F(4) T→F(5) F→P↑F|P(6) P→(E)(7) P→i计算每个非终结符的FIRSTVT集合和LASTVT集合。 解:FIRSTVT(E′)={#}FIRSTVT(E)={+,*,↑,(,i}FIRSTVT(T)={*,↑,(,i}FIRSTVT(F)={↑,(,i}FIRSTVT(P)={(,i}LASTVT(E′)={#}LASTVT(E)={+,*,↑,),i}LASTVT(T)={*,↑,),i}LASTVT(F)={↑,),i}LASTVT(P)={),i}
• < • > P…ab… P…aQb… 在有了每个非终结符P 的FISTVT(P)和LASTVT(P)之后就能够构造文法G的优先表。其算法如下: FOR 每一条产生式PX1X2…Xn FOR i:=1 TO n-1 DO BEGIN IF Xi和 Xi+1均为终结符THEN 置 Xi Xi+1 IF i<=n-2且Xi和Xi+2都为终结符,而Xi+1为非终结符,则置Xi Xi+2 IF Xi为终结符而Xi+1为非终结符 THEN FOR FIRSTVT(Xi+1)中的每个a DO 置 Xi a IF Xi为非终结符而Xi+1为终结符THEN FOR LASTVT(Xi)中的每个a DO 置 a Xi+1 END P…aR.. R+b… R+Qb… P…Rb.. R+…a R+…aQ
构造优先关系表T的方法: • • < < • • > > a) 关系: 可直接查看产生式的右部,对如下形式的产生式A→…ab… , A→…aBb… 有T[a,b]= b) 关系: 对如下形式的产生式A→…aB… 中,对每一 b∈FIRSTVT(B), 有T[a,b]= c) 关系: 对如下形式的产生式A→…Bb… 中,对每一a∈LASTVT(B), 有T[a,b]=
FIRSTVT(E′)={#}FIRSTVT(E)={+,*,↑,(,i}FIRSTVT(T)={*,↑,(,i}FIRSTVT(F)={↑,(,i}FIRSTVT(P)={(,i}LASTVT(E′)={#}LASTVT(E)={+,*,↑,),i}LASTVT(T)={*,↑,),i}LASTVT(F)={↑,),i}LASTVT(P)={),i}FIRSTVT(E′)={#}FIRSTVT(E)={+,*,↑,(,i}FIRSTVT(T)={*,↑,(,i}FIRSTVT(F)={↑,(,i}FIRSTVT(P)={(,i}LASTVT(E′)={#}LASTVT(E)={+,*,↑,),i}LASTVT(T)={*,↑,),i}LASTVT(F)={↑,),i}LASTVT(P)={),i} 例:表达式文法为:(0) E′→#E#(1) E→E+T(2) E→T(3) T→T*F(4) T→F(5) F→P↑F|P(6) P→(E)(7) P→i构造算符优先表 a) 关系由产生式(0) E′→#E# 和(6) P→(E)可得‘#’‘#’,‘(’')'成立。
• • • • • • < < < < < < • • • • • • > > > > > > c) 关系:对表达式文法中非终结符在前终结符在后的相邻符号对有:E# 则有:LASTVT(E) #E+ 则有:LASTVT(E) +T* 则有:LASTVT(T) *P↑ 则有:LASTVT(P) ↑E) 则有:LASTVT(E) ) b) 关系:对所给表达式文法 中终结符在前非终结符在后的 相邻符号对有: #E 则有:# FIRSTVT( E) +T 则有:+ FIRSTVT(T) *F 则有:* FIRSTVT(F) ↑F 则有:↑ FIRSTVT(F) (E 则有:( FIRSTVT(E) (0) E′→#E#(1) E→E+T(2) E→T(3) T→T*F(4) T→F(5) F→P↑F|P(6) P→(E)(7) P→i
LASTVT(E) #LASTVT(E) +LASTVT(T) *LASTVT(P) ↑LASTVT(E) ) # FIRSTVT( E) + FIRSTVT(T) * FIRSTVT(F) ↑ FIRSTVT(F) ( FIRSTVT(E) ‘#’‘#’,‘(’')' • • • • • < < < < < • • • • • > > > > > 优先表 FIRSTVT(E’)={#}FIRSTVT(E)={+,*,↑,(,i}FIRSTVT(T)={*,↑,(,i}FIRSTVT(F)={↑,(,i}FIRSTVT(P)={(,i}LASTVT(E′)={#}LASTVT(E)={+,*,↑,),i}LASTVT(T)={*,↑,),i}LASTVT(F)={↑,),i}LASTVT(P)={),i}
• < • > FIRSTVT(S)={a^(} LASTVT(S)={a^)} FIRSTVT(T)={,a^(} 例:文法G: Sa|^|(T) TS,T|S 构造文法G的优先表。 LASTVT(T)={,a^)} 解:1) S (T) 得() 2) S (T) ,得(低于FIRSTVT(T)中的每一个 TS,T,得,低于FIRSTVT(T)中的每一个 3) S (T),得 LASTVT(T)中的每一个高于) TS,T,得LASTVT(S)中的每一个高于, 加入#S#
例:构造下面文法的算符优先表。 S if Eb then E else E E E+T|T T T*F|F F i Eb b 解:1)求各非终结符的首终结符集和尾终结符集。为了考虑语句的开始和结束符号“#”,对文法拓广,加一个产生式S’#S# FIRSTVT(S)={if} LASTVT(S)={else,+,*,i} FIRSTVT(E)={+,*,i} LASTVT(E)={+,*,i} FIRSTVT(T)={*,i} LASTVT(T)={*,i} FIRSTVT(F)={i} LASTVT(F)={i} FIRSTVT(Eb )={b} LASTVT(Eb)={b} 2)填写算符优先表
右左 if then else + * i b # if then else + * i b #
5.2.2 算符优先分析算法 • • < < • • > > 即:aj-1aj ... ai-1aiai+1 • • • 所谓素短语是指这样的一个短语,它至少含有一个终结符,并且除它自身外,不再含有更小的素短语。 所谓最左素短语,是指处于句型最左边的那个素短语。 把算符优先文法句型(括在两个#号之间)的一般形式写成: #N1a1N2a2…Nnan Nn+1# (5.4) 其中每个ai都是终结符,Ni是可有可无的非终结符。 一个算符优先文法G的任何句型(5.4)的最左素短语是满足如下条件的最左子串:Njaj…Nia iNi+1, a j-1 aj aj aj+1, … , a i-1 a i ai· a i+1
E E + T 包含其他 素短语 F E + T T不包含终结符 T是句柄 i T T * F 例: 文法G[E] EE+T|T T T*F|F F (E)|i 求句型T+T*F+i 的素短语 文法的语法树: 短语:T+T*F+i T+T*F T(最左) T*F i 只有T*F和i为素短语,其中T*F为最左素短语,而该句型句柄为T.
k=1;s[k]=‘#’; /* S为符号栈*/ repeat 将一个输入符号读入a中; IF S[k]VT THEN j=k ELSE j=k-1; While s[j] a { /*素短语归约可能做若干次*/ repeat q=s[j]; /*找素短语的头*/ if s[j-1]VT then j=j-1 else j=j-2 until s[j] Q; 将s[j+1]…s[k]归约为某个N;/*若找不到相应的产生式归约,则出错*/ k=j+1; s[k]=N } if s[j] a or s[j] a then { k=k+1;s[k]=a /*移进*/} else ERROR /*调出错处理程序*/ until a=‘#’ /*识别成功*/
例:根据下面文法及其算符优先表,按算符优先分析的算法分析语句if b then i else i#。 S if Eb then E else E E E+T|T T T*F|F F i Eb b 右左 if then else + * i b # if then else + * i b #
步骤 栈 关系* 输入串 动作 0 # if b then i else i # 1 #if b then i else i # 移进 2 # if b then i else i # 移进 3 #if N then i else i # 对b归约 4 #if N then i else i # 移进 5 #if N then i else i # 移进 6 #if N then N else i # 对i归约 7 #if N then N else i # 移进 8 #if N then N else i # 移进 9 #if N then N else N # 对i归约 10 #N # 归约 成功
例:文法G: Sa|^|(T) TS,T|S 给出句子((a,a),^)#的分析过程 文法G的优先表