编译原理 第六章 LR分析法

合集下载

编译原理教案-lr分析

编译原理教案-lr分析

编译原理教案LR 分析一、教学目标1. 理解LR 分析法的概念和原理。

2. 学会使用LR 分析法进行语法分析。

3. 掌握LR 分析器的构造和应用。

二、教学内容1. LR 分析法的基本概念1.1 LR 分析法的定义1.2 LR 分析法的分类1.3 LR 分析法的特点2. LR 分析器的构造2.1 LR 分析器的组成2.2 LR 分析器的构建步骤2.3 LR 分析器的优化方法3. LR 分析法的应用3.1 LR 分析法在编译器设计中的应用3.2 LR 分析法在其他领域的应用三、教学方法1. 讲授法:讲解LR 分析法的基本概念、原理和构造方法。

2. 案例分析法:分析实际应用中的LR 分析法。

3. 实践操作法:引导学生动手构建LR 分析器。

四、教学准备1. 教案、PPT 及相关资料。

2. 编程环境(如Lex、Yacc 等)。

五、教学过程1. 引入:介绍LR 分析法在编译器设计中的重要性。

2. 讲解:讲解LR 分析法的基本概念、原理和构造方法。

3. 案例分析:分析实际应用中的LR 分析法。

4. 实践操作:引导学生动手构建LR 分析器。

教学评价:通过课后作业、课堂讨论和实践操作等方式评估学生对LR 分析法的理解和应用能力。

六、教学案例:LR 分析法的应用实例6.1 实例介绍:分析一个简单的算术表达式语法。

6.2 构建LR 分析器:使用编程工具(如Lex、Yacc)构建LR 分析器。

6.3 分析过程:演示LR 分析器如何分析输入的算术表达式。

七、LR 分析器的优化7.1 优化概念:介绍LR 分析器优化的目的和方法。

7.2 减少动作表的大小:通过合并相同或相似的产生式来简化动作表。

7.3 优化算法:介绍常用的LR 分析器优化算法,如LALR(1)、SLR(1) 等。

八、高级LR 分析技术8.1 LALR(1) 分析器:介绍LALR(1) 分析器的构建方法和特点。

8.2 LR(1) 与LR(0) 的比较:分析两种LR 分析器的优缺点。

编译原理LR分析(主要是LR(0)分析)

编译原理LR分析(主要是LR(0)分析)

编译原理LR分析(主要是LR(0)分析)⼀、LR分析的基本原理1、LR分析的基本思想LR⽅法的基本思想就是,在规范归约的过程中,⼀⽅⾯要记住已移进和归约出的整个字符串,也就是说要记住历史;⼀⽅⾯能够根据所⽤的产⽣式的推测未来可能碰到的输⼊符号,也就是说能够对未来进⾏展望。

这样,当⼀串貌似句柄的字符串出现在分析栈的顶部时,我们希望能够根据历史和展望以及现实的输⼊符号这三部分的材料,决定出现在栈顶的这⼀串符号是否就是我们要找的句柄。

2、LR分析器的构成采⽤下推⾃动机这种数据模型。

包括以下⼏个部分:1.输⼊带2.分析栈:包括状态栈和⽂法符号栈两部分。

