470 likes | 581 Views
第五章 语法分析 —— 自下而上分析. 所谓自下而上分析法就是从输入串开始,逐步进行 “ 归约 ” ,直到归约到该文法的开始符号为止。或者说,从语法树的末端开始,步步向上 “ 归约 ” ,直到根结。. 5.1 自下而上分析基本问题. 5.1.1 规约 自下而上分析法实质上是一种 “ 移进 / 归约 ” 法。即用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里;当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。.
E N D
第五章 语法分析——自下而上分析 • 所谓自下而上分析法就是从输入串开始,逐步进行“归约”,直到归约到该文法的开始符号为止。或者说,从语法树的末端开始,步步向上“归约”,直到根结。
5.1自下而上分析基本问题 • 5.1.1规约 • 自下而上分析法实质上是一种“移进/归约”法。即用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里;当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。
例: G[S],其产生式如下: ①S→aAcBe ②A→b ③A→Ab ④B→d对输入串abbcde#进行分析。解:利用最右推导得:S => aAcBe => aAcde => aAbcde => abbcde分析过程: abbcde → aAbcde → aAcde → aAcBe → S
步骤: 动作: • 我们希望把输入串abbcde规约到S。假定使用下面的规约过程:首先把 a进栈,然后把b进栈,因为A b是一条规则,于是把栈顶的b规约成A;再让第二个b进栈,这时栈的最顶端的两个符号Ab,因A Ab是一条规则,于是又把栈顶的Ab规约为A。此时栈里只有两个符号aA了。如此反复整个“移进-规约”过程共10步,每一步符号栈的变化情形如上图所示。 • 在上图中共进行了4次规约。没实现一步规约都是把栈顶的一串符号用某个产生式的左部符号来代替。后面我们权且把栈顶上的这样一串符号称为“可规约串”,在第5)步中,如果用规则2)则无法得到最后结果,因此需要精确定义“可规约串”,这是自下而上分析的关键问题。
S→aAcBe A→b A→Ab B→d • (1)最右推导过程见下图 • (2)最左归约过程见下图
语法分析树的生成 S S → a A c B e a b b c d e A A → A b A B B → d A → b
自下而上分析的中心问题是:怎样判断栈顶的符号串的可规约性,以及如何规约。这是5.2节(算符优先分析)和5.3节(LR分析法)将讨论的问题。各种不同的自下而上分析法的一个共同特点是,边输入单词符号(移进符号栈),边规约。也就是在从左到右移进输入串的过程中,一旦发现栈顶呈现可规约串就立即进行规约。自下而上分析的中心问题是:怎样判断栈顶的符号串的可规约性,以及如何规约。这是5.2节(算符优先分析)和5.3节(LR分析法)将讨论的问题。各种不同的自下而上分析法的一个共同特点是,边输入单词符号(移进符号栈),边规约。也就是在从左到右移进输入串的过程中,一旦发现栈顶呈现可规约串就立即进行规约。
5.1.2 规范归约简述 句型:假定G是一个文法,S是它的开始符号。如果S =>α,则称α为句型 * • 令G是一个文法,S是文法的开始符号,假定: (1).αβδ是文法G的一个句型; (2).如果有 S =*> αAδ 且 A =+> β,则称β是句型αβδ相对于非终结符A的短语;特别是,如果有A=>β,则称β是句型αβδ相对于规则A→ β的直接短语。一个句型的最左直接短语称为该句型的句柄。 分析:P85的例5.1和5.2
语法树对应的短语,直接短语和句柄 • 由A=+>β可以看出,β是语法树生长过程中由A结点开始向下生长出来的全部树叶,缺少一片树叶都不满足A=+>β.也即,这些树叶由左至右排列可以向上归结到某个结点(比如说A),并且由该结点向下生长出来的全部树叶也恰好是刚归结的这些树叶,则这个树叶序列就是该结点的短语。 • 如果这种向上归结只需一层(即树叶与该结点为父子关系),则为直接短语。 • 句柄是语法树中最左那棵子树的树叶的自左至右排列,且这棵子树只有父子两代。
规范归约 • 规范归约是规范推导(最右推导)的逆过程,因此规范归约也称最左归约. • 如果文法G是无二义性的,则规范推导的逆过程必定是规范归约. • 我们用句柄来刻画移进-归约过程的可归约串。
移进归约分析器 输入缓冲区 id * id # + E # 产生式序列 移进归约 控制程序 栈 栈内容 + 输入缓冲区内容 = # 句型 #
分析器的四种动作 • 1) 移进:将下一输入符号移入栈 • 2) 归约:用产生式左侧的非终结符替换栈顶的句柄 • 3) 接受:分析成功 • 4) 出错:出错处理 各种自底向上分析方法的控制方法不同
例5-3:i1*i2+i3 的分析 E →T|E+T T →F|T*F F →i|(E) 动作 栈 输入缓冲区 1) # i1*i2+i3 # 2) 移进 #i1 *i2+i3 # 3) 归约 F→i #F *i2+i3 # 4) 归约 T→F #T *i2+i3 # 5) 移进 #T* i2+i3 # 6) 移进 #T*i2 +i3# 7) 归约 F→i #T*F +i3# 8) 归约 T→T*F #T +i3# 9) 归约 E→T #E +i3# 10) 移进 #E+ i3# 11) 移进 #E+i3 # 12) 归约 F→i #E+F # 13) 归约 T→F #E+T # 14) 归约 E→E+T #E # 15) 接受 #E #
产生式序列表示语法分析树 • E → id • E → id • E → id • E → E * E • E → E + E E E E E E id + id * id
5.2算符优先分析 • 算符优先分析过程是自上而下的归约过程,但算符优先分析法不是一种规范归约。在整个归约过程中,起决定作用的是相继两个终结符的优先关系。因此,所谓算符优先分析法就是定义算符之间的某种优先关系。借助这种关系可寻找“可归约串”来进行归约。 • 算符优先关系的定义 (终结符之间) • a ≮ b a 的优先级低于 b • a ≡ b a 的优先级等于 b • a ≯ b a 的优先级高于 b • 注意:1. 算术关系“<”,“≡”和“>”与优先关系具有十分不同的性质。例如,a<·b并不一定意味着b·>a,例如:+<·(,(<· +。 优先关系特点-无交换性、无对称性、无自反性。
5.2.1算符优先文法及优先表构造 • 如果文法 G 中不存在具有相邻非终结符的产生式(如…QR…),则称为算符文法。 • 如果无ε产生式的算符文法 G中,且任意两个终结符之间至多有一种优先关系,则称为算符优先文法。 • 算符优先分析仅适用于算符优先文法。
算符优先文法的定义 • 假定G是一个不含ε产生式的算符文法, 对任何一对终结符a,b: • a ≡ b,当且仅当G中含有形如P→…ab…或P→…aQb…的产生式. • a ≮ b,当且仅当G中含有形如P→…aR…的产生式,而R=>b… 或R=>Qb… . • a ≯ b,当且仅当G中含有形如P→…Rb…的产生式,而R=>…a 或R=>…aQ .
算符优先关系表的构造 为了找出所有满足关系≯和≮的终结符对,首先需要对G的每个非终结符P构造两个集合FIRSTVT(P) 和LASTVT(P): FIRSTVT(P)={a| P =+>a… 或P =+>Qa…,a∈VT 而Q ∈VN} LASTVT(P)={a| P =+>…a 或P =+>…aQ, a∈VT 而Q ∈VN}
FIRSTVT集和LASTVT集的构造 由此, 得FIRSTVT集构造方法: (1)若有产生式P→a…或P→Qa…,则a∈ FIRSTVT(P) (2)若a∈ FIRSTVT(Q),且产生式P→Q…,则a∈ FIRSTVT(P) 得LASTVT集构造方法: (1)若有产生式P→…a或P→…aQ,则a∈ LASTVT(P) (2)若a∈ LASTVT(Q),且产生式P→…Q,则a∈ LASTVT(P)
算符优先文法G构造优先关系表的方法 (1)对形如P→…ab…或P→…aQb…的产生式, 有a ≡ b (2)对形如P→…aR…的产生式,有b ∈ FIRSTVT(R) 则 a ≮ b (3)对形如P→…Rb…的产生式,有a ∈ LASTVT(R) 则 a ≯ b 此外,若将语句符号#作为终结符对待,并设S是文法的开始符号,则有#≡#,# ≮ FIRSTVT(S), LASTVT(S) ≯ #
优先关系构造算法:for(每个产生式A→X1X2…Xn) do for(i=1;i<=n-1;i++){if(Xi和Xi+1均为终结符) 置Xi ≡ Xi+1 ;if(i≤n-2且Xi和Xi+2均为终结符,但Xi+1为非终结符) 置Xi ≡ Xi+1 ;if(Xi为终结符,Xi+1为非终结符)for(FIRSTVT(Xi+1)中的每个b)置Xi<·b;if(Xi为非终结符,Xi+1为终结符)for(LASTVT(Xi)中的每个a)置a·>Xi+1;end;
素短语 • 素短语是一个短语,它至少含有一个终结符,除它本身外不再含有更小的素短语. • 最左素短语是指处于句型最左边的那个素短语. • 算符优先文法句型的最左素短语是唯一的。形式:ai-1<·ai≡ai+1…≡aj-1≡aj·>aj+1 #句型中<·和·>之间的符号串是待归约的符号串即最左素短语.
句柄和最左素短语的区别:G[E]:E→E+T|T T→T*F|F F→(E)|i句型T+T*F+i 直接短语 如果这种向上归结只需一层(即树叶与该结点为父子关系), 则为直接短语
查找最左素短语的方法 1.最左子串法: • 找出句型中最左子串且终结符由左至右的对应关系满足 aj-1≮aj ≡ aj+1 ≡… ≡ ai ≯ ai+1 • 检查文法G的每个产生式的每个候选式,看是否存在这样一个候选式,该候选式中的所有终结符由左至右的排列恰为aj aj+1… ai,即每一位终结符对应相等;如果存在这样的候选式,则该候选式(包括候选式中的非终结符)即为对应该句型中的最左素短语。
查找最左素短语的方法 2.语法树法: • 设句型为w,先画出对应句型w的语法树。其次,找出该语法树中所有相邻终结符之间的优先关系。
例: 设文法G 为: E→E+T|T T→T+P|P P→(E)|i 试找出句型P+T+(E+i)的全部短语和直接短语,并找出句柄和最左素短语.
E + E T P + T E ( E ) T E + T P P i 解: 设文法G 为: E→E+T|T T→T+P|P P→(E)|i 句型P+T+(E+i)的语法分析树
解: • 如果一个树叶序列由左至右排列最终能够到达某一结点上,并且包含由该结点推导出的全部树叶,不多也不少,则这一树叶序列即为短语. • 如果树叶序列与该结点仅差一层,即能够一步直接归结到该结点,则为直接短语. • 而位置在最左边的直接短语为句柄. 由语法树可以看出,P可以归结到T,P+T可以归结到E,i可以归结到P,E+i可以归结到E, (E+i)可以归结到P,P+T+(E+i)可以归结到E.其中能够一步归结到某一结点的只有P和i,所以得出: 短语: P, P+T, i,E+i, (E+i)和P+T+(E+i); 直接短语: P, i 句柄: P
解: • 从语法树上寻找最左素短语应遵循这样一个原则: • 同层的相邻终结符优先关系为”≡” • 不同层相邻的终结符,层次在下的优先级高,层次在上的优先级低. 从左至右扫描语法分析树的终结符序列可以得到: # ≮ + ≯ + ≮ (≮ + ≮ i ≯ ) ≯ # 由≮ + ≯ 和≮ i ≯ 可知素短语为P+T和i,最左素短语为P+T.
E 例: 文法G为: E→T|E+T T→F|T*F F→(E)|i 求T*F+i的最左素短语 E + T T i T * F 解: 1.画出语法树 2. 根据语法树,确定终结符之间的优先关系: # ≮* ≯ + ≮ i ≯ # 3.根据最左素短语的条件得:T*F为最左素短语
算符优先分析算法 S为符号栈,K代表符号栈S的使用深度 K:=1; s[k]:=‘#’ Repeat 把下一个输入符号读进a中; if s[k]∈VT then j:=k else j:=k-1; while s[j] ≯a do //输入符号的优先级别低,则先将栈内的先规约 begin 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 end of while; if s[j] ≮a or s[j] ≡a then //输入符号的优先级别高,则先进栈 begin k:=k+1;s[k]:=a end else error /*调用出错诊察程序*/ until a=‘#’
例 E →T|E+T T →F|T*F F →i|(E) 算符优先分析过程见左图:
优先函数 • 在实际实现算符优先分析法时,使用优先函数f和g. • 若 a ≮ b 则 f(a) ≮ g(b) • 若 a ≯ b 则 f(a) ≯ g(b) • 若 a ≡ b 则 f(a) ≡ g(b) • 使用优先函数的好处: • 节省存储空间 • 便于执行比较运算 • 对应一个优先关系表的优先函数f和g不是唯一的,只要存在一对,就存在无穷多对. • 也有许多优先关系表不存在对应的优先函数.
于是a和b之间的优先关系可以由比较f(a)与g(b)的大小来决定。于是a和b之间的优先关系可以由比较f(a)与g(b)的大小来决定。 • 关于表5.1的优先关系所对应的函数可定义如下表。 列所对应的 行所对应的
用关系图法构造优先函数 1.对所有终结符a(包括”#”),用有下标的fa,ga为结点名画出全部n个终结符所对应的2n个结点; 2.若a ≯ b 或a≡b, 则画一条从fa到gb的有向弧,若a ≮b或a≡b, 则画一条从gb到fa的有向弧. 3.对每个结点都赋予一个数,此数等于从该结点出发所能到达的结点(包括出发结点自身在内)的个数.赋给fa的数作为f(a),赋给gb的数作为g(b). 4.检查所构造出来的函数f和g,看它们同原来的关系表是否矛盾.如果没有矛盾,则f和g就是所要的优先函数,如果有矛盾,那么就不存在优先函数.
由定义直接构造优先函数 对每个终结符a(包括”#”),令f(a)=g(a)=1, 1.如果a≯b,而f(a)<=g(b),则令f(a)=g(b)+1; 2.如果a≮b,而f(a)>=g(b),则令g(b)=f(a)+1; 3.如果a≡b,而f(a)<>g(b),则令 min{f(a),g(b)}=max(f(a),g(b)}; 4.重复2-3直到过程收敛.如果重复过程中有一个值大于2n,则表明该算符优先文法不存在优先函数.
两种方法比较 • 用关系图法构造优先函数仅适用于终结符不多的情况,由定义直接构造优先函数适用于任何情况,并且也易于用计算机实现. • 另外,对于一般的表达式文法而言,优先函数通常都是存在的.
E → E + E | E - E | E * E | E / E | E ^ E | ( E ) | id 存在优先级 + ≮ * * ≯ + id ≯ + id ≯ * + ≮ id * ≮ id id ≯ # # ≮ id 例 5-12:表达式文法的算符优先关系
算符优先关系的使用 • 分析例:id + id * id • 在输入符号串中插入优先符,形成一组以 ≮为左端,以≡为中缀,以≯为右端的短语。 • # ≮ id ≯ + ≮ id ≯ * ≮ id ≯ # • 对短语进行归约后再次插入优先符 • # ≮ E + ≮ E * E ≯ # • # ≮ E + E ≯ # • # E #
算符优先分析的实现 • 组成结构 • 移进归约分析器 + 优先关系表 • 工作框架 • 输入、输出、初态、终态不变 • 分析算法 P93 • 参照输入串、优先关系表,完成一组产生式归约,产生语法分析树。
id+id*id 的分析过程 id + id * id # 算符优先分析 控制器 E → id id + # id * + # + # + # # * + # + # * + # id # # # E → id E → id E → E * E E → E + E 算符优先关系表
算符优先分析小结 • 优点 • 简单、效率高 • 能够处理部分二义性文法 • 缺点 • 文法书写限制大 • 占用内存空间大 • 不规范、存在查不到的语法错误
算法: 从优先关系构造优先函数方法: 1.a∈VT∪{#},建立两个符号fa和ga; 2.若a ≡ b, 则把fa和gb分在一组;3.a,b ∈VT,若a·>b,则从fa至gb画一条弧;若a<·b,则从gb至fa画一条弧; 4.若图中无环,则存在优先函数,f(a)和g(b)等于从fa 和gb出发的最长路径。
解:用关系图构造优先函数 3 5 1 5 5 fi f+ f) f( f* gi g+ g) g( g* 1 6 6 4 2