第6章 自底向上优先分析法
自底向上分析方法,也 称移进-归约分析法,粗略地说它的实现思想是对输入符号串自左向右进行扫描,并将输入符逐个移入一个后进先出栈中,边移入边分析,一旦栈顶符号串形成某个 句型的句柄时,(该句柄对应某产生式的右部),就用该产生式的左部非终结符代替相应右部的文法符号串,这称为归约。重复这一过程直到归约到栈顶中只剩文法 的开始符号时则为分析成功,也就确认输入串是文法的句子。本章将在介绍自底向上分析思想基础上,着重介绍算符优先分析法。
例6.1,设文法G[S]为:
(1)S→aAcBe
(2)A→b
(3)A→Ab
(4)B→d
对输入串abbcde#进行分析,检查该符号串是否是G[S]的句子。
由于自底向上分析的移进-归约过程是自顶向下最右推导的逆过程,而最右推导为规范推导,自左向右的归约过程也称为规范归约。
容易看出对输入串abbcde的最右推导为:
S  aAcBe
 aAcde
 aAcde  aAbcde
aAbcde  abbcde
 abbcde
由此我们可以构造它的逆过程即归约过程。
先设一个后进先出的符号栈,并把句子左括号”#”号放入栈底。对上述分析过程也可看成自底向上构造语法树的过程,每步归约都是构造一棵子树,最后当输入串结束时刚好构造出整个语法树。
在上述移进-归约或自底向上构造语法树的过程中,考虑几个问题:
- u 何时移进?
- u 何时归约?
- u 将哪个字符串归约?
当 一个文法无二义性时,那么它对一个句子的规范推导是唯一的,规范规约也必然是唯一的。因而每次归约时要找当前句型的句柄,也就是说,任何时候栈中的符号串 和剩余的输入串组成一个句型,当句柄出现在栈顶符号串中时,则可用句柄归约,这样一直归约到输入串只剩结束符,文法符号栈中只剩开始符号。
由此可见,自底向上分析的关键问题是在分析过程中如何确定句柄,即如何知道何时在栈顶符号串中已形成某句型的句柄。然而自底向上的分析算法很多,我们仅在本章和第7章介绍目前常用的算符优先分析和LR类分析法。
6.1 自底向上优先分析法概述
优先分析法又可分简单优先法和算符优先分析法。
- l 简单优先分析法的基本思想是对一个文法按一定原则求出该文法所有符号(即终结符和非终结符)之间的优先关系,按照这种关系确定归约过程中的句柄,它的归约过程实际上是一种规范规约。
- l 算符优先分析法的基本思想则是只规定算符之间的优先关系,即只考虑终结符之间的优先关系,由于算符优先分析不考虑非终结符之间的优先关系,在归约过程中只要找到句柄就归约,并不考虑归约到那个非终结符名,因而算符优先归约不是规范归约。
本节主要介绍算符优先分析法,对简单分析法只做粗略介绍。
6.2简单优先算法
简单优先分析法是按照文法符号(终结符和非终结符)的优先关系确定句柄的,因此我们首先介绍任意两个文法符号之间的优先关系是怎样确定的,及如何构造优先关系表。
6.2.1 优先关系
已给文法,对于任意文法符号,首先定义优先关系的表示:
X=Y 表示X和Y的优先关系相等。
X>Y 表示X的优先于Y。
X<Y 表示X的优先性比Y的优先性小。
这样我们就可对已知文法中对它的任意两个文法符号X,Y按其在句型中可能会出现的相临关系来确定他们的优先关系。
- l X=Y 当且仅当G中存在产生式A→…XY…
- l         X<Y  当且仅当G中存在产生式A→…XB… ,且B![]() Y… Y…
- l         X>Y  当且仅当G中存在产生式A→…BD… ,且B![]() …X和D …X和D![]() Y… Y…
例6.2 若有文法G[S]:
S→bAb A→(B|a B→Aa)
根据上面=、>、<关系的定义,由文法的产生式可求得文法符号之间的优先关系如下:
- l 求=关系:
由S→bAb,A→(B,B→Aa)可得:b=A,A=b,(=B, A=a, a=)
- l 求<关系:
由S→bAb,且A (B,A
(B,A a可得:b< ( ,b<a
 a可得:b< ( ,b<a
由A→(B且B (B…;B
(B…;B a…;B
a…;B A…,可得:(<(,(<a,(<A
A…,可得:(<(,(<a,(<A
- l 求>关系:
由S→bAb且A …),A
…),A …B,A
…B,A a,可得:)>b,a>b,B>b
a,可得:)>b,a>b,B>b
由B→Aa)且A …),A
…),A a,A
a,A …B,可得:)>a,a>a,B>a
…B,可得:)>a,a>a,B>a 
上述关系也可以用语法树的结果表示如图。

把文法符号之间的关系用矩阵表示,称作优先关系矩阵。
例6.2文法的简单优先关系矩阵可用下表表示。
‘#’号用来表示语句括号,‘#’号的优先级<所有符号,所有符号的优先级>‘#’号,当然这里仅对与‘#’号有相邻关系的文法符号而言。

6.2.2 简单优先文法的定义
若一个文法是简单优先文法必须满足以下条件:
- l 在文法符号集V中,任意两个符号之间最多只有一种优先关系成立。
- l 在文法中任意两个产生式没有相同的右部。
其中第一条必须满足是显然的,对第二条来说,若不满足则会出现归约不唯一。
6.2.3简单优先分析法
简单优先分析法分析算法如下:
1)将输入符号串a1a2……an#依次逐个存入符号栈S中,直到遇到栈顶符号ai>下一个待输入符号ai+1时为止。
2)栈顶当前符号ai为句柄尾,在栈中找句柄的头符号ak,即找到ak-1<ak为止。
3)由句柄ak……ai在文法的产生式中查找右部为ak……ai的产生式,若找到则用相应左部代替句柄,若找不到则为出错,这时可断定输入串不是该文法的句子。
4)重复上述(1)、(2)、(3)步骤直到归约完输入符号串,栈中只剩文法的开始符号为止。
6.3算符优先分析法
6.3.1 直观算符优先分析法
通 常在算术表达式求值过程中,运算次序是先乘除后加减,这说明了乘除运算的优先级高于加减运算的优先级,乘除为同一优先级但运算符在前边的先做,这称为左结 合,同样加减运算也是如此,这也说明了运算的次序只与运算符有关,而与运算对象无关,因而直观算符优先分析法的关键是对一个给定文法G,人为地规定其算符的优先顺序,即给出优先级别和同一个级别中的结合性质,算符间的优先关系表示与简单优先关系的表示类似,其规定如下:
- l a<b 表示a的优先性低于b。
- l a=b 表示a的优先性等于b,即与b相同。
- l a>b 表示a的优先性高于b。
但必须注意,这三个关系和数学中是不同的,它们是有序的,也就是若有a>b,不一定有b<a,a=b成立不一定有b=a。
下面给出一个表达式的文法为:
E→E+E|E-E|E*E|E/E|E↑E|(E)|i
我们可以对此表达式的文法按公认的计算顺序规定优先级和结合性如下:
1)↑优先级最高,遵循右结合。相当↑<↑。
例如:2↑3↑2=2↑9=512。即同类运算符在归约时为从右向左归约。即i1↑i2↑i3为i2↑i3先归约。
2)*,/优先级其次,服从左结合。相当*>*、*>/、/>/、/>*、 *<↑、 /<↑
3)+,-优先级最低,服从左结合。相当+>+、+>-、→+、→-、+ < *、+ < /、+ < ↑ 。
4)对‘(’,‘)’规定括号的优先性大于括号外的运算符,小于括号内的运算符,内括号的优先性大于外括号。对于句子括号‘#’号规定与它相邻的任何运算符的优先性都比它大。此外,对运算对象的终结符i其优先级最高。
综上所述,我们可对表达式运算符的优先关系构造表。

