1、深圳大学编译原理实验报告蔡树彬实验一资料深 圳 大 学 实 验 报 告 课程名称: 编译原理 实验项目名称: 文法分析方法及其应用 学院: 计算机与软件学院 专业: 软件工程 指导教师: 蔡树彬 报告人: 学号 班级: 实验时间: 2015年9月16日至10月28日 实验报告提交时间: 2015年11月10日 教务处制实验目的与要求:目的:针对分词、停用词过滤等文法分析应用问题,设计并实现相应的解决方案,再通过设计文法相关类族,以及实现文法化简等方法,既加深对抽象的文法、推导、语言等形式语言理论基础概念的理解与掌握,也加强对面向对象程序编写能力和计算思维的培养。要求: 第一部分: 分词输入:输
2、入是一个文本文件,里面的内容是符合某个语言语法、词法要求的源代码(语法可参考课本P104,包括语句表、for循环和赋值语句等),例如“position := initial + rate * 60;”;输出:设计并实现对输入文件的处理(禁用正则表达式),以获得如下输出,输出是一个文本文件,对前面例子,里面内容是:(标识符,position)(赋值运算符,:=)(标识符,initial)(加法运算符,+)(标识符,rate)(乘法运算符,*)(整数,60)(分隔符,; )第二部分:停用词过滤,分为“产生随机停用词”、“产生随机待过滤文本”和“过滤停用词”3个小实验。产生随机停用词:生成一个文件长
3、度和单词平均长度可控的文本文件,要求字符集为26个字母,每行生产一个单词,每个单词的长度随机,全部单词的平均长度可控制,通常为4、5(非严格要求),总共输出的文件长度可控制。产生随机待过滤文本:生成一个文件大小和单词平均长度可控的文本文件,要求字符集为26个字母+“ ”(空格)+“rn”(回车换行);从文件开始一直到结束,持续输出,不额外换行(除非遇到生成的rn),总共输出的文件大小可控制。过滤停用词:写一个程序,快速扫描待过滤文本,然后将待过滤文本中出现的所有停用词,替换为“*”,要求禁用正则表达式,不要误杀(例如,若停用词包括“abc”,那么“abcd”等不应该被误杀。第三部分:文法化简设
4、计文法类,实现对文法GS=(Vt, Vn, P, S)的文件读写,文法的文件表示形式以及内存表示形式可自定义。本质上,文法就是3个集合+1个符号,重点(难点)是产生式集合如何处理。文法的文本形式可根据自己需要自由定义。在前述的基础上,实现文法化简的无用符号及无用产生式消除算法(即课本算法2.1、2.2)。方法、步骤:要完成本实验,依据实验要求进行分解,需要完成的实验步骤是:1. 如何读写文件?读写文法文件内容,需要用到文件IO,查阅、复习文件IO操作。 写文件的方法包含在头文件include 中,通过ofstream cout(file.txt,ios:out)对文件进行写。 读文件的方法包含
5、在头文件include 中,通过freopen(in.txt,r,stdin)对文件进行读。2. 如何分词?第一部分实验要求进行分词,源代码中的单词可以分成3类,一类是约定的保留字,一类是普通标识符,最后一类是数字2.1 如何识别保留字?2.2 如何识别标识符?2.3 如何识别数字?特别的,如果你有多种方法来识别这3类单词,那这些方法有何优缺点?分析并作出你的选择。 首先将保留字和和标识符一一列举出来,创建保留字表和标识符表,然后对待识别文件进行分类(分成保留字、标识符、运算符、分隔符),然后逐一比对,最终不属于以上分类的就是数字。 识别保留字时,可以选择创建保留字及其名称的表,直接与保留字逐
6、个比较,然而看起来没有将单词分成三类的感觉,而创建表来比较的话看起来要简洁很多,因此不用前者。识别整数时也可以根据ASCLL码的值区间去判断,但是这种方法不太直观。3. 如何产生符合要求的随机停用词和待处理文本第二部分实验要求先产生随机的停用词和待处理文本,主要是如何产生符合要求的这些词或文本?3.1 如何产生随机停用词?3.2 如何控制随机停用词的平均长度(而不是固定长度)?3.3 如何产生待处理文本中的“段落”?3.4 如何控制待处理文本的长度?1.调用srand(time(0),使得每次产生的随机数不同,定义一个string类型的字符串word,a+rand()%26即可产生a-z的字母
7、,然后将每次产生的字母添加进word中,即可产生随机停用词。 2.定义一个int变量length,用rand()函数随机确定length的取值范围,然后在循环中以length为判断条件即可生成所需平均长度的停用词。 3.建立的符号集中添加入”rn”即可产生段落。 4.定义一个int类型的变量len,用rand()函数随机确定len的取值范围,然后在产生停用词的循环外嵌套一个循环,以len为判断条件即可控制产生停用词的个数,即处理文本的长度。4. 如何过滤停用词第二部分实验最后要求把待处理文本中出现的停用词替换为“*”,那你如何准确、快速判断出文本中的停用词? 通过定义两个指针变量,分别储存生成
8、的停用词表和待处理文件,然后利用strcmp()函数对两者进行比较。若在遇到空格回车换行之前全部一致,则用“*”代替待处理文件中的单词,最终输出处理后的单词。尤其注意对最后一个单词的截断处理。5. 如何设计文法类?文法类里面,有3个集合,1个特别的非终结符开始符号。集合应如何表示?Set是常见的范型,可使用例如Set来表示产生式的集合。也可直接采用数组等形式来表示,那种方法更好?分析并做出你的设计。 类成员中,非终结符集合和终结符集合使用数组格式储存,这是一种常用的数据格式,它可以直接用下标的方式获取其中的数据,开始符号使用char类型,产生式集合同样使用了数组格式。对于产生式集合,可以考虑使
9、用了vector格式,这种格式有push_back()函数可以向其添加元素,可以直接使用下标法访问成员,所以可以作为产生式集合。选用数组,主要是因为其较为简单。6. 如何实现无用文法的化简算法?算法2.1、2.2课本已经给出了说明,那你如何将算法说明变成代码?有什么主要内容? 由于课本中提供了算法2.1、2.2的处理过程,因此在编程过程中基本的步骤是和课本上一样的,但是具体的实现过程却比课本上要复杂的多,比如求Vn,Vt和P时,课本上是直接将其置为空,然后向其添加内容,但代码实现的过程中,我们需要用到Vn,Vt和P来进行判断和筛选,所以只能通过新建临时的集合的方式,经过课本上的方法处理之后再临
10、时的集合赋值给Vn、Vt和P。在课本描述为重复进行的步骤中,我们需要用到循环,并且循环里面需要有判断语句甚至是嵌套另一个循环。实验过程及内容: 实验过程及内容,处理代码设计说明、代码及其注释外,特别关注编程过程。 要求,至少有一张照片,照片上出现你(正面)+正在写的代码(电脑要有外观)实验1_1代码:#include #include #include using namespace std;#define N 100char strN;string KeyWordN=int,if,else,for,while,return,main; /仅列出常见关键字string symbol1N=+,-
11、,*,/,%;string symbol2N=!,&,|,&,|;string symbol3N=,=,=;int GetClassify(char c); /分类函数void LexicalAnalyzer(string s,int k); /词法分析器void GetIdentifier(string s,int k); /标识符函数void GetOperator(string s,int k); /运算符函数void GetSeparator(); /分隔符函数int main() ifstream fin(string.txt); finnoskipws; /读取空白字符 int p
12、os=0; int i; while(!fin.eof() finstrpos; pos+; cout测试语句:strendl; string String=; int key,curKey; key=GetClassify(str0); curKey=GetClassify(str0); for(i=0;i=A & c=a & c=0 & c=9) | c=_ | c=.) /标识符或整数或关键字 return 1; else if(c=( | c=) | c= | c= | c=;) /分隔符 return 2; else return 3; /运算符/词法分析器void LexicalA
13、nalyzer(string s,int k) if(s!=) if(k=1) /标识符或整数或关键字 GetIdentifier(s,k); else if(k=2) /分隔符 GetSeparator(); else if(k=3) /运算符 GetOperator(s,k); couts)endl; /标识符函数void GetIdentifier(string s,int k) int i; bool flag1=false; for(i=0;i9 | si0) flag1=true; break; if(flag1=true) bool flag2=true; for(i=0;i7;
14、i+) if(s=KeyWordi) cout(关键字,; flag2=false; if(flag2) cout(标识符,; else bool flag3=true; for(i=0;is.length();i+) if(si=.) flag3=false; cout(浮点数,; break; if(flag3) cout(整数,; /运算符函数void GetOperator(string s,int k) int i; for(i=0;i5;i+) if(s=symbol1i) switch(i) case 0:cout(加法运算符,; break; case 1:cout(减法运算符
15、,; break; case 2:cout(乘法运算符,; break; case 3:cout(除法运算符,; break; case 4:cout(求余运算符,; break; for(i=0;i5;i+) if(s=symbol2i) cout(条件运算符,; for(i=0;i5;i+) if(s=symbol3i) cout(关系运算符,; if(s=:=) cout(赋值运算符,; else if(s=- | s=+) cout(操作运算符,; else if(s=) cout(移位运算符,;/分隔符函数void GetSeparator() cout(分隔符,;实验1_2_1代码
16、:#include #include #include #include #include using namespace std;/随机产生长度为size的单词string GetStopWords(int size);int main() string str; int i,rows,aver; cout请输入行数和单词平均长度:rowsaver; for(i=1;i=rows;i+) int length; if(i%2) if(i=rows) length=aver; else length=rand()%(2*aver-1)+1; else length=2*aver-length;
17、 str=GetStopWords(length); coutstrendl; return 0;/随机产生长度为size的单词string GetStopWords(int size) int flag; string str=; for(int i=0;isize;i+) char ch; ch=char(rand()%26+97); flag=rand()%2; /大小写随机产生 if(flag) ch-=32; /将字符ch转换成大写 str+=ch; return str;实验1_2_2代码:#include #include #include #include #include u
18、sing namespace std;/随机产生长度为size的单词string GetFiles(int size); int main() int count,k,length; int num=1; string str; cout请输入文件大小和单词平均长度:countk; while(count0) if(num%2) length=rand()%(2*k-1)+1; else length=2*k-length; if(lengthcount) /判断是否发生截断 length=count; str=GetRandomString(length); cout1) if(rand()
19、%2) /随机产生回车换行 cout0) /产生空格 cout ; count-; num+; return 0;/随机产生长度为size的字符串string GetFiles(int size) int flag; string str=; for(int i=0;isize;i+) char ch; ch=char(rand()%26+97); flag=rand()%2; /大小写随机产生 if(flag) ch-=32; /将字符ch转换成大写 str+=ch; return str;实验1_2_3代码:#include#include#include#include#include#
20、includeusing namespace std;void GetStopWords(); /获得停用词表void GetFiles(); /获得待处理文件void SettleFiles(); /替换文件函数char *v,*f; /v是停用词,f是待处理文件int n,length; /n是禁用词个数,length是禁用词的平均长度int size,len; /size为待处理文件大小,len为单词平均长度int num,*key; /num是单词个数,key用来记录实际长度int main() GetStopWords(); GetFiles(); SettleFiles(); re
21、turn 0;/替换文件函数void SettleFiles() int i,j,k; ofstream cout(result.txt,ios:out); for(i=0;inum;i+) for(j=0;jn/2*2;j+) if(!strcmp(fi,vj) for(k=0;kkeyi;k+) fik=*; for(i=0;inum;i+) for(j=0;j=keyi;j+) coutfij; 实验1_3_1代码:/定义文法类class Grammarprivate: char VnMAX; /非终结符号集 int Vn_num; /非终结符号数目 char VtMAX; /终结符号集
22、 int Vt_num; /终结符号数目 string pMAX; /产生式集合 int P_num; /产生式数目 char start; /起始符号public: void Initial(); /初始化及输入文法类 void Display(); /输出化简后的文法 void RemoveProduction(); /无用产生式消除 void RemoveSingle(); /单产生式消除 ;实验1_3_2代码:#include #include #include #include using namespace std;const int MAX=100;/定义文法类class Gra
23、mmarprivate: char VnMAX; /非终结符号集 int Vn_num; /非终结符号数目 char VtMAX; /终结符号集 int Vt_num; /终结符号数目 string pMAX; /产生式集合 int P_num; /产生式数目 char start; /起始符号public: void Initial(); /初始化及输入文法类 void Display(); /输出化简后的文法 void RemoveProduction(); /无用产生式消除 void RemoveSingle(); /单产生式消除 ;void Grammar:Initial() int i=0,j=0,k=0,num; for(i=0;iMAX;i+) /初始化赋值 Vni=0; Vti=0; pi=0; i=0; coutnum; while(num-) cinVn+i; Vn_num=i; coutnum; while(num-) cinVt+j; Vt_num=j; coutnum; while(num-) cinp+k; P_num=k; coutstart;void Grammar:RemoveProduction() char Vn1MAX; string p1MAX; int
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1