分析表的构造(编译原理)
编译原理及编译程序构造

第一章 引论 一、程序设计语言
•程序设计语言 –高级语言 –汇编语言 –机器语言 •在计算机上如何执行一个高级语言程序? –把高级语言程序翻译成机器语言程序 –运行所得的机器语言程序求得计算结果
第一章 引论 二、程序设计语言的转换与编译
•翻译 –在不改变语义的条件下,把某种语言的源程序 转换成另一种语言程序——目标语言程序。 •解释 –接受某高级语言的一个语句输入,进行解释并 控制计算机执行,马上得到这句的执行结果,然 后再接受下一句。
第一章 引论 三、编译程序 4.优化
• 任务 对产生的中间代码进行加工变换,以期在最 后阶段能产生更为高效(省时间、省空间)的 目标代码 • 依据原则:程序的等价变换规则 • 主要优化内容 删除公共子表达式、合并已知量、删除无用 赋值语句、循环优化等
第一章 引论 三、编译程序 5.目标代码生成
• 任务:把中间代码程序转化成具体机器的指令序列 • 注:转换过程需涉及具体机器的指令系统以及寄存 器分配等硬件功能。
第一章 引论 三、编译程序 8. 遍
• 遍:指对源程序或源程序的中间结果从头到尾扫描一次, 并做有关的加工处理,生成新的中间结果或目标代码的过 程。 –注:遍与阶段的含义毫无关系。 • 多遍扫描的好处 –节省内存空间,提高目标代码质量,使编译的逻辑结构 清晰。 • 多遍扫描的缺点 –编译时间较长。 –注:在内存许可情况下,还是遍数尽可能少些为好。
词 源程序 法 分 析 器
语 法 代 码 生 成
优 化
目 标 代 目标代码 码 生 成
出错处理
第一章 引论 三、编译程序 1.词法分析
• 任务 –输入源程序,对构成源程序的字符串进行扫 描和分解,依照词法规则,识别出一个个的 单词,并转化为机器易于使用的内码形式。 • 单词 –是高级语言中有实在意义的最小语法单位, 它由字符构成。
【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集 近来复习编译原理,语法分析中的⾃上⽽下LL(1)分析法,需要构造求出⼀个⽂法的FIRST和FOLLOW集,然后构造分析表,利⽤分析表+⼀个栈来做⾃上⽽下的语法分析(递归下降/预测分析),可是这个FIRST集合FOLLOW集看得我头⼤。
教课书上的规则如下,⽤我理解的语⾔描述的:任意符号α的FIRST集求法:1. α为终结符,则把它⾃⾝加⼊FIRSRT(α)2. α为⾮终结符,则:(1)若存在产⽣式α->a...,则把a加⼊FIRST(α),其中a可以为ε(2)若存在⼀串⾮终结符Y1,Y2, ..., Yk-1,且它们的FIRST集都含空串,且有产⽣式α->Y1Y2...Yk...,那么把FIRST(Yk)-{ε}加⼊FIRST(α)。
如果k-1抵达产⽣式末尾,那么把ε加⼊FIRST(α) 注意(2)要连续进⾏,通俗地描述就是:沿途的Yi都能推出空串,则把这⼀路遇到的Yi的FIRST集都加进来,直到遇到第⼀个不能推出空串的Yk为⽌。
重复1,2步骤直⾄每个FIRST集都不再增⼤为⽌。
任意⾮终结符A的FOLLOW集求法:1. A为开始符号,则把#加⼊FOLLOW(A)2. 对于产⽣式A-->αBβ: (1)把FIRST(β)-{ε}加到FOLLOW(B) (2)若β为ε或者ε属于FIRST(β),则把FOLLOW(A)加到FOLLOW(B)重复1,2步骤直⾄每个FOLLOW集都不再增⼤为⽌。
⽼师和同学能很敏锐地求出来,⽽我只能按照规则,像程序⼀样⼀条条执⾏。
于是我把这个过程写成了程序,如下:数据元素的定义:1const int MAX_N = 20;//产⽣式体的最⼤长度2const char nullStr = '$';//空串的字⾯值3 typedef int Type;//符号类型45const Type NON = -1;//⾮法类型6const Type T = 0;//终结符7const Type N = 1;//⾮终结符8const Type NUL = 2;//空串910struct Production//产⽣式11 {12char head;13char* body;14 Production(){}15 Production(char h, char b[]){16 head = h;17 body = (char*)malloc(strlen(b)*sizeof(char));18 strcpy(body, b);19 }20bool operator<(const Production& p)const{//内部const则外部也为const21if(head == p.head) return body[0] < p.body[0];//注意此处只适⽤于LL(1)⽂法,即同⼀VN各候选的⾸符不能有相同的,否则这⾥的⼩于符号还要向前多看⼏个字符,就不是LL(1)⽂法了22return head < p.head;23 }24void print() const{//要加const25 printf("%c -- > %s\n", head, body);26 }27 };2829//以下⼏个集合可以再封装为⼀个⼤结构体--⽂法30set<Production> P;//产⽣式集31set<char> VN, VT;//⾮终结符号集,终结符号集32char S;//开始符号33 map<char, set<char> > FIRST;//FIRST集34 map<char, set<char> > FOLLOW;//FOLLOW集3536set<char>::iterator first;//全局共享的迭代器,其实觉得应该⽤局部变量37set<char>::iterator follow;38set<char>::iterator vn;39set<char>::iterator vt;40set<Production>::iterator p;4142 Type get_type(char alpha){//判读符号类型43if(alpha == '$') return NUL;//空串44else if(VT.find(alpha) != VT.end()) return T;//终结符45else if(VN.find(alpha) != VN.end()) return N;//⾮终结符46else return NON;//⾮法字符47 }主函数的流程很简单,从⽂件读⼊指定格式的⽂法,然后依次求⽂法的FIRST集、FOLLOW集1int main()2 {3 FREAD("grammar2.txt");//从⽂件读取⽂法4int numN = 0;5int numT = 0;6char c = '';7 S = getchar();//开始符号8 printf("%c", S);9 VN.insert(S);10 numN++;11while((c=getchar()) != '\n'){//读⼊⾮终结符12 printf("%c", c);13 VN.insert(c);14 numN++;15 }16 pn();17while((c=getchar()) != '\n'){//读⼊终结符18 printf("%c", c);19 VT.insert(c);20 numT++;21 }22 pn();23 REP(numN){//读⼊产⽣式24 c = getchar();25int n; RINT(n);26while(n--){27char body[MAX_N];28 scanf("%s", body);29 printf("%c --> %s\n", c, body);30 P.insert(Production(c, body));31 }32 getchar();33 }3435 get_first();//⽣成FIRST集36for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FIRST集37 printf("FIRST(%c) = { ", *vn);38for(first = FIRST[*vn].begin(); first != FIRST[*vn].end(); first++){39 printf("%c, ", *first);40 }41 printf("}\n");42 }4344 get_follow();//⽣成⾮终结符的FOLLOW集45for(vn = VN.begin(); vn != VN.end(); vn++){//打印⾮终结符的FOLLOW集46 printf("FOLLOW(%c) = { ", *vn);47for(follow = FOLLOW[*vn].begin(); follow != FOLLOW[*vn].end(); follow++){48 printf("%c, ", *follow);49 }50 printf("}\n");51 }52return0;53 }主函数其中⽂法⽂件的数据格式为(按照平时做题的输⼊格式设计的):第⼀⾏:所有⾮终结符,⽆空格,第⼀个为开始符号;第⼆⾏:所有终结符,⽆空格;剩余⾏:每⾏描述了⼀个⾮终结符的所有产⽣式,第⼀个字符为产⽣式头(⾮终结符),后跟⼀个整数位候选式的个数n,之后是n个以空格分隔的字符串为产⽣式体。
编译原理

