1、编译原理实验实验一 词法扫描器设计一 实验目的通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力。二 实验内容设计一个简单的类C语言的词法扫描器。三 实验要求(一) 程序设计要求(1) 根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。(2) 提供源程序输入界面;(3) 词法分析后可查看符号表和TOKEN串表;(4) 保存符号表和TOKEN串表(如:文本文件); (5) 遇到错误时可显示提示信息,然后跳过错误部分继续进行分析。(二)实验报告撰写要求(
2、1) 系统功能(包括各个子功能模块的功能说明);(2) 开发平台(操作系统、设计语言);(3) 设计方案;1) 主数据流图;2) 主要子程序的流程框图(若有必要);3) 模块结构图;4) 主要数据结构:符号表、TOKEN串表等。(4) 具体设计过程(包括主控程序、各个功能模块的具体实现)。四 实验总结附录:类C语言的词法文法id Letter int10 Num int10 | Num OP +| - |* |/ | = |= | !=Keywordif | then | else | while | do Lettera|b|c|d|e|f|g|i|j|k|l|m|n|o|p|q|r|s|t
3、|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|ZNum0|1|2|3|4|5|6|7|8|9 | Letter | Num | 一.设计内容1.根据附录给定的文法,从输入的类C语言源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分隔符五大类;文法见最后附录。2.源程序保存在文件中。3.词法分析后可查看符号表和TOKEN串表;4.保存符号表和TOKEN串表(如:文本文件); 二.详细设计1.首先根据题目要求对要进行词法分析的单词符号进行编码。单词符号种别编码单词符号种别编码main117int
4、218char319if420else5,21for6:22while7;23ID824NUM925=1026+1127-1228*13!29/14(15)162.在本实验中,将需要出来的文法符号分为几类:(1)关键字:在本实验中对关键字分别进行存储,在判断是否为标识符前首先对关键字进行识别。(2)标识符:标识符处理函数识别标识符。正则定义为:(3)运算符:运算符包括= + - * / ( ) , ; = = = != 等,需单独写函数进行识别。 关系运算符需根据下图进行识别: (4)数字:在本例中仅识别整数。digit = 1|2|3|4|5|6|7|8|9Digit = 0|1|2|3|4
5、|5|6|7|8|9Digit = digit Digit*3.扫描器 扫描器作为独立的子程序,首先进行扫描剔除无用的换行和连续的空格,对处理后的代码进行分析。三.模块划分和实现1.数据结构(1)ModulClass存储划分好的词法单元的分类,存储有单元的名称和单元的标号,与上面的表格中的信息一致。在程序开始时需要首先将分类信息读取然后填充表格class ModulClass /存储词法单元的分类public: string strID; /单元名字 int number; /单元编号;ModulClass modulclassModulClass_size;(2)Codeclass存储在程序
6、识别过程中识别到的词法单元class CodeClass /存储识别过程中识别的词法单元public: string code; /名字 int number; /编号;CodeClass codeclassCodeClasss_size;2.预处理模块 readcode()函数(1)代码存储在code.txt中,用C+流读取文件内容,相关代码如下。ifstream infile(code.txt,ios:in); if (!infile) cout无法打开代码文件!endl; exit(-1); infile.getline(temp,1000,EOF); tempstrlen(temp)
7、= 0;(2)去除换行符号 for(i = 0;i strlen(temp);i+) if(tempi = n) strtemp += ; else strtemp += tempi; (3)去除多余的空格符号,将多个空格连续的压缩成一个for(j = 0;j = strtemp.length();) if(strtempj = ) while(strtemp+j = ) strcode += ; /处理空格,将多个连续的空格压缩成一个 continue; else strcode += strtempj; j+; cout消去空格和换行符处理结果endlstrcodemodulclassi.
8、strID; in_classmodulclassi.number; i+;4. 判断是否为标识符int is_key_ID(int forward,int back) /判断是否是标识符该函数判断读入的是否为标识符,根据标识符判断的正则表达式进行识别,若非标识符则输出错误,若识别则将该标识符的字符串和种别码进行保存。需建立两个指针,forwawrd 指针和 back指针,首先forward指针移动,back指针则指向标识符的第一个字符的位置,直到识别完毕。关键代码如下:while(+forward) /扫描字符串,返回 idtemp,保存forward if(strcodeforward =
9、 65)&(strcodeforward = 97)&(strcodeforward = 48)&(strcodeforward = 57) /下一个是数字 temp+len = strcodeforward; else forward-; break; 5.判断匹配关键字判断该字符串符合标识符的文法之后,需事先判断该标识符是否是系统预留的关键字。 bool iskey = false; /判断是否是key codeclassnum_class.code = idtemp; /保存词法单元code属性 for(int i = 0;i = 48)&(strcodeforward = 57)/下一
10、个是数字 temp+len = strcodeforward; else forward-; break; 7.判断是否是relop符号分为两种情况:由一个字符组成和由两个字符组成(1)仅有一个字符组成 if(temp1 != = ) /该运算符仅有一个字符 forward-; /回退指针 /保存词法单元 switch(temp0) case : codeclassnum_class.code = G; /保存词法单元code属性 codeclassnum_class.number = 24; /ID的编号 break; case =: codeclassnum_class.code = =;
11、 /保存词法单元code属性 codeclassnum_class.number = 10; /ID的编号 num_class+; (2)由两个字符组成 else /由两个字符构成,第二个为= /保存词法单元 switch(temp0) case : codeclassnum_class.code = GE; /保存词法单元code属性 codeclassnum_class.number = 26; /relop的编号 break; case =: codeclassnum_class.code = EQ; /保存词法单元code属性 codeclassnum_class.number = 2
12、8; /relop的编号 break; case !: codeclassnum_class.code = NE; /保存词法单元code属性 codeclassnum_class.number = 29; /relop的编号 num_class+; return forward; /返回当前扫描的位置8.词法单元扫描器扫描器维持两个指针,forward指针和back指针,同时获取扫描区域的总长度。根据back指针指向的字符的属性,判断该词法单元的种类,然后根据种类跳转到相应的识别函数中去,观察该函数能否被识别,若能够被识别则保存该词法单元,跳转道下一个词法单元,否则输出错误信息。void s
13、canner() int i; int forward = 0,back = 0; /维持两个指针 int lenth = strcode.length(); /扫描区域的总长度 char temp; num_class = 0; /记录识别出词法单元的个数方便存储 while(forward = 65)&(temp = 97)&(temp = 48)&(temp = 57) /判断是否是数字 back = forward; forward = is_number(forward,back); forward+; back = forward; continue; else if( (temp
14、 = +) | (temp = -) |(temp = *) |(temp = /) |(temp = () |(temp = ) | (temp = ) | (temp = ) |(temp = ) |(temp = ) |(temp = ,) |(temp = :) |(temp = ;) )/判断是否是符号 back = forward; for(i = 0;i ModulClass_size;i+) /在表中查找当前词法单元的编号 if(modulclassi.strID0 = temp) codeclassnum_class.number = modulclassi.number;
15、codeclassnum_class.code = modulclassi.strID; break; num_class+; /增加词法单元个数 forward+; back = forward; continue; else if(temp = ) |(temp = !) ) /判断是否是relop比较运算符 back = forward; forward = is_relop(forward,back); forward+; back = forward; continue; else if(temp = ) /空格 forward+; back = forward; continue;
16、 else forward+; back = forward; /while9. 将产生的词法单元写入文件 依次将生成的对象写入文件即可。ofstream outfile; outfile.open(词法分析结果.txt); for(i = 0;i num_class;i+) outfilecodeclassi.code ; outfilecodeclassi.numberendl; coutcodeclassi.code ; coutcodeclassi.numberendl; outfile.close();四.实验结果1.class文件的内容如下,存放预先设定好的词法单元2.code文件
17、代码如下,存放要识别的程序源代码3.图为程序运行结果,为识别后的词法单元五.实验总结 本次实验中词法分析相关代码均由我一人独立编写。理论联系实际的过程中比较坎坷,首先必须明白词法分析的过程,明白词法单元的识别过程,然后才能设计自己的程序。但书本知识和程序仍然有一定的差距,在设计过程中必须按照步骤一步一步进行设计,按照标准的模块进行划分。同时模块的划分必须合理,尽量减少模块间的联系,对今后调试程序有很大帮助。 同时通过这次实验我明白了正则文法的作用,在学习形式语言的时候一直疑惑文法的体系和正规文法的用处,在本次实验中我体会到了正则文法的威力,正则文法可以很好的被计算机高级语言编程识别,而其他文法
18、则没有这种优势。附录:源代码/词法分析器 BaiChenjia#include iostream#include string#include math.h#include fstream#define ModulClass_size 29#define CodeClasss_size 100using namespace std;string strcode; /存储处理过后的代码int num_class = 0; /记录识别出的词法单元的个数class ModulClass /存储词法单元的分类public: string strID; /单元名字 int number; /单元编号;M
19、odulClass modulclassModulClass_size;class CodeClass /存储识别过程中识别的词法单元public: string code; /名字 int number; /编号;CodeClass codeclassCodeClasss_size;int readcode() /读取要处理的代码 int i,j; char temp1000; strcode = ; string strtemp = ; /存储代码 ifstream infile(code.txt,ios:in); if (!infile) cout无法打开代码文件!endl; exit(
20、-1); infile.getline(temp,1000,EOF); tempstrlen(temp) = 0; infile.close(); for(i = 0;i strlen(temp);i+) if(tempi = n) strtemp += ; else strtemp += tempi; strtempi = 0; for(j = 0;j = strtemp.length();) if(strtempj = ) while(strtemp+j = ) strcode += ; /处理空格,将多个连续的空格压缩成一个 continue; else strcode += strte
21、mpj; j+; cout消去空格和换行符处理结果endlstrcodeendl; return 0;void init_class() /对文法规定的标识符、数字、符号等进行分类,写入modulclass对象中 int i; ifstream in_class; in_class.open(class.txt); if (!in_class) cout无法打开代码文件!modulclassi.strID; in_classmodulclassi.number; i+; in_class.close(); /*for(i = 0;i ModulClass_size;i+) coutmodulclassi.strID modulclassi.number= 65)&(strcodeforward = 97)&(strcodeforward = 48)&(strcodeforward = 57) /下一个是数字 temp+len = strcodeforward; else forward-; break;
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1