目 录
引言............................................................. 2
第一章 概述................................................... 3
1.1设计内容.................................................. 3
1.2设计要求.................................................. 3
第二章 设计的基本原理......................................... 3
2.1 CLOSURE(I)的构造......................................... 3
2.2 GO(I,X)的构造............................................ 3
2.3 FIRST集合的构造.......................................... 3
2.4 LR(1)分析表的构造........................ ............. 3
第三章 程序设计.............................................. 4
3.1总体方案设计............................................. 4
3.2各模块设计............................................... 5
3.2.1读入模块:Read_G().................................. 5
3.2.2 计算FIRST模块:get_first() ....................... 5
3.2.3 判断项目数否在项目集里:is_in(proj temp,int T)..... 5
3.2.4 获得计算closure(I)时需要的First(βa):
gete_expc(proj temp)............................... 5
3.2.5 项目集的CLOSURE计算:e_closure(int T) ............. 5
3.2.6 检查项目集是否已经在项目集族里:is_contained()...... 6
3.2.7 GO()函数的实现:go(). ............................... 6
3.2.8 LR(1)分析表的构造:get_action()..................... 6
3.2.9 对输入串的语法分析:在main()中实现 ................ 6
第四章 程序测试................................................ 6
4.1 课本115页文法的LR(1) 分析器的构造和语法分析.........6
4.2 表达式文法的LR(1)分析器的构造和语法分析............... 7
第五章 结论.................................................... 9
参考文献.......................................................... 9
附录 程序清单................................................ 10
引言
《编译原理》是计算机专业的一门重要的专业课程,其中包含大量软件设计思想。通过课程设计,实现一些重要的算法,或设计一个完整的编译程序模型,能够进一步加深理解和掌握所学知识,对提高自己的软件设计水平具有十分重要的意义。
我选择的是老师给的第31题,并予以扩充。即对任意给定的文法G构造LR(1)项目集规范族,其中要实现CLOSURE(I)、GO(I,X)、FIRST集合等。在此基础上,
构造了LR(1)分析表。然后对输入的句子进行语法分析,给出接受或出错报告。程序采用文件输入输出方式。其中包括两个输入文件:文法grammar.txt,以及输入串input.txt;两个输出文件:项目集items.txt和文法的LR(1)分析表action_table.txt。由于语法分析的结果只给出接受或错误报告,比较简单。所以直接在屏幕上输出,也便于用户查看。
在具体编写程序过程中,对文法操作的各个功能模块独立成为一个子程序,而对具体输入串的分析则放在main()函数中进行。各个变量及函数的意义和用法我将在叙述程序设计的总体方案中详细给出。
程序的总体算法思想来自《编译原理》课程。具体实现由我独立完成。程序用C/C++语言编写。在Microsoft Visual C++ 2005环境下调试通过。
第一章 概述
1.1 设计内容
对任意给定的上下文无关文法G,构造其LR(1)项目集族,并且在此基础上进一步构造其LR(1)分析表。然后分析输入的“句子”。
1.2 设计要求
对输入的文法G(要求是上下文无关文法),在程序中实现CLOSURE(I)、GO(I,X)、FIRST等的构造,并利用这些功能函数构造出LR(1)项目集族。并且输出结果。在此基础上构造出G的LR(1)分析表(这个表也输出给用户),并对输入的“句子”进行语法分析,给出分析结果。
第二章 设计的基本原理
2.1 CLOSURE(I)的构造
CLOSURE(I)表示和I中项目可以识别同样活前缀的所有项目的集合。它可以由以下方法得到:
⑴ I中的所有项目都属于CLOSURE(I);
⑵ 若项目[A→α·Bβ,a]属于CLOSURE(I),B→ξ是一个产生式,那么,对于FIRST(βa)中的每一个终结符b,如果[B→·ξ,b]原来不在CLOSURE(I)中,则把它加进去;
⑶ 重复执行步骤⑵,直到CLOSURE(I)不再增大为止。
2.2 GO(I,X)的构造
GO(I,X) = CLOSURE(J)
其中 J={ 任何形如[A→αX·β,a]的项目|[A→α·Xβ,a]属于I}
2.3 FIRST集合的构造
在这个程序中使用的是FIRST(βa),这基于每一个非终结符的FIRST集合(终结符的FIRST就是它本身)。所以需要对每一个非终结符构造其FIRST集合。方法如下:
连续使用下面的规则,直到每个集合FIRST不再增大为止。
⑴ 若X属于VT,则FIRST(X)= {X}。
⑵ 若X属于VN,且有产生式X→a…,则把a加入到FIRST(X)中;若X→ε也是一条产生式,则把ε也加入到FIRST(X)中。
⑶ 若X→Y…是一个产生式且Y属于VN,则把FIRST(Y)中的所有非ε元素都加入到FIRST(X)中;若X→Y1Y2…Yk是一个产生式,Y1,…,Yi-1都是非终结符,而且,对于任何j,1<= j <= i-1,FIRST(YJ)都含有ε(即Y1…Yi-1=>ε),则把FIRST(Yi)中的所有非ε元素都加入到FIRST(X)中;特别的,若所有的FIRST(YJ)都含有ε,j=1,2,3...k,则把ε加入到FIRST(X)中。
2.4 LR(1)分析表的构造
在实现GO(I,X)时,记录下状态的转化。得到分析表中的移进部分。然后,再扫描所有的项目集,找到其中包含归约项目的那些项目集,根据其中的项目,得到分析表中那些归约的部分。
第三章 程序设计
3.1总体方案设计
在main()函数中读入文法。并对文法进行扩展,同时记录下文法的所有终结符和非终结符。对每一个非终结符计算它的FIRST集合。以备在计算CLOSURE(I)时使用。然后,调用GO()函数。完成LR(1)项目集族的计算。计算的结果记录到items.txt中。并且记录下状态之间的转换关系。接下来,调用get_action()根据上面的项目集族和记录的状态转换数组获得LR(1)分析表。然后就可以对输入的句子进行语法检查。程序中主要变量以及函数的说明如下:
·char G[20][20]; 存放输入的文法;为简单起见,设文法的产生式条数不 多于20条,每个产生式不多与20个字符,用@表示ε,且产生式输入的时候要以$结束
·int length[20]; 每条产生式的长度
·int number = 0; 产生式的条数
·bool tempofinput[150]; 记录哪些ASCII字符在文法中,以求得所有的VN和VT
·char str_vn[20]; 记录所有的非终结符
·int size_vn = 0; 记录非终结符的个数
·char str_vt[150]; 记录所有的终结符