很显然,所给表达式文法显然是二义性文法,但我们人为直观地给出运算符之间的优先关系且这种优先关系是唯一的,有了这个优先关系表我们就能分析了。
6.3.2 算符优先文法的定义
(1)算符文法
定义6.1 设有一文法G,如果G中没有形如A→…BC…的产生式,其中B和C为非终结符,则称G为算符文法(Operater Grammar)也称OG文法。如,表达式文法E→E+E|E*E|(E)|i。
性质1 算符文法中任何句型都不包含两个相邻的非终结符。
证: 设γ是句型,S=ω0 Þ ω1…… Þ ωn-1 Þ ωn=γ
对推导长度为n用归纳法。当n=1时,
S=ω0 Þ ω1=γ即S Þ γ必存在产生式S→γ,而由算符文法的定义,产生式中无相邻的非终结符,显然满足性质1。
假设n-1时结论成立,ωn-1满足性质1。
若ωn-1=αAδ,A为非终结符。
由假设α的尾符号和δ的首符号都不可能是非终结符。
又若A→β是文法的产生式,则有ωn-1 Þ ωn=αβδ=γ
而A→β是文法的原产生式不含两个相邻的非终结符,所以αβδ也不含两个相邻的非终结符。满足性质1,证毕。
性质2 如果Ab或bA出现在算符文法的句型γ中,其中A∈VN,b∈VT,则γ中任何含b的短语必含有A。
证明:用反证法。
(2)算符优先文法
定义6.2 设G是一个不含ε产生式的算符文符,a和b是任意两个终结符,A、B、C是非终结符,算符优先关系=、<、>定义如下:
1)a=b 当且仅当有形如A→…ab…或A→…aBb…的产生式。
2)a<b 当且仅当有形如A→…aB…的产生式,且B b…或B
b…或B Cb…
Cb…
3)a>b 当且仅当G中含有形如A→…Bb…的产生式,且B …a或B
…a或B …aC
…aC 
以上三种关系也可由下列语法树来说明:
- l a=b则存在语法子树如图(a)
- l a<b则存在语法子树如图(b)
- l a>b则存在语法子树如图(c)
其中δ为ε或为C。