第二章练习2.1 考虑文法G[S],其产生式如下:S→(L)|aL→L,S|S(1)试指出此文法的终结符号、非终结符号。
解答:终结符号为:{(,),a,,,} 非终结符号为:{S,L} 开始符号为:S(2)给出下列各句子的分析树:①(a,a) ②(a,(a,a)) ③(a,((a,a),(a,a)))(3)构造下列各句子的一个最左推导:①(a,a)S (L)(L,S) (S,S) (a,S)(a,a)②(a,(a,a))S (L)(L,S)(S,S) (a,S) (a,(L)(a,(L,S))(a,(S,S))(a,(a,S))(a,(a,a))③(a,((a,a),(a,a)))S (L)(L,S)(S,S)(a,S) (a,(L))(a,(L,S))(a,(S,S))(a,((L),S))(a,((L,S),S)) (a,((S,S),S))(a,((a,S),S))(a,((a,a),S)) (a,((a,a),(L)))(a,((a,a),(L,S)))(a,((a,a),(S,S)))(a,((a,a),(a,S)))(a,((a,a),(a,a)))(4)构造下列各句子的一个最右推导:.①(a,a)S (L)(L,S)(L,a)(S,a)(a,a)②(a,(a,a))S (L)(L,S) (L,(L)) (L,(L,S))(L,(L,a))(L,(S,a))(L,(a,a))(S,(a,a))(a,(a,a))③(a,((a,a),(a,a)))S (L)(L,S) (L,(L)) (L,(L,S))(L,(L,(L)))(L,(L,(L,S)))(L,(L,(L,a)))(L,(L,(S,a)))(L,(L,(a,a)))(L,(S,(a,a)))(L,((L),(a,a)))(L,((L,S),(a,a)))(L,((L,a),(a,a)))(L,((S,a),(a,a)))(L,((a,a),(a,a)))(S,((a,a),(a,a)))(a,((a,a),(a,a)))(5)这个文法生成的语言是什么?L(G[S]) = (α1,α2,...,αn)或a 其中αi(1≤i≤n),即L(G[S])是一个以a为原子的纯表,但不包括空表。
编译原理语法分析——自下而上分析

E
1)LR分析法 2)算符优先分析法
E+ T
T
F
T * F i3
F
i2
i1
归约的含义: G(E): E i| E+E | E-E | E*E |
例:设文法G(S): (1) S aAcBe (2) A b (3) A Ab (4) B d
试对abbcde进行“移进-归约”分析。
e
BBd
abbbbcccdddeee
bcc
Ab
Saa
步骤: 1 2 3 4 5 6 7 8 9 10 动作: 进a 进b 归(2) 进b 归(3) 进c 进d 归(4) 进e 归(1)
规范归约是关于是一个最右推导的逆过程
最左归约
规范推导
由规范推导推出的句型称为规范句型。
把上例倒过来写,则得到:
S aAcBe aAcde aAbcde
abbcde
显然这是一个最右推导。
规范归约是关于是一个最右推导的逆过程
最左归约
规范推导
由规范推导推出的句型称为规范句型。
S
句柄“最左”特征的含 义
aAcde (4) B d
aAcBe (1) S aAcBe
S
S
a A c Be
A
bd
b S
S
a A c Be
Ab
d
S
a A c Bea A c Be d
定义:假定是文法G的一个句子,我们称序列 n, n-1, ,0
是的一个规范归约,如果此序列满足:
编译原理复习题2

