编译原理——第五章

第五章  语法分析    自下而上分析

知识总结

一、自上而下分析基本问题

1、移进规约

基本思想:

用一个寄存符号的先进后出栈,把输入符号一个一个地移进到栈里,当栈顶形成某个产生式的候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。

规约:

是指根据文法的产生式规则,把产生式的右部替换成左部符号。

2、规范规约

短语:

定义:令G是一个文法,S是文法的开始符号,假定αβγ是文法G的一个句型。

其中α,β,γ∈(VN∪VT)*,A∈VN ,如果有

则β称是句型αβγ相对于非终结符A的短语。

直接短语:

特别是,如果有A=>β,则称β是句型αβγ相对于规则A—>β的直接短语

句柄:

一个句型的最左直接短语称为该句型的句柄。

规范规约:


注意:

(1)规范归约是关于一个最右推导的逆过程
    最左归约是关于一个规范推导的逆过程
    由规范推导推出的句型称为规范句型

(2)由于规范句型由最右推导推出的句型,故该句型的句柄右边只含有终结符号

语法树与分析法

(1)子树:是由该树的某个结点(子树的根)连同它的所有子孙组成。

(2)简单子树:只有单层分支的子树(只有父子两代没有第三代)

(3) ①每个句型都有一棵语法树与之对应
     ②每棵语法树的叶结点自左至右排列就组成一个句型
     ③每棵子树的叶结点自左至右排列就组成一个短语
     ④每棵简单子树的叶结点自左至右排列就组成一个直接短语

     ⑤每棵最左简单子树的叶结点自左至右排列就组成一个句柄

3、用符号栈进行自下而上的语法分析

'#’的使用
(1)在分析开始时,将’#’预先进栈,作为 栈底符号
(2)将’#’作为输入串的结束符

即分析开始时的格局为


自左向右对输入串ω不断向栈中进行移进——归约,直到形成如下格局

表示分析成功。

二、算符优先分析法

1、定义两个终结符‘a’与‘b’的优先关系

a =.b   表示a的优先性等于b
a >.b   表示a的优先性大于b

a <.b   表示a的优先性小于b 

2、算符优先文法及优先表构造

算符优先文法

(1)算符文法

定义:一个文法,如果它的任一产生式的右部都不含两个相继(并列)的非终结符,即不含如下形式的产生式右部:

…QR… 

则我们称该文法为算符文法,也称OG文法。

(2)定义终结符之间的优先关系

假定G是一个不含产生式的算符文法。对于任何一对终结符a、b,我们说:

1. a =. b 当且仅当文法G中含有形如P→…ab…或P→…aQb…的产生式;

2. a <. b 当且仅当G中含有形如P→…aR…的产生式, 而R  b…或R Qb…;

3. a>.b 当且仅当G中含有形如P→…Rb…的产生式,而 R …a或R…aQ。

(3)如果一个算符文法G中的任何终结符对(a,b)至多只满足下述三关系之一:
a=.b
a>.b
a<.b

 则称G是一个算符优先文法(OPG文法)。

构造算符优先关系表

(1)通过检查产生式的每一个候选式可以找出满足a=.b
  (即P→…ab…或P→…aQb…的产生式)

(2)为了满足<.和>.,需对G中每个非终结符P构造两个集合FIRSTVT(P)和LASTVT(P)



(3)构造集合FIRSTVT(P)的算法
按其定义,可用下面两条规则来构造集合FIRSTVT(P):
① 若有产生式P→a…或P→Qa…,
则aFIRSTVT(P);
② 若aFIRSTVT(Q),且有产生式P→Q…,

则aFIRSTVT(P)。

(4)同理构造构造集合LASTVT(P)的算法
按其定义,可用下面两条规则来构造集合LASTVT(P):
① 若有产生式P→… a或P→… aQ ,
则aLASTVT(P);
② 若a LASTVT(Q),且有产生式P→… Q ,

则aLASTVT(P)。

(5)有了这两个集合之后,就可以通过检查每个产生式的候选式确定满足关系<.和>.的所有终结符对。
①假定有个产生式的一个候选形为
   …aP…
  那么,对任何bFIRSTVT(P),有a <. b。
②假定有个产生式的一个候选形为
…Pb…

  那么,对任何aLASTVT(P),有a >. b。

注意:
对于‘#’号,相当于在文法开始符号S前加一个额外的开始符号,比如为Z

然后,把

Z →#S#

添加到原文法中,再进行分析。

3、算符优先分析算法的设计

(1).问题的提出
自下而上分析
移进-归约法:句柄为可归纳串
算符优先分析法:最左素短语为可归纳串
(2).素短语
指一个句型的短语,它至少包括有一个终结符号且除去它本身之外不再含任何更小的素短语
(3).最左素短语

处在句型最左端那个素短语成为最左素短语

(4).算符优先分析算法和设计

①句型的一般表示形式:
 #N1a1N2a2…NnanNn+1#
 其中,每个ai都是终结符,Ni是可有可无的非终结符
②定理:
一个算符优先文法G的任何句型的最左素短语是满足如下条件的最左子串 Njaj…NiaiNi+1,
aj-1 <. aj
  aj =. aj+1,aj+1 =. aj+2,…,ai-1 =. ai
    ai >. ai+1

注意:

出现在左端或右端的非终结符一定属于这个素短语

4、优先函数

优先函数的定义
把每个终结符与两个自然数f(θ)与g(θ)相对应,使得
若θ1 <. θ2,则f(θ1) < g(θ2)
若θ1 =. θ2,则f(θ1) = g(θ2)
若θ1 >. θ2,则f(θ1) > g(θ2)

f称为入栈优先函数,g称为比较优先函数。