定义6.3 设有一不含ε产生式的算符文法G,如果对任意两个终结符对a,b之间至多只有<、>和=三种关系的一种成立,则称G是一个算符优先文法,即OPG文法。
由定义6。2和6。3很容易知:E→E+E| E*E | (E) | i 不是算符优先文法。
因为对算符+、*来说,由E→E+E和E→E*E。
可有+<*,又可由E→E*E和E→E+E得+>* 。

这里须再次强调,两个终结符之间的优先关系是有序的,允许由a>b,b>a同时存在,而不允许有a>b,a<b,a=b三种情况之两种同时存在。
6.3.3 算符优先关系表的构造
首先我们定义如下两个集合:
FIRST VT(B)={b|B  b……或B
b……或B  Cb……}
Cb……}
LAST VT(B)={a|B  ……a或B
……a或B  ……aC}
……aC} 
三种优先关系的计算为:
(a)=关系:
可直接查看产生式的右部,对形如产生式A→…ab…或A→…aBb…则有a=b成立。
(b)<关系:
求出每个非终结符B的FIRST VT(B),对形如产生式:A→…aB…中对每一b∈FIRST VT(B)则有a<b成立。
(c)>关系:
计算每个非终结符B的LAST VT(B),对形如产生式A→…Bb…中对每一a∈LAST VT(B) 则有a>b成立。
可用上述算法计算下列表达式文法的算符优先关系。
例6.3若表达式文法为:
(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),可得#=#,(=)成立,
为了求<,>关系,先计算FIRST VT集合和LAST VT集合。
FIRST VT(E’)={#}; FIRST VT(E)={+,*,↑,(,i }; FIRST VT(T)={*,↑,(,i}
FIRST VT(F)={↑,(, i}; FIRST VT(P)={(,i}
LAST VT(E’)={#}; LAST VT(E)={+,*,↑,),i}
LAST VT(T)={*,↑,),i}; LAST VT(F)={↑,),i}; LAST VT(P)={),i}
然后逐条扫描产生式寻找产生式右部有形如:A→…aB…和A→…Bb…的产生式。
(b)<关系:
#E 则:#<FIRST VT(E) +T 则:+<FIRST VT(T)
*F 则:*<FIRST VT(F) ↑F 则:↑<FIRST VT(F)
(E 则:(<FIRST VT(E)
(c)>关系:
E# 则: LAST VT(E)># E+ 则: LAST VT(E)>+
T* 则: LAST VT(T)>* P↑ 则: LAST VT(P)>↑
E) 则: LAST VT(E)>)
从而可以构造优先关系矩阵为表。

6.3.4 算符优先分析算法
有了算符优先关系表,我们就可以对任意给定的符号串进行归约分析。
(1)算符优先分析句型的性质
算符文法的任何一个句型应为如下形式:#N1a1N2a2……NnanNn+1#
其中Ni(1≤i≤n+1)为非终结符或空,ai(1≤i≤n)为终结符。
若有Niai……NjajNj+1为句柄,则Ni和Nj+1在句柄中。
该句柄终结符之间的关系为:
ai-1<ai , ai=ai+1=……=aj-1=aj , aj>aj+1
这是因为算符优先文法有如下性质,即:如果aNb(或ab)出现在句型r中,则a和b之间有且只有一种优先关系。
算符优先文法在归约过程中只考虑终结符之间的优先关系确定句柄,而与非终结符无关


为了解决在算符优先分析过程中如何寻找句柄的问题,我们引进最左素短语的概念。
(2)最左素短语
定义6.5 设有文法G[S],其句型的素短语是一个短语,它至少包含一个终结符,并除自身外不包含其他素短语,最左边的素短语称最左素短语。
如,若表达式文法G[E]为:
E→E+T|T T→T*F|F F→P↑F|P P→(E)|i
句型#T+T*F+i#的语法树如图。 包含短语为:T+T*F+i 、T+T*F 、T 、T*F、i
由定义知i和T*F为素短语,T*F为最左素短语。

(3)算符优先分析归约过程算法
算符优先分析法不是规范归约。规范归约的关键问题时如何寻找当前句型的句柄,而算符优先分析归约的关键,是如何找最左素短语,最左素短语NiaiNi+1ai+1…ajNj+1应满足:
ai-1<ai
ai=ai+1=…aj
aj>aj+1
归约到那个非终结符?在文法的产生式中存在右部符号串的符号个数与该素短语的符号个数相等,非终结符号对应Nk,(k=i,…,j+1),终结符对应ai,…,aj,其符号名要与ai,…,aj的实际名相一致,相应位置也一致,才有可能形成素短语。其归约过程如下:

6.3.5 优先函数
前面用算符优先分析法时,对算符之间的优先关系,我们用优先矩阵表示,这样需占用大量的内存空间,当文法有n个非终结符时,就需要有(n+1)2个内存单元(终结符和#号),因而,在实际应用中往往用优先函数来代替优先矩阵表示优先关系。它对具有n个终结符的文法,只需2(n+1)个单元存放优先函数,这样可节省大量的存储空间。
我们可以定义两个函数f,g满足如下条件。
当a=b,则令f(a)=g(b)
当a<b,则令f(a)<g(b)
当a>b,则令f(a)>g(b)
对f,g我们称它为优先函数。
已给优先关系,构造优先函数的方法:
(1)由定义直接构造优先函数
若已知文法G终结符之间的优先关系,可按如下步骤构造其优先函数f,g。
(a)对每个终结符a∈VT(包括#号在内)令f(a)=g(a)=1,
(b)如果a>b,而f(a) ≤g(b)则令f(a)=g(b)+1
(c)如果a<b,而f(a) ≥g(b)则令g(b)= f(a)+1
(d)如果a=b,而f(a) ≠g(b)则令min{f(a),g(b)}=max{f(a),g(b)}
(e)重复(b)~(d)直到过程收敛。
如,若已知表达式文法的算符优先矩阵如表,

则其优先函数计算过程如下表:

例中优先函数的计算迭代三次收敛。不难看出对优先函数每个元素的值都增加同一个常数,优先关系不变。因而,对同一个文法的优先关系矩阵对应的优先函数不唯一。
然而也有一些优先关系矩阵中的优先关系是唯一的,却不存在优先函数,例如下面优先关系矩阵:

不存在优先函数f,g的对应关系。
由于若存在优先函数f,g,则必定满足下列条件,
由矩阵的第一行应有f(a)=g(a),f(a)>g(b)
由矩阵的第二行应有f(b)=g(a),f(b)=g(b)
这样导致有 f(a)=g(a)=f(b)=g(b)
与f(a)>g(b)矛盾,因而优先函数不存在。
(2)用关系图法构造优先函数
对于存在优先函数的优先矩阵,也可以用关系图法构造优先函数:
(a)对所有终结符a(包括‘#’)用下脚标的fa,ga为结点名,画出2n个结点。
(b)若ai>aj或ai=aj,则从fai到gaj画一条箭弧。
若ai<aj或ai=aj,则从gaj到faj画一条箭弧。
(c)给每个结点赋一个数,此数等于从该结点出发所能到达的结点(包括该结点自身在内)的个数。赋给结点fai的数,就是函数f(ai)的值,赋给gaj的数,就是函数g(aj)的值。
(d)对构造出的优先函数,按优先关系矩阵检查一遍是否满足优先关系的条件,若不满足时,则说明不存在优先函数。
若已知上面例题的优先关系矩阵。构造优先关系图为图6。9。
 
    

(3)优先函数的优缺点
对于用优先函数分析虽然占用空间少,但它有不可克服的缺点如下所述:
我们在利用优先关系矩阵进行优先分析时,当两个终结符对无优先关系的情况时,优先关系矩阵的相应元素为出错信息,而用优先函数进行优先分析时,对两个终结符对没有优先关系时不能区分,因而出错时不能准确地指出错误位置。
如,表达式为i+i*i(i+i)#按算符优先矩阵‘i’与‘(’无优先关系,当归约分析N+N*i时,能即时发现错误,而用优先函数分析时发现不了错误,直到归约到N+N*NN时,才能由两非终结符相邻的出现而发现错误,因而不能准确指出错误位置。
6.3.6 算符优先分析法的局限性
算符优先分析法去掉了单非终结符之间的归约,尽管在分析过程中,可以采取一些检查措施,但仍难完全避免把错误的句子得到正确的归约。
 
                    
                     
                    
                 
                    
                
 Y…
Y…  …X和
…X和 Y…
Y…  
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号