1、6.1 LR分析法,LR分析法是一种自下而上进行规范归约的语法分析方法。,这里L是指从左到右扫描输入符号串。R是指构造最右推导的逆过程。,LR分析法主要缺点:对于一个语言的文法,构造LR分析器的工作量相当大,具体实现较困难。,因此,目前对于真正实用的编译程 序,采用构造 LR 分析器的专用工具“ YACC ” 自动地构造出LALR(1) 语法分析器。,本 章主要介绍LR分析法的基本思想和LR(0)、SLR(1) 、LR(1) 、LALR(1)分析器的工作原理和构造方法。,6.1 LR分析法,LR分析法的基本思想:,LR分析法是一种规范归约分析法。,规范归约分析法的关键是在分析过程中如何确定分析
2、栈栈顶的符号串是否形成句柄。,6.1.1 LR分析器的逻辑结构和工作过程,LR分析法确定句柄的基本思想:在规范归约分析过程中,根据分析栈中记录的已移进和归约出的整个符号串(即历史)和根据使用的规则推测未来可能遇到的输入符号(即展望)以及现实读到的输入符号这三个方面的信息来确定分析栈栈顶的符号串是否构成句柄。,6.1.1 LR分析器的逻辑结构和工作过程,LR分析器的逻辑结构,一个LR分析器的逻辑结构示意图如下图所示。,它由分析栈、,分析表和,总控程序3个部分组成。,分析栈,输出,6.1.1 LR分析器的逻辑结构和工作过程,分析栈用来存放分析过程中的历史和展望信息。,LR分析法将历史和展望信息抽象
3、成状态,并放在分析栈中,这就是说分析栈中的每个状态概括了从分析开始到某一归约阶段的整个分析历史和对未来进行的展望。,1. 分析栈,6.1.1 LR分析器的逻辑结构和工作过程,例如,对文法GE:,EE+T| T,TT*F | F,F(E) | id,状态Sm不仅表征了从分析开始到现在已扫描过的输入符号被归约成#ET,而且由Sm可以预测,如果输入串没有语法错误,根据归约时所用规则(非终结符T的规则)推测出未来可能遇到的输入符号仅是,中的任意一个符号。,FOLLOW(T)=+,*,),#,分 析 栈 示 意 图,6.1.1 LR分析器的逻辑结构和工作过程,只有FOLLOW(T)中的符号才会跟在T后面
4、,若当前读到的输入符号是* ,根据文法可知*的优先级高于,栈顶尚未形成句柄,则应将*移入栈中;,若当前读到的输入符号是或)或#时,根据文法可知栈顶已形成句柄,则应将符号串ET归约为E;,若当前读到的输入符号不是上述四种符号之一,则表示输入串有语法错误。,由此可知,LR分析器的每一步分析工作,都是由栈顶状态和现行输入符号所唯一确定的。,6.1.1 LR分析器的逻辑结构和工作过程,LR分析表是LR分析器的核心部分。,一张LR分析表由分析动作(ACTION)表和状态转换( GOTO )表两部分组成,它们都是二维数组。,状态转换表元素GOTOSi , X规定了当状态Si面临文法符号X时,应转移到的下一
5、个状态。,2. LR分析表,6.1.1 LR分析器的逻辑结构和工作过程,见表,分析动作表元素ACTIONSi , a规定了当状态Si面临输入符号a时应执行的动作。,分析动作表对应四种可能动作:,移进:把状态Sj=GOTOSi , a和输入符号 a移入分析栈。,归约:当栈顶符号串形成句柄,且文法中 有A的规则,其中|=,则归约 动作是从分析栈栈顶去掉个文法符号和个状态,并把归约符A和 GOTOSi- ,A=Sj移入分析栈中。,6.1.1 LR分析器的逻辑结构和工作过程,见表,6.1.1 LR分析器的逻辑结构和工作过程,接受(acc): 表示分析成功。此时,分析栈中只剩文法开始符号S和当前读到的输
6、入符号#。即输入符号串已经分析结束。,报错:表示输入串含有错误,此时出现栈顶的某一状态遇到了不该遇到的输入符号。,见表,总控程序也称为驱动程序。,总控程序从左至右扫描输入符号串,并根据当前分析栈中栈顶状态以及当前读到的输入符号按照LR分析表元素所指示的动作完成每一步的分析工作。,3. 总控程序,对所有的LR分析器其总控程序是相同的。,6.1.1 LR分析器的逻辑结构和工作过程,总控程序算法:,输入:输入串w和LR分析表。,输出:若w是句子,得到w的自下而上分析成功,否则输出错误信息。,( LR分析器的工作过程的形式化描述 ),算法:初始化时,初始状态S0在分析栈栈顶,输入串w#的第1个符号读入
7、a中。,6.1.1 LR分析器的逻辑结构和工作过程,6.1.1 LR分析器的逻辑结构和工作过程,例 1 设文法G为:,相应于文法的LR分析表如下表所示。,0. SS,1. SA,2. SB,3. AaAb,4. Ac,5. BaBb,6. Bd,6.1.1 LR分析器的逻辑结构和工作过程,返回,返回,返回,对文法句子aacbb#的LR分析过程如下:,初始化时,初始状态 0 和句子的左界符 #在分析栈栈顶,读入输入串 aacbb# 的第1个符号a 。,6.1.1 LR分析器的逻辑结构和工作过程,6.1.1 LR分析器的逻辑结构和工作过程,6.1.2 LR(0)分析法,LR(0)分析就是在分析的每
8、一步,只需根据当前栈顶状态而不必向前查看输入符号就能确定应采取的分析动作。,LR分析器的关键部分是分析表的构造。,构造LR分析表的基本思想是:,从给定的上下文无关文法直接构造识别文法所有规范句型活前缀的DFA,然后再将DFA转换成一张LR分析表。,6.1.2 LR(0)分析法,文法规范句型的活前缀,1. 字符串的前缀是指字符串的任意首部。,例如,字符串abc的前缀有,a,ab,abc。,2. 规范句型活前缀是指规范句型的前缀,这种前缀不包含句柄右边的任何符号。,注意,活前缀可以是一个或者是若干个规范句型的前缀。,6.1.2 LR(0)分析法,6.1.2 LR(0)分析法,由前例,对输入串aac
9、bb#的归约过程,可以看出,当所分析的输入串没有语法错误时,则在分析的每一步,分析栈中已移进一归约的全部文法符号与余留的输入符号串合起来,就是所给文法的一个规范句型。,6.1.2 LR(0)分析法,这也就是说,在LR分析过程中的任何时刻,栈中的文法符号应是某一规范句型的活前缀,这是因为一旦句型句柄在堆栈的顶部形成,就会立即被归约,因此,只要输入串已扫描过的部分保持可归约成一个活前缀,那就意味着所扫描过的部分是正确的。,6.1.2 LR(0)分析法,例如,对前例,文法GS的规范句型aaAbb的句柄是aAb,栈中符号串为aaAb,此句型的活前缀为,a,aa,aaA,aaAb,它们均不含句柄右边符号
10、b。,这样一来,我们对句柄的识别就变成对规范句型活前缀的识别。,6.1.2 LR(0)分析法,那么,如何识别文法规范句型的活前缀呢?由于在分析的每一步分析栈中的全部文法符号是当前规范句型的活前缀,且与当前栈顶状态相关联,因而可以利用有穷自动机去识别所给文法的所有规范句型的活前缀。,LR分析器的工作过程可看成是一个逐步识别所给文法规范句型活前缀的过程。,6.1.2 LR(0)分析法,由此可知,,6.1.2 LR(0)分析法,LR(0)项目,由活前缀定义可知,在一个规范句型的活前缀中,绝不含有句柄右边的任何符号。因此,活前缀与句柄之间的关系有下述三种情况:, 活前缀中已含有句柄的全部符号,表明此时
11、某一规则A的右部符号串已出现在栈顶,其相应的分析动作是用此规则进行归约。如上例中第6步:,6.1.2 LR(0)分析法,6.1.2 LR(0)分析法, 活前缀中只含有句柄的一部分符号,此时意味着形如 A12 规则的右部子串1已出现在栈顶,2正期待着从余留的输入串中进行归约得到。如上例中第5步:, 活前缀中不含有句柄的任何符号,此时意味着期望从余留输入串能看到由某规则 A 的右部 所推出的符号串。如上例中第3步:,6.1.2 LR(0)分析法,6.1.2 LR(0)分析法,为了刻画在分析过程中, 文法的一个规则右部符号串已有多大一部分被识别,我们可在文法中每个规则右部适当位置上加一个圆点来表示。
12、针对上述三种情况,标有圆点的规则分别为:,A,A1 2,A,我们把文法G中右部标有圆点的规则称为G的一个LR(0)项目。,值得注意的是对空规则 A,仅有LR(0)项目A 。,直观上说,一个LR(0)项目指明了对文法规范句型活前缀的不同识别状态,文法G的全部LR(0)项目是构造识别文法所有规范句型活前缀的DFA的基础。,由于不同的LR(0)项目反映了在分析过程中栈顶的不同情况,因此,我们可以根据圆点位置和圆点后是终结符还是非终结符,将一个文法的全部LR(0)项目进行分类。,6.1.2 LR(0)分析法,6.1.2 LR(0)分析法,LR(0)项目分类如下:,归约项目,移进项目,待约项目,接受项目
13、,6.1.2 LR(0)分析法, 归约项目,形如A,其中(VNVT)*,即圆点在最右端的项目,它表示一个规则的右部已分析完, 句柄已形成,应该按此规则进行归约。, 移进项目,形如A a,其中, (VNVT)* ,即圆点后面为终结符的项目, 它表示期待从输入串中移进一个符号,以待形成句柄。,6.1.2 LR(0)分析法, 待约项目,形如A B,其中, (VNVT) * , B VN*,即圆点后面为非终结符的项目,它表示期待从余留的输入串中进行归约得到B,然后分析A的右部。, 接受项目,形如SS ,其中S为文法的开始符号,即文法开始符号的归约项目。 S为左部的规则仅只有一个,它是归约项目的特殊情况
14、,它表示整个句子已经分析完毕,可以接受。,6.1.2 LR(0)分析法,构造识别文法所有规范句型活前缀DFA的方法 :,在这个项目集中,所有的LR(0)项目识别的活前缀是相同的,我们可以利用闭包函数(CLOSURE)来求DFA一个状态的项目集。,对于构成识别文法规范句型活前缀DFA的每一个状态是由若干个LR(0)项目所组成的集合,称为LR(0)项目集 ,,4.5.2 LR(0)分析法,为了使“接受”项目唯一,我们总对文法G进行拓广。假定文法G的开始符号为S,在文法G中引入一个新的开始符号S,并加进一个新的规则S S,从而得到文法G的拓广文法G。,(1) 定义闭包函数,设I是拓广文法G的一个LR
15、(0)项目集,定义和构造I的闭包CLOSURE(I)如下:,6.1.2 LR(0)分析法,I中的任何一个项目都属于 CLOSURE(I)。,(b) 若A B属于CLOSURE(I), 则每一形如 B 的项目也属于CLOSURE(I)。,(c) 重复(b)直到CLOSURE(I)不再增 大为止。,6.1.2 LR(0)分析法,例如,对例1中的文法,令I=SS ,则,即为初态的项目集I0,CLOSURE(I),SS,,SA,,SB,,AaAb,Ac,,BaBb,,Bd,=,有了初态的项目集之后,如何求出对于文法符号X可能转移到的下一个状态的项目集?,6.1.2 LR(0)分析法,(2) 定义状态转
16、移函数GO,设I是拓展文法G的任意一个项目集,X为一文法符号,定义状态转移函数GO(I,X)如下:,GO( I , X ),=,CLOSURE( J ),J,=,AaX | AaX I,6.1.2 LR(0)分析法,例如:初态的项目集,GO(I0 , S ),=,CLOSURE(SS ),=, SS ,=,I1,GO(I0 , a ),=,CLOSURE(AaAb , BaBb),=, AaAb , AaAb , Ac BaBb , BaBb , Bd ,=,I4, SS , SA , SB, AaAb ,Ac ,BaBb , Bd ,I0=,6.1.2 LR(0)分析法,通过闭包函数(CLO
17、SURE)和状态转移函数(GO)很容易构造出文法 G 的识别文法规范句型活前缀的DFA。,6.1.2 LR(0)分析法,(3) 构造识别文法规范句型活前缀DFA的方法 :,(a) 求CLOSURESS,得到初态项目集。,(b) 对初态项目集或其它已构造的项目集,应用状态转移函数GO(I,X)求出新的项目集(后继状态)。,6.1.2 LR(0)分析法,(d) 转移函数GO建立状态之间的连结关系。,对前例中的文法,构造识别文法所有规范句型活前缀的DFA如下图所示:,(c) 重复(b)直到不出现新的项目集(新状态)为止。,6.1.2 LR(0)分析法,识别文法G 活前缀的DFA,6.1.2 LR(0
18、)分析法,识别文法G 活前缀的DFA,6.1.2 LR(0)分析法,注意,DFA中的每一个状态都是终态,当M到达它们时,识别出某规范句型的一个活前缀,对那些只含归约项目的项目集,如I2、I3、I5 、 I6、I8、I10,当M到达这些状态时,表示已识别出一个句柄,这些状态称为句柄识别态。,当M处于状态I1时,M识别的活前缀为S,表示输入串已成功分析完毕,用SS进行最后一次归约,称状态为接受状态。,6.1.2 LR(0)分析法,构成识别一个文法活前缀的DFA的状态(项目集)的全体称为这个文法的LR(0)项目集规范族。,(4) LR(0)分析表的构造 :,若一个文法G的拓广文法G的LR(0)项目集
19、规范族中的每个项目集不存在移进项目和归约项目同时并存或多个归约项目同时并存,则称G为LR(0)文法。,6.1.2 LR(0)分析法,识别文法G 活前缀的DFA,6.1.2 LR(0)分析法,对LR(0)文法,构造LR(0)分析表的算法如下:,输入:识别LR(0)文法G规范句型活前缀的DFA,输出:文法G的LR(0)分析表,方法:用整数 0, 1, 2, ,n 分别表示状态 I0, I1, I2 , In, 令包含项目SS 的集合 Ik 的下标为分析器的初始状态。,6.1.2 LR(0)分析法,若项目Ax属于 Ik, 且转换函数 GO(Ik , x)=Ii , 当 x 为终结符时,则置ACTIO
20、Nk, x=Si。,2. 若GO(Ik , A)=Ij , A为非终结符,则置GOTOk, A=j。,见图,见图,见表,见表,6.1.2 LR(0)分析法,3. 若项目A属于Ik ,则对任何终 结符和结束符#(统一记为a)则置 ACTIONk, x=rj (假定A为文法的第j条规则),见图,见表,6.1.2 LR(0)分析法,5. 分析表中凡不能用规则1至4填入信息的元素均置为“出错标志”,为了 分析表的清晰,仅用空白表示出错标志。,4. 若项目SS 属于Ik,则置 ACTIONk, #=acc。,见图,见表,见表,6.1.2 LR(0)分析法,根据上述方法构造的LR(0)分析表不含多重定义时
21、,称这样的分析表为LR(0)分析表,能构造LR(0)分析表的文法称为LR(0)文法。,6.1.2 LR(0)分析法,例2 考虑文法GS:,(1) 构造识别文法规范句型活前缀的DFA,(2) 判断该文法是否LR(0)文法,若是,请构造LR(0)分析表,若不是,请说 明理由。,S(S) | a,6.1.2 LR(0)分析法,分 析:,首先将文法拓广,并给出每条规则编号,0. SS,1. S (S),2. S a,识别文法规范句型活前缀的DFA如下图所示 :,6.1.2 LR(0)分析法,I0:,I2:,I1: SS,S,a,I3: S a,(,(,a,I4: S (S),),I5: S (S),S
22、,识别活前缀的DFA,6.1.2 LR(0)分析法,因为它的6个LR(0)项目集中均不含有冲突项目,即不存在移进项目和归约项目并存或多个归约项目并存的情况。该文法是LR(0)文法。,其LR(0)分析表如下:,6.1.2 LR(0)分析法,文法GS的LR(0)分析表,0,S3 S2,1,1,acc,2,3,4,5,S3 S2,r2 r2 r2 r2,S5,r1 r1 r1 r1,4,见图,6.1.2 LR(0)分析法,由上述构造过程可以看出,LR(0)分析器的特点是不需要向前查看输入符号就能归约,即当栈顶形成句柄,不管下一个输入符号是什么,都可以立即进行归约而不会发生错误。,本节完,6.1.2 LR(0)分析法,识别活前缀的DFA,见表,I0:,I2:,I1: SS,S,a,I3: S a,(,(,a,I4: S (S),),I5: S (S),S,返回,返回,返回,识别文法G活前缀的DFA,0,1,2,3,4,5,S4 S5 S6,acc,S4 S5 S6,r1 r1 r1 r1 r1,r2 r2 r2 r2 r2,r4 r4 r4 r4 r4,1 2 3,7 9,文法GS的LR(0)分析表,返回,返回,返回,6,7,8,9,10,S8,r6 r6 r6 r6 r6,S10,r3 r3 r3 r3 r3,r5 r5 r5 r5 r5,返回,