编译原理第五章语法分析——自下而上分析内容总结

一、学习内容

本章我们主要学习以自下而上的方法进行语法分析,首先需要了解移进和规约的基本思想,即用一个寄存符号的先进后出栈,把输入符号一个一个地移进到栈里,当栈顶形成某个产生式的候选式时,即把栈顶的这一部分替换成(归约为)该产生式的左部符号。规范规约是假定a是文法G的一个句子,我们称序列an,an-1,¼ ,a0是a的一个规范归约,实际上规范归约相当于最右推导的逆过程,由规范推导推出的句型称为规范句型。然后我们学习了用符号栈进行自下而上的语法分析,在分析开始时,将“#”预先进栈,作为栈底符号,同时将“#”作为输入串的结束符,自左向右对输入串ω不断向栈中进行移进——归约。再往下我们了解到算符优先分析法,定义算符之间优先关系,借助这种关系来寻找“可归约串”和进行归约,此时就需要定义两个终结符‘a’与‘b’的优先关系:a =.b表示a的优先性等于b;a .>b表示a的优先性大于b;a <.b表示a的优先性小于b ,需要注意的是这里的“=.”“.>”“<.”不同于数学上的 “=”“>”“<”,a =.b不一定对应着b =.a。引出算符文法,是指一个文法,如果它的任一产生式的右部都不含两个相继(并列)的非终结符,即不含…QR…形式的产生式右部,则我们称该文法为算符文法,也称OG文法。根据算符文法,引出算符优先文法以及算符优先关系表,具体的构造方法在知识运用中提及。随后我们学到了优先函数,把每个终结符q与两个自然数f(q)与g(q)相对应,使得若q1 <. q2,则f(q1) < g(q2);若q1 =. q2,则f(q1) = g(q2);若q1 >. q2,则f(q1) > g(q2),f称为入栈优先函数,g称为比较优先函数,但是许多优先关系表不存在优先函数。

接着我们学习了第三节LR分析法,LR分析方法也是一种自下而上的分析方法,LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范归约过程,它用到了两个表:动作表(ACTION[s,a]:       当状态s面临输入符号a时,应采取什么动作)和状态转换表(GOTO[s,X]:状态s面对文法符号X时,下一状态是什么)。构造LR分析表我们需要了解活前缀的概念:文法G的活前缀是他的规范句型的前缀,该前缀不超过句柄的右端。该前缀加上被分析串中未被分析的终结符,就可以构成一个规范句型,只要输入串的已扫描部分可归约成一个活前缀,意味着扫描过的部分没有错误。LR分析表的构造要构造识别活前缀的有限自动机,用有限自动机中的状态表示分析表中的状态,用状态图中的状态之间的转换关系对分析表中的action和goto函数等进行定义。我们把右部某位置上标有圆点的产生式称为相应文法的一个LR(0)项目,特别对形如A→ε的产生式,A→·。本章一个重要内容构造识别活前缀的NFA:首先构造文法的所有产生式的项目,每个项目都为NFA的一个状态;其次确定初态、句柄识别态、句子识别态以及状态之间的转换关系。同样重要的LR(0)项目集规范族构造:首先构造G的拓广文法G’,设S为文法G的开始符号,构造一个文法G’,它包含整个文法G,并且引进了一个不出现在G中的非终结符S¢,并加进一个新产生式S¢→S,这个S¢是G¢的开始符号,G’成为G的拓广文法;其次构造I的闭包CLOSURE(I);最后设置转换函数。需要注意一个项目集可能包含多种项目,则会产生移进-归约冲突和归约-归约冲突,若其LR(0)项目集规范族不存在这两种冲突,称为LR(0)文法。大多数程序设计语言的文法不能满足LR(0)文法的条件,即其规范族中会有含有冲突的项目集(状态),我们通过对于有冲突的状态,向前查看一个符号,以确定采用的动作来解决这个问题。

二、知识运用

1.短语的判断(两个条件)

令G是一个文法,S是文法的开始符号,假定abd是文法G的一个句型,其中α,β,d∈(VN∪VT)*,A∈VN ,如果有①S*=>αAd且②A+=>β则b称是句型abd相对于非终结符A的短语。

2.终结符之间的优先关系

(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.构造算符优先关系表

(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)

        ②若aÎFIRSTVT(Q),且有产生式P→Q…,则aÎFIRSTVT(P)

(4)同理构造集合LASTVT(P)的算法,按其定义,可用下面两条规则来构造集合LASTVT(P):

        ① 若有产生式P→… a或P→… aQ ,则aÎ LASTVT(P)

        ② 若aÎ LASTVT(Q),且有产生式P→… Q ,则aÎ LASTVT(P)

(5)有了这两个集合之后,就可以通过检查每个产生式的候选式确定满足关系<.和.>的所有终结符对:

①假定有个产生式的一个候选形为…aP…那么,对任何bÎFIRSTVT(P),有a <. b

②假定有个产生式的一个候选形为…Pb…那么,对任何aÎLASTVT(P),有a >. b

4.优先表构造优先函数

(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就是要求的优先函数,若有矛盾,则不存在优先函数。

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

  (1)若项目A→a•ab属于Ik,且转换函数GO(Ik,a)=Ij,当a为终结符时 ,则置ACTION[k,a]为Sj;

 (2)若项目A→a•属于Ik,则对a为任何终结符或“#”,置ACTION[k,a]=rj, j为产生式在文法G′中的编号;

 (3)若GO(Ik,A)=Ij,则置GOTO[k,A]=j,其中A为非终结符,j为某一状态号;      

  (4)若项目S′→S•属于Ik,则置ACTION[k,#]= acc;

 (5)其它填上“报错标志”。

以下为具体习题:

 










三、我的感受

  第五章难度较之前几章有所提升,前面部分例如短语的判断、终结符之间优先关系的判断、算符优先关系表以及优先函数等知识相对简单,这里通过习题的锻炼基本可以较为熟练的掌握。后面部分构造识别文法所有活前缀的NFA方法难度不是很大但是比较繁杂,确定状态之间转换关系时容易粗心出错,状态图往往比较杂乱不易完全正确。而对于LR(0)项目集规范族构造,在闭包的处理过程中需要多加留心。最后利用SLR解决构造的LR(0)项目集规范族冲突理解起来有点困难,这部分需要我将课本知识反复琢磨,在习题方面也将放更多的精力,争取做到学会、学熟、学精。

猜你喜欢

转载自blog.csdn.net/xmj1886480/article/details/80316167