优先函数的构造方法
如果优先函数存在,则可以通过以下三个步骤从优先表构造优先函数:
(1)对于每个终结符a,令其对应两个符号fa和ga,画一张以所有符号fa和ga为结点的方向图。如果a>.b,则从fa画一条弧至gb如果a<.b,则从gb画一条弧至fa 。
(2)对每个结点都赋予一个数,此数等于从该结点出发所能到达的结点(包括出发点自身)。赋给fa的数作为f(a)赋给ga的数作为g(a)。

(3)检查所构造出来的函数f和g是否与原来的关系矛盾。若没有矛盾,则f和g就是要求的优先函数,若有矛盾,则不存在优先函数。

三、LR分析法

1、LR分析方法和LL分析方法的比较:


LR分析方法——分析器结构


动作表
ACTION[s,a]:当状态s面临输入符号a时,应采取什么动作
每一项ACTION[s,a]所规定的四种动作:
       <1>. 移进:把(s,a)的下一状态s’=GOTO[s,a] 和输入符号a推进栈,下一输入符号变成现行输入符号.
       <2>. 归约:指用某产生式A进行归约.  假若的长度为r, 归约动作是A, 去除栈顶r个项,使状态sm-r变成栈顶状                     态,然后把(sm-r, A)的下一状态s’=GOTO[sm-r, A]和文法符号A推进栈.
       <3>. 接受:宣布分析成功,停止分析器工作。

       <4>. 报错:发现源程序含有错误,调用出错处理程序

      si:移进,并将状态i进栈。

      ri:用第i个产生式归约,同时状态栈与符号栈退出相应个符号,根据GOTO表将相应状态入栈。

LR分析过程

第一步  分析开始时,首先将初始状态SO及句子左界符#推入分析栈中。

第二步  设在分析的某一步,分析栈及余留的输入符号串处于如下的格局。 


则以栈顶的状态及正扫视的输入符号ai组成符号对(Sm,ai)去查分析动作表,并根据表元ACTION[Sm,ai]的指示完成相应的分析动作。每一分析表元所规定的动作,仅能是下列四种动作之一: 

(1)若ACTION[Sm,ai]=“移进”,这表明句柄尚未在栈顶部形成,此时正期待继续移进输入符号以形成句柄,故将当前的输入符号推入栈中:


然后,以符号对(Sm,ai)查状态转移表,设相应的表元GOTO [Sm,ai]= Sm+1,再将此新的状态(即要转移到的下一状态)推入栈中,则有如下的格局:



(2)若ACTION[Sm,ai]= rj ,其中rj意指按文法的第j个产生式A→Xm-r+1 Xm-r+2…Xm进行归约。

   将分析栈从顶向下的r个符号(因为该产生式右部符号串的长度为r)退出,然后再将文法符号A推入栈中,此时分析栈的格局为:


然后,以(Sm-r ,A)查状态转移表,设GOTO [Sm-r,A]=Sl,将此新状态推入栈中,则有如下的格局:

需注意的是,当完成归约动作之后,输入串指示器不向前推进,它仍然指向动作前的位置。

(3)若ACTION[Sm,ai]=“接受”,则表明当前的输入串已被成功地分析完毕,应中止分析器的工作。

(4)若ACTION[Sm,ai]=ERROR,则表明当前的输入串中有语法错误,也应终止分析器的工作。

第三步  重复上述第二步的工作,直到在分析的某一步,栈顶出现“接受状态”或“出错状态”为止。对于前者,分析栈的最终格局应为:


其中,Z为文法的开始符号,Sα则为使ACTION[Sα,#]=“接受”的唯一状态(即接受状态)。

对任何不同的LR(1)分析表都适用。

2、LR(0)项目集族和分析表的构造

活前缀:

文法G的活前缀是他的规范句型的前缀,该前缀不超过句柄的右端。

活前缀特点:

该前缀加上被分析串中未被分析的终结符,就可以构成一个规范句型

活前缀与句柄间的关系:

(1)活前缀中已含有句柄的全部符号(句柄的符号即为其最右符号)。
(2)活前缀中含句柄的一部分符号(句柄开头的 若干符号与活前缀最右的若干个符号一致)。

(3)活前缀中全然不包含句柄的任何符号 。

LR(0)项目:在每个产生式的右部适当位置添加一个圆点构成项目。

构成识别一个文法活前缀的DFA项目集(状态)的全体称为这个文法的LR(0)项目集规范族。

I的闭包CLOSURE(I):

(1)  I的任何项目都属于CLOSURE(I);
(2)  若A→·B属于CLOSURE(I),那么,对任何关于B的产生式B→的项目B→·也属于CLOSURE(I);
(3)  重复执行上述两步骤直至CLOSURE(I) 不再增大为止
例如:设I={S→·E}

则CLOSURE(I)={S→·E ,E→·aA, E→·bB}

定义转换函数如下:
GOTO(I,X)=CLOSURE(J)其中:
I为包含某一项目集的状态,
X为一文法符号,

J={任何形如A→X•的项目|A→•X属于I}。

LR(0)分析表的ACTION和GOTO表的构造步骤


LR(0)项目集规范族存在移进-归约,或归约-归约冲突,称为LR(0)文法。

知识应用

总结

通过整理可以看出这一章的内容多而杂,并且理解起来很吃力,更不用说做题了。课后提目前只能独立完成基础题,稍微复杂一点的题做起来就没有了思路,不停地翻课件,看例题。但是还是无果,只能借助一些资料来完成。这一章的内容短时间内还无法消化,只能有时间了再通过自己的博客和课件巩固学习。

猜你喜欢

转载自blog.csdn.net/qq_34149526/article/details/80301995