编译原理复习题21、(10分)下面的文法G[S]是否是LL(1)文法,说明理由,构造LL(1)分析表S→aBc|bABA→aAb|BbB→cB|2、(5分)消除下列文法的左递归,消除左递归后判断是否是LL(1)文法。
S→SaB|bBA→S|aB→Ac3、(5分)构造下面算符文法的优先矩阵,判断是否是算符优先文法S→A[]A→[A→aAA→B]B→a4、(10分)将表达式A+B某(C-D)-E/F↑G分别表示为三元式、四元式、逆波兰式序列5、(10分)现有文法如下:S→aS|bS|a判断该文法是哪一类LR文法,说明理由,并构造相应的分析表。
1、已知文法GA::=aABe|aB::=Bb|d(1)给出与上述文法等价的LL(1)文法G’。
(2)构造预测分析表并给出输入串aade#分析过程。
(10分)2、设已给文法G:E::=E+TE::=TT::=T某FT::=FF::=P↑FF::=PP::=(E)P::=i构造此文法的算符优先矩阵。
(10分)某某某某3、有正规式babb(abb)(1)构造该正规式所对应的NFA(画出状态转换图)。
(2)将所求的NFA确定化。
(画出确定化的状态转换图)。
(3)将所求的NFA最小化。
(画出最小化后的状态转换图)。
(10分)4、若有文法G(S)的产生式如下:S::=L=RS::=RL::=某RL::=iR::=L,构造识别所有项目集规范族的DFA。
(15分)(1)判断该文法是否是LR(0)文法,说明理由。
(2)判断该文法是否是SLR(1)文法,说明理由。
(3)判断该文法是否是LR(1)文法,说明理由。
(4)判断该文法是否是LALR(1)文法,说明理由1、(10分)将表达式((B某D+A)/E+D)某F+G分别表示为三元式、四元式、逆波兰式序列2、(10分)对基本块P画出DAG图B:=3D:=A+CE::=A某CF:=E+DG:=B某FH:=A+CI:=A某CJ:=H+IK:=B某5L:=K+JM:=L假定只有L在基本块出口之后活跃,写出优化后的四元式序列。
编译原理第6章_1