(s0,#)为分析开始前预先放在栈⾥的初始状态和句⼦括号。

3.LR 分析表:包括动作表和状态转移表两张表。

3、LR分析表是LR分析器的核⼼部分⼀张LR分析表包括两部分:动作表(ACTION)和状态转换表(GOTO)。

它们都是⼆维数组。

ACTION[s,a]规定了当状态s⾯临输⼊符号a时应采取什么动作(移进、归约、接受和报错),⽽GOTO[s,X]规定了当状态s⾯对⽂法符号X(终结符或⾮终结符)时的下⼀状态是什么。

显然,GOTO[s,X]定义了⼀个以⽂法符号为字母表的DFA。

不同的 LR 分析法构造LR分析表的⽅法都不同,由此产⽣了不同的LR分析法。

4、LR分析算法置ip指向输⼊串w的第⼀个符号 令Si为栈顶状态 a是ip指向的符号(当前输⼊符号) BEGIN(重复开始) IF ACTION[Si,a]=Sj THENBEGINPUSH j,a (进栈) ip前进(指向下⼀输⼊符号) END ELSEIF ACTION[Si,a]=rj(若第j条产⽣式为A→β) THEN BEGIN pop|β| 项 若当前栈顶状态为Sk pushGOTO[Sk,A] 和A(进栈) END ELSEIF ACTION[Si,a]=acc THEN return (成功) ELSE error END. (重复结束)⼆、LR(0)分析器1、可归前缀与规范句型的活前缀⽂法G[S]:(1) S → aAcBe[1](2) A → b[2](3) A → Ab[3](4) B → d[4]S ÞaAcBe[1]ÞaAcd[4]e[1]ÞaAb[3]cd[4]e[1]Þab[2]b[3]cd[4]e[1]每次归约句型的前部分依次为:ab[2]aAb[3]aAcd[4]aAcBe[1]规范句型的这种前部分符号串称为可归前缀我们把形成可归前缀之前包括可归前缀在内的所有规范句型的前缀都称为活前缀(活前缀就是可归前缀的前缀)如下:e,a,abe ,a,aA,aAbe ,a,aA,aAc,aAcde ,a,aA,aAc,aAcB,aAcBe三、LR分析(⼀)LR分析构造识别活前缀的有穷⾃动机项⽬(item):在每个产⽣式的右部适当位置添加⼀个圆点构成项⽬。

编译原理 第6章-LR分析-小结资料

编译原理 第6章-LR分析-小结资料
LR(0)项目集规范族; 对LR(1)或 LALR(1)分析表,构造 LR(1)项目集规范族。
Compiler Construction Principles
(2)构造识别文法规范句型活前缀的DFA。 (3)将DFA转换成相应的LR分析表。
四种分析表的构造基本相同,仅对含 归约项目的项目集构造分析表元素不同。
构造该文法的LR(0)项目集族和转换函 数如下图所示。
I0:
S′→·S S →·(S)
S
S →·
(
S
I2:SS S
→(·S) →·(S) →·
(
I1: S'→S.
I3: S →(S·) )
I4: S →(S)·
0. S' →S 1. S →(S) 2. S →ε
见表
该文法不是LR(0)文法。因为I0,I2中 含有移进—归约的冲突。
)
I6: S→S(S·), )/(
2. S → ε S →· , )/(
S →S·(S), )/(
Compiler Construction Principles
所有的LR(1)项目集中没有移进—归约 的冲突,所以该文法为LR(1)文法 或该文法为SLR(1)文法, 任何SLR(1)文 法都是LR(1)或LALR(1)文法
3 S2 S4
4 r1 r1 r1
FOLLOW(S) ={ #, (, ) }
Compiler Construction Principles
步骤 栈中状态
10
2 01
3 012
4 0123
5 01232
6
012323
7 0123234
8 0123
9 01234

编译原理 第06章_LR分析法(3)

编译原理 第06章_LR分析法(3)

的。将同心集合并为: I5,12: L→i•, =/# I4,11: L→*•R, =/# R→•L, =/# I7,13: L→*R•, =/# L→•*R, =/# I8,10: R→L•, =/# L→•i, =/#
6.4 LALR(1)分析法
我们看到合并同心集后的项目集其核心 部分不变,仅搜索符合并。对合并同心集后 的项目集的转换函数为GO(I,X)自身的合并, 这是因为相同的心之转换函数仍属同心集, 例如: GO(I4,11, i)=GO(I4, i)∪GO(I11, i)= I5,12 GO(I4,11, R)=GO(I4, R)∪GO(I11, R)= I7,13 GO(I4,11, *)=GO(I4, *)∪GO(I11, *)= I4,11
0. S' →S 1. S →L=R
2. S →R 3. L →*R
4. L →i 5. R →L
6.4 LALR(1)分析法
3. 若LALR(1)项目集族中不存在归约一 归约冲突,则该文法是LALR(1)文法。对例 中的文法,由于合并同心集后不存在归约— 归约冲突,所以该文法是LALR(1)文法。
S'→•S,# I0: R→•L,# S→•L=R,# L I :R→L•,# L→• * R,# S→•R,# 10 L I2:S→L•=R,# L→•i,# L→•*R,=/# L R→L•,# * i L→•i,=/# i R I11: L→*•R,# R→•L,# I3: S→R•,# I12: L→i•,# R→•L,# * i L→• * R,# R L→ * •R,=/# I4: I13:L→*R•,# L→•i,# R→•L,=/# I5: L→i•,=/# L→•*R,=/# R * i I7: L→*R•,=/# L→•i,=/#

编译原理-清华大学-第6章-LR分析法(2+1,2+1)

编译原理-清华大学-第6章-LR分析法(2+1,2+1)
出错。
r1 5
三、LR分析算法
状态/符号
Sm Xm Sm-1Xm-1 …… …… …… S1 X1
0#
输入缓冲区 a1…ai…an#
LR主控 程序
动作表 转移表 action goto
产生式 序列
分析表
置ip指向输入串w的第一个符号;
状态0和符号#分别进分析栈;
令S为状态栈的栈顶状态;a是ip指向的符号;
作为DFA的初始状态。
21
3)定义状态转换函数GO (产生新的项目集)
GO(I,X)定义为CLOSURE(J),其中I,J都是项目集, X(VN∪VT), J={AX•|当A•XI}。
J 的构造方法类似于词法分析的 MOVE函数
GO(I,X)类似于 CLOSURE( MOVE(I,X))
4)构造LR(0)项目集规范族的算法
2、S′S• 称为句子识别态或接受项目;
3、转换关系:项目i为XX1…Xi-1•Xi…Xn, 项目j为XX1…Xi • Xi+1…Xn, 则从项目i画一弧线射向j,标记为Xi;
4、若项目i为X•A,其中A是非终结符,则从i项目画 弧射向所有A•的项目,V*
5、规约项目为终态用双圈表示,双圈外有*号者为接受态 18
(最左规约,规范规约)
ab[2]b[3]cd[4]e[1]
(用[2]归约)
<= aAb[3]cd[4]e[1]
<= aAcd[4]e[1] <= aAcBe[1]
(用[3]归约) (用[4]归约) (用[1]归约)
<= S
其中<=表示规约
问题:在归约过程中,那些是可归前缀?
13
4、活前缀:G=(Vn,Vt,P,S'), 若有规范推导 S′* αAωαβω,

第六章编译原理

第六章编译原理

1. 分析栈中的文法符号+栈外余留输入串 规范句型 2. 规约实质:不断进栈,等待栈顶形成当前句型的句柄 3 句柄一定是产生式的右部候选式
关键:找出当前句型的“可归约串x”
最左素短语 算符优先分析法
句柄
L(R)文法 如何找当前句柄归约?
1.
引入一个新的状态栈来表示符号栈中的符 号目前状态 用LR分析表来表示不同状态下对于各输入 符号应采取的动作
对符号串#a,b#的分析过程 步骤 1 2 3 4 5 6 状态栈 符号栈 余留符号 产生式 ACTION/GOTO
S0
S0 S3 S0 S2 S0 S2 S5
#
#a #B #B,
a,b#
,b# ,b# b# # # # # B→b A→B A→B,A B→a
S3
γ S5 S4 γ γ γ
4, 2 2 ,6 3 ,2
1
2
3
8
2 9
3 3 10
6
7 8 9 10 11
6.4 SLR 分析表的构造
为了解决LR(0)中一个项目集合中存在“移进—归约”和“归 约—归约“冲突,而产生的。
例 6.2 P102 的LR(0) 分析表
解决冲突的办法: 对于一个状态Si的项目集: Si={A→α △β ,B→γ △,C→δ △} 其中, α , γ , δ ∈V* First(β )∈VT 存在“移进—归约” “归约—归约”冲突 若Follow(B)∩Follow(C)∩First(β )=ф 则 当输入符号为a时,(a∈VT∪’#’)
则C→△γ ∈CLOSURE(I) b. 重复b,直到CLOSURE(I)不再增加为止.
论述: 1 .把G[
S
]第一个项目 S →△S作为初始状态项目集的核

编译原理-LR分析法(附源码)

LR分析实验报告一、实验项目名称LR分析二、实验目的掌握用LR 分析法对表达式文法进行自底向上语法分析的算法,加深对LR 分析法的三、实验环境Windows 10Microsoft Visual Studio 2015四、实验内容本次实验的SLR(1)文法为表达式拓广文法:(0)S’→E(1)E→E+T(2)E→T(3)T→T*F(4)T→F(5)F→(E)(6)F→i改进后的SLR(1)分析表如教材142 页图7.8。

编写识别表达式拓广文法的合法句子的SLR(1)分析程序,对输入的任意符号串,给出分析过程及分析结果。

分析过程要求输出步骤、状态栈、符号栈、输入串和语法动作。

如果该符号串不是表达式文法的合法句子,要给出尽量详细的错误提示。

五、实验步骤将改进后的SLR(1)分析表存到一个数组中,本次实验的文法是写在程序中的,不可改变,这种方法降低了实验代码的难度。

六、源程序清单、测试数据、结果#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>char*action[12][6] = { /*ACTION*/"S5#",NULL,NULL,"S4#",NULL,NULL,NULL,"S6#",NULL,NULL,NULL,"acc",NULL,"r2#","S7#",NULL,"r2#","r2#",NULL,"r4#","r4#",NULL,"r4#","r4#","S5#",NULL,NULL,"S4#",NULL,NULL,NULL,"r6#","r6#",NULL,"r6#","r6#","S5#",NULL,NULL,"S4#",NULL,NULL,"S5#",NULL,NULL,"S4#",NULL,NULL,NULL,"S6#",NULL,NULL,"S11#",NULL,NULL,"r1#","S7#",NULL,"r1#","r1#",NULL,"r3#","r3#",NULL,"r3#","r3#",NULL,"r5#","r5#",NULL,"r5#","r5#", };int goto1[12][3] = {/*GOTO*/1,2,3,0,0,0,0,0,0,0,0,0,8,2,3,0,0,0,0,9,3,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0 };char vt[6] = { 'i','+','(',')','*','#' };/*存放终结符*/char vn[3] = { 'E','T','F', };/*存放非终结符*/char *LR[7] = { "S->E#","E->E+T#","E->T#","T->T*F#","T->F#","F->(E)","F->i" };/*存放产生式*/int a[10];char b[10], c[10], c1;int top1, top2, top3, top, m, n;void lr() {int g, h, i, j, k, l, p, y, z, count;char x, copy[10], copy1[10];top1 = 0; top2 = 0; top3 = 0; top = 0;a[0] = 0; y = a[0]; b[0] = '#';count = 0;z = 0;printf("----------------请输入表达式(以#结尾)--------------\n");do {scanf("%c", &c1);c[top3] = c1;top3 = top3 + 1;} while (c1 != '#');printf("步骤\t状态栈\t\t符号栈\t\t输入串\t\tACTION\tGOTO\n");do {y = z; m = 0; n = 0; /*y,z指向状态栈栈顶*/g = top; j = 0; k = 0;x = c[top];count++;printf("%d\t", count);while (m <= top1) {/*输出状态栈*/printf("%d", a[m]);m = m + 1;}printf("\t\t");while (n <= top2) {/*输出符号栈*/ printf("%c", b[n]); n = n + 1; }printf("\t\t");while (g <= top3) {/*输出输入串*/ printf("%c", c[g]);g = g + 1;}printf("\t\t");while (x != vt[j] && j <= 6)j++;if (j == 6 && x != vt[j]){printf("error\n");return;}if (action[y][j] == NULL) {printf("error\n");return;}elsestrcpy(copy, action[y][j]);if (copy[0] == 'S'){/*处理移进*/z = copy[1] - '0';top1 = top1 + 1;top2 = top2 + 1;a[top1] = z;b[top2] = x;top = top + 1;i = 0;while (copy[i] != '#'){printf("%c", copy[i]); i++;}printf("\n");}if (copy[0] == 'r'){/*处理归约*/i = 0; while (copy[i] != '#'){printf("%c", copy[i]);i++;}h = copy[1] - '0';strcpy(copy1, LR[h]);while (copy1[0] != vn[k])k++;l = strlen(LR[h]) - 4;top1 = top1 - l + 1;top2 = top2 - l + 1;y = a[top1 - 1];p = goto1[y][k];a[top1] = p;b[top2] = copy1[0];z = p;printf("\t");printf("%d\n", p);}}while (action[y][j] != "acc");printf("acc\n");getchar();}七、实验小结和思考实现LR(1)文法很困难,我是直接将文法写在程序中直接输出分析表,而让程序实现对输入符号串的分析,在编程过程中也遇到了很多困难,如对某些终结符的动作或是规约函数的实现,最后通过上网查找参考资料,都得到了解决。

编译原理--语法分析之LR分析法的简单实现

编译原理--语法分析之LR分析法的简单实现清晰记得本次实验在推了两次项⽬集规范簇之后,发现⽂档中给出的⽂法有错误,联系⽼师得到改正后,遂顺利完成。

简单记录⼀下本次实验的经历,留作以后备⽤,若有错误之处,还请路过的博友不吝赐教。

实验设计⽬标构造LR(1)分析程序,利⽤它进⾏语法分析,判断给出的符号串是否为该⽂法识别的句⼦。

实验原理整体思路:在总控程序的控制下,从左到右扫描输⼊符号串,根据状态栈中的栈顶状态、符号栈中的栈顶字符和⽂法及当前输⼊符号,按分析表完成相应的分析⼯作。

LR分析器由三个部分组成:总控程序,也可以称为驱动程序。

对所有的LR分析器总控程序都是相同的。

分析表或分析函数,不同的⽂法分析表将不同,同⼀个⽂法采⽤的LR分析器不同时,分析表将不同,分析表⼜可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可⽤⼆维数组表⽰。

分析栈,包括⽂法符号栈和相应的状态栈,它们均是先进后出栈。

分析器的动作就是由栈顶状态和当前输⼊符号所决定。

GOTO[i,X]=j表⽰,规定当栈顶状态为i,遇到当前⽂法符号为X时应转向状态j,X为⾮终结符。

ACTION[i,a]规定了栈顶状态为i时,遇到输⼊符号a应执⾏的动作有四种可能:1. 移进:action[i,a]= S j:状态 j 移⼊到状态栈,把 a 移⼊到⽂法符号栈,其中 i , j 表⽰状态号。

2. 归约:action[i,a]=R k:当在栈顶形成句柄时,则归约为相应的⾮终结符A,即⽂法中有A->B的产⽣式,若B的长度为R(即|B|=R),则从状态栈和⽂法符号栈中⾃顶向下去掉R个符号,即栈指针SP减去R,并把A移⼊⽂法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。

3. 接收Acc:当归约到⽂法符号栈中只剩⽂法的开始符号S时,并且输⼊符号串已结束即当前输⼊符是'#',则为分析成功。

4. 报错:当遇到状态栈顶为某⼀状态下出现不该遇到的⽂法符号时,则报错,说明输⼊端不是该⽂法能接受的符号串。

编译原理 第6章课件

第6章LR分析法教学要求:1.掌握:活前缀的概念,2.理解:LR (0 ), SLR (1), LR(1)和LALR(1)分析过程,各类分析表的构造3.了解:二义性文法在LR 分析中的应用目录 6.1 LR 分析概述6.2 LR (0) 分析6.3 SLR(1) 分析6.4 LR (1)分析6.5 LALR(1)分析6.6 二义性文法在LR 分析中的应用强调算符之间的优先关系的唯一性,这使得它的适应面比较窄算法在发现最左素短语的尾时,需要回头寻找对应的头LR(k)分析法可分析LR(k)文法产生的语言– L :从左到右扫描输入符号,– R :最右推导对应的最左归约(反序完成最右推导)– k :向前读入k 个符号,以便确定归约用的产生式LR 分析法正是给出一种能根据当前分析栈中的符号串和向右顺序查看输入串的K 个( K ≥0)符号就可唯一地确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能唯一地确定句柄。

LR 分析法的归约过程是规范推导的逆过程,所以LR 分析过程是一种规范归约过程。

6.1 LR分析概述L:从左到右扫描输入串R : 最右推导的逆过程分析器模型和分析算法• LR分析特征讨论说明:S[i] 为状态栈, X[i]为文法符号栈。

状态转换表用GOTO[S i ,X]= S j 表示,规定当栈顶状态为S i ,遇到当前文法符号为X 时应转向状态S j ,X 为终结符号或非终结符号。

ACTION[S i ,a]规定了栈顶状态为S i ,遇到输入符号为a 应执行的动作。

动作有如下四种: 移进: S j = GOTO[S i ,a]移入状态栈,a 移入到文法符号栈。

归约: 栈顶形成句柄为β时,文法有产生式 A →β,若 β的长度为r ,则从两个栈顶去掉r 个符号,把A 移入符号栈,S j =GOTO[S i ,A] 移入状态栈。

接受acc 报错LR 分析算法 置ip 指向输入串w 的第一个符号 令S 为栈顶状态 a 是ip 指向的符号 重复 begin if ACTION[S,a]=S j then begin PUSH j,a(进栈)ip 前进(指向下一输入符号) end else if ACTION[S,a]=r j (第j 条产生式为A →β)then beginpop |β| 项令当前栈顶状态为S’push GOTO[S’,A]和A(进栈)end else if ACTION[s,a]=accthen return (成功)else errorend.重复LR 文法:对于一个上下文无关文法(Context Free Grammar)-cfg 文法, 如果能 够构造一张 LR 分析表, 使得它的每一个入口均是唯一的(Sj,rj,acc,空白), 则称该 cfg 是LR 文法.LR分析:特征:规范的符号栈中的符号是规范句型的前缀,且不含句柄以后的任何符号(活前缀)分析决策依据:栈顶状态和现行输入符号.• 四种技术 LR(0) SLR(1) LR(1) LALR(1)6.2 LR(0) 分析LR(0)文法--------能力最弱,理论上最重要:存在FA 识别活前缀识别活前缀的DFA 如何构造(LR(0)项目集规范族的构造)LR(0)分析表的构造一、可归约前缀和子前缀最右推导过程(每条产生式尾部加上编号)S ⇒aAcBe[1] ⇒aAcd[4]e[1] ⇒aAb[3]cd[4]e[1]⇒ab[2]b[3]cd[4]e[1]归约时在栈里的句型的前缀 归约前可在栈里的规范句型(不含句柄) 的前缀 ab[2] aaAb[3] a,aAaAcd[4] a,aA,aAcaAcBe[1] a,aA,aAc,aAcB可归约前 子前缀活前缀(viable prefixes )G=(Vn,Vt,P,S),若有S’ ⇒ αA ω ⇒ αβω,γ是αβ的前缀,则称是文法G 的活 前缀. 其中S’是对原文法扩充(S’→S)增加的非终结符.? 为使S’不出现在任何产生式的右部.活前缀是规范句型(右句型)的前缀,但不超过句柄移进归约分析的栈中出现的内容加上余留输入构成规范句型二、识别活前缀的FA启示:可以把非终结符号和终结符号都看成一个FA 的输入符号,每把一个符号 进栈时看成已识别过了该符号,而状态进行转换,当识别到可归约前缀 时,相当于在栈顶形成了句柄,则认为达到了识别句柄的终态。

编译原理LR分析法

编译原理LR分析法
编译原理是研究如何将高级语言程序转换成等价的低级机器语言程序的学科, LR分析法是其中一种重要的语法分析方法。
何为编译原理
编译原理是计算机科学的一个分支,研究将高级语言程序转换为等价的底层机器代码的过程。它涉及词法分析、 语法分析、语义分析、优化和代码生成等多个阶段。
LR分析法的概述
LR分析法的步骤
1
1. 构建LR项集族
基于文法的产生式,生成LR(0)项集族,
2. 构建LR分析表
2
包括起始项集和其它项集。
根据LR项集族和文法的终结符和非终结
符,构建LR分析表,包括移进、规约和
接受操作。Leabharlann 33. 进行语法分析
使用构建的LR分析表,对输入的符号串 进行逐步解析,直到接受或出错。
构建LR分析表
项集的闭包
通过对项集进行闭包运算,计算 出项集中的所有项。
项集的转移
根据项目集的状态和接收符号, 进行项集的状态转移。
规约项的处理
确定规约的产生式和规约动作, 构建规约表。
LR分析表的使用
使用构建的LR分析表,可进行能够解析输入符号串的自底向上语法分析。它 根据输入符号和栈顶符号,执行移进、规约或接受操作来推导和验证语法结 构。
优缺点和应用
优点
具有广泛适用性,支持大多 数上下文无关文法。解析效 率高,能够快速生成语法树。
缺点
对于某些复杂的语法,可能 需要构建大型的分析表。编 写LR分析器的难度较高。
应用
LR分析法被广泛用于编译器 设计、解析器生成器和语法 分析工具的开发中。
LR分析法是一种自底向上的语法分析方法,用于构建一个确定性的有限状态 自动机(LR自动机)以解析各种语法结构。它具有广泛的应用,包括编译器 设计和语法分析工具的开发。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第六章 LR分析法在第5章中已经讨论过,自底向上分析方法是一种移进归约过程,当分析的栈顶符号串形成句柄时就采取归约动作,因而自底向上分析法的关键问题是分析过程中如何确定句柄。

LR分析法正是给出一种能根据当前分析栈中的符号串(通常以状态表示)和向右顺序查看输入串的K个(K≥0)符号就可唯一地确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能唯一地确定句柄。

LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范归约过程。

LR(K)分析方法是1965年Knuth先生提出的,括号中的K表示向右查看输入串符号的个数。

这种方法比起自顶向下的LL(K)分析方法和自底向上的优先分析方法对文法的限制要少得多,也就是说对于大多数用无二义性上下文无关的文法描述的语言都可以用相应的LR分析器进行识别,而且这种方法还具有分析速度快,能准确、即时地指出出错位置。

但是,由于它的主要缺点是对于一个实用语言文法的分析器的构造工作量相当大,K愈大构造愈复杂,实现相当困难。

因此,目前对于真正实用的编译程序,所采用的LR分析器都是借助于美国Bell实验室1974年推出的“一个编译器的编译器—YACC”来实现的。

它能接受一个用BNF描述的满足LALR(1)的上下文无关文法并将自动构造出LALR(1)语法分析器。

本章将主要介绍LR分析的基本思想和当K≤1时LR分析器的基本构造原理和方法。

其中LR (0)分析器是在分析过程中不需向右查看输入符号,因而它对文法的限制较大,对绝大多数高级语言的语法分析器是不能适用的,然而,它是构造其它LR类分析器的基础。

当K=1是,已能满足当前绝大多数高级语言编译程序的需要。

其中SLR(1)和LALR(1)分别是LR(0)和LR(1)的一种改进。

本章重点:LR(0)、SLR(1)第一节 LR分析概述(一)LR(1)分析器的逻辑结构及工作过程Array在逻辑上,一个LR(1)分析器的结构如图6-1-1(a)所示。

它有一个输入符号串,一个下推分析栈,以及一个总控程序和分析表。

LR(1)分析器在总控程序的控制下自左至右扫视输入串中的各个符号,并根据当前分析栈中所存放之文法符号的状况及正扫描之输入符号,按分析表的指示完成相应的分析动作。

在分析的每一时刻,分析栈中记录了迄今为止的分析历程。

因此,为了方便,对于分析过程的每一步,我们可将迄今的分析历程用一种“状态”来刻画,并将此状态名置于分析栈的栈顶,如图6-1-1(b)所示。

分析刚开始时,栈中仅有一个句子的左界符号#,此时分析器处于初始状态S O。

此S O不仅刻画了分析栈中当前仅有一个符号#这一事实,而且还预示着:即将扫视的输入符号,应正好是可作为句子首符号的那些符号。

类似地,状态S1刻画了分析栈中已存有符号#X1的情况,S2刻画了栈中存有符号串 # X1X2的情况,…,栈顶状态S m刻出了栈中已存有符号串 # X1X2…X m,等等。

此外,根据分析栈栈顶状态,还可对当前可能遇到的输入符号进行预测。

例如,对于前面所述的文法G[E],设分析栈中已移进和归约出的符号串为 # E+T 时的栈顶状态为S i,则S i不仅表征了迄今所扫描过的输入符号业已被归约成# E+T,而且由S i还可作这样的预测:若输入符号串无语法错误,则当前可遇到的输入符号,仅能是(+,*,),或#。

显然,对于上述栈顶状态S i,若当前所扫视到的符号为*,则应将*移入栈中;当扫视到的符号为+、)或#时,则应将符号串E+T归约为E;若扫视到的不是上述四种符号之一,则应按语法错误处理。

由此可见,知道了栈顶状态S m和正扫视到的输入符号a i,就知道了当前所需的全部有用信息,从而也就可唯一地确定当前分析器所应完成的动作。

所以,在具体实现时,并不需要将已归约出的文法符号串也记入分析栈中。

作为LR(1)分析器核心的分析表由两个子表组成:其一是分析动作表,另一个为状态转换表,分别如图6-1-2(a)和6-1-2(b)所示。

其中:S1,S2,…S n为分析器的各个状态;a1,a2,…,a e 为文法的全部终结符号或句子的界符;X1,X2,…X为文法字汇表中的全部文法符号。

分析表中的每一元素ACTION[S m,a i]指明,当栈顶状态为S m且扫视到的输入符号为a i时应完成的动作。

状态转移表中的元素GOTO[S m,X i]则指明,当栈顶状态为S m且面临文法符号Xi时所应转移到的下一状态。

图6-1-2(a)分析动作表图6-1-2(b)状态转移表LR(1)分析器在总控程序的控制下进行工作,其过程如下(为书写方便,我们将分析栈按顺时针旋转九十度):第一步分析开始时,首先将初始状态S O及句子左界符#推入分析栈中。

第二步则以栈顶的状态及正扫视的输入符号ai组成符号对(S m,a i)去查分析动作表,并根据表元ACTION[S m,a i,]的指示完成相应的分析动作。

每一分析表元所规定的动作,仅能是下列四种动作之一:(1)若ACTION[S m,a i]=“移进”,这表明句柄尚未在栈顶部形成,此时正期待继续移进输入符号以形成句柄,故将当前的输入符号推入栈中,即有:然后,以符号对(S m,a i)查状态转移表,设相应的表元GOTO [S m,a i]= S m+1,再将此新的状态(即要转移到的下一状态)推入栈中,则有如下的格局:(2)若m i j j A→X m-r+1 X m-r+2…X m进行归约。

这表明栈顶部的符号串X m-r+1 X m-r+2…X m已是当前句型(相对于非终结符号A)的句柄。

按第j个产生式进行归约,也就是将分析栈从顶向下的r个符号(因为该产生式右部符号串的长度为r)退出,然后再将文法符号A推入栈中,此时分析栈的格局为然后,以(S m -r ,A )查状态转移表,设GOTO [S m -r ,A]=S l ,将此新状态推入栈中,则有如下的格局:(3)若ACTION[S m ,a i ]=“接受”,则表明当前的输入串已被成功地分析完毕,应中止分析器的工作。

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

第三步 重复上述第二步的工作,直到在分析的某一步,栈顶出现“接受状态”或“出错状态”为止。

对于前者,分析栈的最终格局应为:其中,Z 为文法的开始符号,S e 则为使ACTION[S α,#]=“接受”的唯一状态(即接受状态)。

上述所列的三个步骤,实质上是对LR (1)分析器总控程序的一个非形式的描述,它对任何不同的LR (1)分析表都是适用的。

第二节 LR (0)分析LR (0)分析表构造的思想和方法是构造其它LR 分析表的基础。

我们回顾在第5章曾给出例1文法G[S]为:(1)S →aAcBe (2)A →b (3)A →Ab (4)B →d对输入串abbcde#用自底向上归约的方法进行分析,当归约到第5)步时栈中符号串为#aAb ,我们采用了产生式(3)进行归约而不是产生式(2)归约,而在第3)步归约时栈中符号串为#ab 时却用产生式(2)归约,虽然在第2)步和第5)步归约前栈顶号都为b ,但归约所用产生式却不同,其原因在于已分析过的部分在栈中的前缀不同,也就是我们在LR 分析中引进的状态栈的栈顶状态不同,为了说明这个问题我们先在表6-2-1中给出例1文法G[S]的LR(0)分析表,在表6-2-2给出利用LR 分析法对输入串abbcde#的分析过程。

表6-2-1 例1文法的LR(0)分析表表6-2-2 对输入串abbcde#的分析过程一、可归前缀和前缀在表6-2-2分析中,每次归约前句型的前部分依次为:abaAbaAcdaAcBe这正是我们在表6-2-2的分析过程中每次采取归约动作前符号栈中的内容,即分别对应步骤3)、5)、8)10)时符号栈中的符号串,我们把规范句型的这种前部分串称可归前缀。

我们再来分析上述归约时规范句型的前缀:ε,a,abε,a,aA,aAbε,a,aA,aAc,aAcdε,a,aA,aAc,aAcB,aAcBe不难发现前缀a,aA,aAc都不只是某一个规范句型的前缀,因此我们把形成可归前缀之前包括可归前缀在内所有规范句型的前缀都称为活前缀。

活前缀为一个或若干规范句型的前缀。

在规范归约过程中的任何时刻只要已分析过的部分即在符号栈中的符号串均为规范句型的活前缀,则表明输入串的已被分析过的部分是该文法某规范句型的一个正确部分。

二、LR(0)项目集规范族构造1、LR(0)项目在一个规范句型的活前缀中,决不会含有句柄右边的任何符号。

这是因为一旦句型的句柄在栈的顶部形成,将会立即被归约之故。

因此,活前缀与句柄间的关系不外下述三种情况:(1)活前缀中已含有句柄的全部符号(句柄的最右符号即为其最右符号);(2)活前缀中含句柄的一部分符号(句柄开头的若干符号与活前缀最右的若干个符号一致);(3)活前缀中全然不包含句柄的任何符号。

第一种情况表明,此时某一产生式A→β的右部符号串β已出现在栈顶,因此相应的分析动作应当是用此产生式进行归约。

第二种情况意味着形如A→β1β2的产生式的右部子串β1已出现在栈顶,正期待着从余留输入串中看到能由β2推出的符号串。

而第三种情况则意味着,期望从余留输入串中能看到由某一产生式A→α右部,即α所推出的符号串,为了刻画在分析过程中,文法的一个产生式右部符号串已有多大一部分被识别,我们可在该产生式的右部的某处加上一个圆点“·”来指示位置。

例如,对于上述三处情况,标有圆点的产生式分别为A→β·,A→β1·β2以及A→·α。

我们把右部某位置上标有圆点的产生式称为相应文法的一个LR(0)项目,特别对形如A→ε的产生式,相应的LR(0)项目为A→·。

显然,不同的LR(0)项目,反映了分析过程中栈顶的不同情况。

在文法G中的每个产生式的右部适当位置添加一个圆点构成一个LR(0)项目例如,产生式S→aAcBe对应有6个项目。

[0]S→·aAcBe[1] S→a·AcBe[2] S→aA·cBe[3] S→aAc·Be[4] S→aAcB·e[5] S→aAcBe·一个产生式可对应的项目为它的右部符号长度加1。

A→ε的产生式,相应的LR(0)项目为A→·下面我们就会看到,文法的全部LR(0)项目将是构造识别它的所有活前缀的有限自动机的基础。

2、构造识别活前缀的NFA如果把文法的所有产生式的项目都引出,每个项目都为NFA的一个状态。

仍以文法G′为例S′→EE→aA|bBA→cA|dB→cB|d该文法的项目有:1、S′→·E 10、A →d·2、S′→E·11、E →·bB3、E→·aA 12、E →b·B4、E→a·A 13、E →bB·5、E→aA·14、B→·cB6、A→·cA 15、B→c·B7、A→c·A 16、B→c B·8、A→cA·17、B →·d9、A →·d 18、B →d·由于S′仅在第一产生式的左部出现,因此规定项目1为初态,其余每个状态都为活前缀的识别态,圆点在最后的项目为句柄识别态,第一个产生式的句柄识别态为句子识别态。

相关文档
最新文档