STACK REMAINING INPUT
1
(int + int)#
2(
int + int)#
3 (int
+ int)#
4 (T
+ int)#
5 (E
+ int)#
6 (E +
int)#
7 (E + int
)#
8 (E + T
)#
9 (E
)#
10 (E)
#
11 T
#
12 E
#
13 S
#
PARSER ACTION Shift Shift Reduce: T –> int Reduce: E –> T Shift Shift Reduce: T –> int Reduce: E –> E + T Shift Reduce: T –> (E) Reduce: E –> T Reduce: S –> E
的左部而得到的
文法要求
shift-reduce or reduce-reduce 冲突(conflicts)
分析程序不能决定是shift 还是 reduce 或者分析程序归约时有多个产生式可选
例子 (dangling else) : S –> if E then S | if E then S else S
LR分析算法
then begin pop || 项 令当前栈顶状态为S’ push GOTO[S’, A]和A(进栈)
end else if ACTION[s,a]=acc
then return (成功) else error end
项目集规范族构造
同心集
编译原理
某些LR(1)项目集称为同心的,除了向前看
符号外,这些项目集是相同的 一个心就是一个LR(0)项目集
26
合并同心集
编译原理
把所有同心的项目集合并为一个项目集 同心集合并后不会产生“移进-归约”冲突,
但会产生“归约-归约”冲突
27
构造LALR(1)分析表
通常所采用的方法
36
编译原理 – 四种LR类型:
LR(0)
SLR(1) LALR(1) LR(1) 功能逐个增强 四种LR类型的文法是真包含关系
37
编译原理
The End. Thanks!
38
编译原理
编译原理
主 讲:温 璞 责任教师:蒋慧平
1
编译原理
第八讲
LR(k)分析方法(II)
2
编译原理
上一讲主要内容
– LR(0)分析表的构造
本讲内容
– SLR(1)分析表的构造
– LR(1)分析表的构造 – LALR(1)分析表的构造
3
编译原理
LR(0)文法是一类简单的文法 对其所构造的识别活前缀的DFSA的每
个状态都不能含冲突项
– 移进项目和规约项目不能并存 – 规约项目不能并存
大多数适用的程序设计语言的文法不
能满足LR(0)文法的条件,不能用LR(0) 分析表的方法进行分析 可通过向前查看一个输入符号来协助 解决冲突
4
编译原理
5
编译原理
6
编译原理
7
编译原理
8
构造SLR(1)分析表
编译原理
15
CLOSURE(I)构造
编译原理
16
编译原理 第6章-LR分析-小结资料
Compiler Construction Principles
SLR规则: I: { A→α .bβ B 1→ γ1. B2 → γ2. } {b} ∩FOLLOW(B1)=Φ {b} ∩FOLLOW(B2)=Φ a ∈ {b} 移进 FOLLOW(B1)∩FOLLOW(B2)=Φ a ∈ FOLLOW(B1) 用B 1→ γ1 归约 a ∈ FOLLOW(B2) 用B2 → γ2 归约
)
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)文法
(
Compiler Construction Principles
I0:S'→·S S S →·S(S) S →·
0. S'→S
1. S →S(S)
2. S → ε
I1: S'→S· S →S·(S)
(
I2: S →S(·S) S →·S(S) S →·
I4: S →S(S)· )
S I3:S →S(S·) S →S·(S)
Compiler Construction Principles
例1 设有文法G[S]:
S →(S) |ε
试判断该文法是否SLR(1)文法,若 不是,请说明理由;若是,请构造 SLR(1)分析表。
《编译原理》教学大纲
《编译原理》教学大纲大纲说明课程代码: 3225003总学时: 64 学时(讲课 48 学时,实验16 学时)总学分: 4课程类别:学科基础课适用专业 : 计算机科学与技术(专业)预修要求: C 语言程序设计、 C++ 程序设计、数据结构课程的性质、任务及地位:《编译原理》是计算机科学与技术专业的一门重要基础课。
通过对该课程的学习,使学生掌握编译过程中的相关原理和编译技术,让学生能初步进行编译程序的开发和维护,同时促进提高学生开发软件的能力。
教学目的与基本要求:本课程的目的,通过向学生讲述编译系统的结构、工作流程及编译程序各部分的设计原理和实现技术,使学生既掌握编译技术理论的基础与基本知识,也具有设计、实现、分析和维护编译程序等方面的初步能力。
本课程理论性较强。
因授课对象为工科学生,所以在强调编译系统的构造原理和实现方法的同时,为培养学生的实际工作能力,通过上机实践进一步加深学生对课堂教学内容的理解。
目的是要使学生牢固掌握相关的基本理论和基本方法,并能初步利用上述理论和方法解决简单实际问题。
教学方法和教学手段的建议:在教学方法上,贯彻理论联系实际、“精讲、多练”的原则,进行案例式、启发式的教学,对于一些实际性较强的问题要多采用课堂讨论等方式,以提高学生的思辨能力和学习的主动性;引导学生读书、理解、体悟、运用相结合;提高学生的学习兴趣与热情,培养与发挥学生的提出、分析及解决问题的能力。
教学手段:运用多媒体教学手段 +黑板 +上机实验的手段。
采取课堂讲授、课堂讨论、课后练习与自学等形式。
大纲的使用说明:大纲对课程性质、目的等作简单说明,同时列出各章节要学习的知识点、重点、难点,便于教学时教授重点的安排和学生自学安排。
大纲正文第一章引论学时: 4 学时(讲课 4 学时,实验 0 学时)了解编译的概念;理解编译程序的各组成部分及功能。
本章讲授要点:介绍程序设计语言与编译程序间的关系,主要内容包括:各级程序设计语言的定义、源程序的执行、编译程序的构造、编译程序的分类、形式语言理论与编译实现技术的联系。
编译原理陈火旺版PPT课件
例有文法G[L]
(1)LE,L (2)LE (3)Ea (4)Eb
要求对输入串a,b,a进行分 析,即分析#a,b,a#
首先应给出LR分析表
为了节省空间,在实际应用中,将动作(Action) 表和状态转换(Goto)表中关于终结符的各列对 应进行合并。
10
例如,本来 Action(S0,a)= “移进”,表示 在状态S0下输入 a时,执行“移
进行分析时,对
为了构造分应析的动表作,是我把们符根据各项目的特点把项 目分成不同类型号,a移分进类符的号栈原。则是根据圆点所在位置
和圆点之后是终结符它还表是明非该状终态结等符进行的。
1.,移进V项*,目a:V圆T,它点此析对之时完待的应,毕后着分已,的为对析把状终非。已终态结分在结为符符移的B进项状目态, A;Sa.Aa.c,Be 2.待约项目:圆点栈之顶,后可为以非按终相结符的项目, A.B ,
(1)应用面广:能够用LR分析程序识别绝大多数的程 序设计语言的语法结构;
(2)实现效率高:虽构造方法复杂,但是实现(执行) 效率高。 (3)查错准确:LR分析器能够及时发现语法错误并准 确指出错误位置。
1
LR(k)分析方法中L是指自左(Left)向右扫描输入单词 串,R指分析过程是最右(Right)推导的逆过程(规 范归约),k是指在决定当前分析动作时需向前察看 的输入符号个数。
输入符号进栈; 归约:用相应的产生
S0
移进
元素元为素空为白a表cc 示表出示错接受
式进行归约;
S1
r5
接受:当归约到只剩下
…
文法开始符号且输入串 结束时分析成功;
Sm
ac c
出错:当状态栈顶为某一状态下,出现了不该出现的
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
I4: A → c·A
A →· cA A → ·d
I8:A → cA·
I1: S’→E · I9: B → cB·
I6:E →aA·
I10:A → d ·
I7: E →bB· I11: B → d·
I5: B → c·B
B →· cB B →·d
I6:E →aA·
I10:A → d ·
I7: E →bB· I11: B → d·
I5: B → c·B
B →· cB B →·d
I0={S→·E, E→·aA, E→·bB}
1)GOTO (I0, E)= closure(J)=closure({S’→E·})= {S’→E·} = I1
2)GOTO (I0, a)= closure(J)=closure({E→a·A}) ={ E→a·A, A→·cA, A→·d} )=I2 3)GOTO (I0, b)= closure(J)=closure ({E →b.B}) ={E →b · B, B→ · cB, B→ · d}= I3
• 文法G’通过闭包函数求得DFA的项目集有: I0: S’→·E
E →·aA E →·bB
I2: E →a·A
A →· cA A → ·d
I3: E →b·B
B →· cB B →·d
I4: A → c·A
A →· cA A → ·d
I8:A → cA·
I1: S’→E · I9: B → cB·
3 d d 5 c
7 13
11 13
B
9 13
• 步骤六: 把每个子 A → cA· A A →· cA 集所含状 A → c·A d A → ·d 态集对应 c A→ d · d 的项目写 E →a·A 在新的状 a A2→· cA A A → ·d E →aA· 态中,得 S’→·E E →·aA E S’→E · * 到识别活 E →·bB 前缀的有 E →b·B E →bB· b b B →· cB 限自动机 B →·d • 使用方法 2 构造识别活前缀的 DFA,需要列出拓广文法的所有 d DFA c B→ d·,这样做 项目,按规定规则构造其NFA DFA B,然后再确定化为 → c·B d 确定化的工作量较大。
T6
T8
T9
T1
• 确定化的DFA
c
A
d d
8 13
4
c a 0 2
1 13
10 13
A * b
6 13
E
b c
S’→·E S’→E · A → c·A E →bB· B → c·B B → cB· B → d·
A → cA·
A→d· E →b·B
E →a·A
E →aA·
例如,文法G: E → aA|bB A → cA| d B → cB| d
用增广文法 表示成
文法G’: S’→E E → aA|bB A → cA| d B → cB| d
I10:A → d ·
I11: B → d·
转换函数(GOTO函数)
• 转换函数的定义如下: GOTO(I,X)=closure(J) 其中:
I是G的一个LR(0)项目集
X为一个文法符号, X {VT∪VN} J={当A→α· Xβ I时,任意形如A→αX· β的项目} 即GOTO (I,X)为I中所有形如A→α· Xβ的项目所对应的项 目A→αX· β的集合的闭包
S’→·E的闭包为:
S’→·E E →·aA E →·bB
E →a·A的闭包为: E →a·A
A→· cA
A→· d
例如,文法G: E → aA|bB A → cA| d B → cB| d
用增广文法 表示成
文法G’: S’→E E → aA|bB A → cA| d B → cB| d
A → c·A的闭包为: E →b·B的闭包为: B → c·B的闭包为: A → c·A E →b·B B → c·B
项目集。
c
•方法3:把增广文法的第一个项目S’→·S作为初态集的
内核项,通过求内核项的闭包函数直接求出LR(0)项目
集规范族,再由转换函数建立状态之间的连接关系得到
识别活前缀的DFA 第一步:找出内核项 第二步:通过闭包函数求得DFA的项目集规范族
第三步:求出各项目集的GOTO函数
第四步:画出确定的有穷自动机
8 13 10 13 5 13
13 18 13
16 13
文法G’的项目有: 1.S’→·E 步骤四: 2.S’→E · 找源自同一产 3.E →·aA 生式的项目, 4.E →a·A 添加状态间的 5.E →aA· 连线 3 6. A →· cA 7. A → c·A 8. A → cA· E 9. A → ·d 1 10. A → d · 11. E →·bB 12. E →b·B 11 13. E →bB· 14. B →· cB 15. B → c·B 16. B → cB· 17. B →·d 18. B → d·
I6:E →aA·
I10:A → d ·
I7: E →bB· I11: B → d·
I5: B → c·B
B →· cB B →·d
I2={E →a·A, A →· cA,A → ·d}
1) GOTO(I2, A)= closure(J)=closure({E →aA · }) = {E →aA · }= I6 2) GOTO(I2, c)= closure(J)=closure({A →c ·A }) ={A → c · A ,A →· cA,A → ·d} =I4
ε c ε A
7
A
ε 9
8 13
d
10 13
5 13
B
ε
13
ε c ε 15 B
17
16 13
d
18 13
• 步骤五:运用 子集法将其确 定化 T0= { 1, 3, c d A
B
E
T0
T1 T2 T3 T4 T5 T6
T2
T3
T2= {4, 6, 9}
T3= { 12, 14, 17} T4= {6, 7, 9}
• 对于一个适用的高级语言的文法,用方法1构造识别活前缀 的有限自动机从理论的角度讲是很严格的,实现起来却是很 复杂的。
识别活前缀的确定的有穷自动机
• 方法2:求出文法的所有LR(0)项目,按一定规则构造识别 活前缀的NFA再确定化为DFA 例如,文法G: 步骤一: E → aA|bB 用增广文法表示成 A → cA| d B → cB| d 文法G’: S’→E E → aA|bB A → cA| d B → cB| d
B →· cB B →·d
c
B
B → cB·
c
c
A → c·A A →· cA A → ·d
• 分析使用方法2构造识别
A d d A
A → cA·
活前缀的DFA中每个状态
中项目集的构成,发现
c
A→ d ·
如下规律:
a
S’→·E E →·aA E →·bB
E →a·A A2 →· cA A → ·d
T5= { 14, 15, 17}
T6= { 5 } T7= { 13 } T8= { 8 } T9= { 16 } T10= { 10 } T11= { 18}
T7
T8 T9 T10 T11
T7
T4 T5 T4 T5
T10 T11 T10 T11
A→· cA
A→· d
B→· cB
B→· d
B→· cB
B→· d
例如,文法G: E → aA|bB A → cA| d B → cB| d
用增广文法 表示成
文法G’: S’→E E → aA|bB A → cA| d B → cB| d
• 通过闭包函数求得DFA的项目集规范族 I0: S’→·E
内核项:包括初始项S’→·S以及圆点不在最左端的所有项
例如,文法G: E → aA|bB A → cA| d B → cB| d
用增广文法 表示成
文法G’: S’→E E → aA|bB A → cA| d B → cB| d
文法G’的内核项有: S’→·E S’→E · E →a·A E →aA·
3) GOTO(I2, d)= closure(J)=closure ({A → d ·})
={A → d ·}= I10
• 文法G’通过闭包函数求得DFA的项目集有: I0: S’→·E
E →·aA E →·bB
I2: E →a·A
A →· cA A → ·d
I3: E →b·B
B →· cB B →·d
A → c·A
A → cA· A→d·
E →bB· B → c·B B → cB· B → d·
E →b·B
项目集的闭包
• 文法G已表示为增广文法G’,如果I是文法G’的一个项目集, 定义和构造I的闭包CLOSURE(I)如下: 1)一开始,将I中的各个项加入到CLOSURE(I)中 2)若项目X→ · A 属于CLOSURE(I),那么形如A→· r的项
LR(0)分析表的构造
步骤一: 构造识别文法活前缀的确定有穷自动机(DFA)
步骤二: 根据DFA构造相应的LR(0)分析表
•识别活前缀的确定的有穷自动机
• 方法1:根据形式定义求出活前缀的正规表达式,然后由此 正规表达式构造NFA再确定化为DFA