1、编译原理课程设计编译原理课程设计设计题目:微型编译器设计题目:微型编译器设计目的:学生在学习编译原理课程过程中,结合构造编译程序的基本理论,总共用一周时间完成课程设计。要求用一种编程语言描述及上机调试,实现一个小编译程序(包括词法分析,语法分析,语义分析以及中间代码的产生等重要子程序),使学生将理论与实际应用结合起来,从而提高学生软件开发的能力。设计内容: 一、需求分析1.引言(1)编写目的本需求规格说明书是为了实现一个小编译程序而编写,主要面向程序员、测试员和最终用户。本说明书是整个软件开发的依据,它对以后阶段的工作起指导作用,也是项目完成后验收的依据。(2)背景说明编译原理课程设计要求我们
2、在学习过程中,结合构造编译程序的基本理论,总共用一周时间完成课程设计。要求用一种编程语言描述及上机调试,实现一个小编译程序(包括词法分析,语法分析,语义分析以及中间代码的产生等重要子程序),将理论与实际应用结合起来,从而提高软件开发的能力。 (3)参考资料编译原理,吕映芝、张素琴、蒋维杜编著,清华大学出版社编译原理,Alfred V.Aho等,李建中译,机械工业出版社软件工程,史济民、顾春华、李昌武、苑荣编著,高等教育出版社2.概述(1)功能概述:设计一个词法分析器,该词法分析器的功能包括:a.能够拼出语言中的各个单词;b.将拼出的标识符填入符号表;c.生成一个词法分析表,将单词的种别码和属性
3、值填入该文件,返回(种别码, 属性值)。用递归下降分析法实现对附录文法的语法分析与翻译,要求:a. 若语法正确,则用语法制导翻译法进行语义翻译:对可执行语句,应产生出四元式中间代码并输出到文件四元式表中;同时,生成一个符号表,把中间代码用到的符号也输出到符号表中。b. 若语法错误,要求指出出错性质和出错位置。出错处理应设计成一个出错处理子程序。3.数据流图与数据字典(1)数据流图:(2)数据字典: 数据流数据流名:单词表示别名:组成:种别码+属性值备注:数据流名:符号表示别名:组成:类型+名字+值备注:数据流名:四元式别名:组成:四元式操作码+第一操作数+第二操作数+结果变量备注: 数据项3数
4、据项名:种别码别名: 取值:正整数备注:数据项名:属性值别名:单词自身值取值:字符备注:数据项名:类型别名:变量类型取值:正整数备注:数据项名:名字别名:变量名字取值:字符备注:数据项名:值别名: 变量的值取值:正整数备注:数据项名:四元式操作码别名: 取值:字符备注:数据项名:第一操作数别名: 取值:整数或字符备注:数据项名:第二操作数别名: 取值:整数或字符备注:数据项名:结果变量别名: 取值:字符备注: 数据文件文件名:四元式中间代码文件别名:组成:四元式操作码+第一操作数+第二操作数+结果变量组织: 备注:文件名:词法结果分析文件别名:组成:种别码+属性值组织: 备注:文件名:符号表文
5、件别名:组成:类型+名字+值组织: 备注: 加工说明加工名称:词法分析编号:激发条件:运行代码加工逻辑:当用户运行代码时,调用词法分析函数,经过词法分析之后,生成词法分析结果文件和符号表文件。执行频率:每执行一次代码调用一次 加工名称:语法/语义分析编号:激发条件:运行代码加工逻辑:当用户运行代码时,调用词法分析函数,经过词法分析之后,再调用语法/语义分析程序,生成四元式文件 执行频率:每执行一次代码调用一次 二、概要设计1.引言1.1 编写目的完成系统得大致设计并明确系统的数据结构和软件结构,进一步细化得出的软件总体概貌,把它加工成在程序细节上非常接近源程序的软件表示。1.2 参考资料编译原
6、理,吕映芝、张素琴、蒋维杜编著,清华大学出版社编译原理,Alfred V.Aho等,李建中译,机械工业出版社软件工程,史济民、顾春华、李昌武、苑荣编著,高等教育出版社2.总体设计2.1 目标明确系统的数据结构和软件结构,给出内部软件和外部系统部件之间的接口定义,软件各个模块的功能说明,数据结构的细节以及具体要求。3.系统数据结构设计3.1逻辑结构设计词法分析结果表文件:种别码(即单词编号,kind)属性值(即单词本身,word)符号表:TYPE(类型)NAME30(名字)Value8(值)四元式中间代码文件:操作码(op)操作数1(op1)操作数2(op2)结果(result)三、详细设计 1
7、. 参考资料编译原理,吕映芝、张素琴、蒋维杜编著,清华大学出版社编译原理,Alfred V.Aho等,李建中译,机械工业出版社2 总体设计用一种编程语言描述及上机调试,实现一个小编译程序(包括词法分析,语法分析,语义分析以及中间代码的产生等重要子程序)。3 程序描述. scaner模块 功能:完成单词的识别。 入口参数:存放原程序数组 出口参数:词法的分析结果二元组及存放原程序的数组下标 详细逻辑(流程图表示). Stconst模块 功能:常量定义的处理 入口参数:当前读到的单词 出口参数:标识符名,标识符值和类型 详细逻辑(流程图表示). Stvar模块 功能:变量说明部分的处理 入口参数:
8、当前读到的单词 出口参数:标识符名,标识符值和类型 详细逻辑(流程图表示). stread模块功能:读语句的处理入口参数:当前读到的单词出口参数:无详细逻辑(流程图表示) . stwrite模块功能:写语句的处理入口参数:当前读到的单词出口参数:无详细逻辑(流程图表示) . expression模块 功能:赋值语句的处理 入口参数:当前读到的单词 出口参数:语义分析后的四元组文件 详细逻辑(流程图表示). e模块 功能:表达式的处理 入口参数:单词 出口参数:单词 详细逻辑(流程图表示). t模块 功能:项的处理 入口参数:单词 出口参数:单词 详细逻辑(流程图表示). f模块 功能:因子的处
9、理 入口参数:单词 输出结果:单词 详细逻辑(流程图表示)四、测试1 引言1.1 编写目的软件测试是为了发现软件的错误,该文档的读者对象是软件测试部门,以指导软件测试过程。1.2 参考资料编译原理,吕映芝、张素琴、蒋维杜编著,清华大学出版社编译原理,Alfred V.Aho等,李建中译,机械工业出版社软件工程,史济民、顾春华、李昌武、苑荣编著,高等教育出版社2.测试方案2.1词法分析模块的测试:测试的目的是保证一些标识符变量的书写正确具体是通过在程序中输入一些非法的标识符变量来检测错误。要求系统能给出错误的正确提示如:输入var 11a;结果为:ERROR:在第2行(变量的声明有错)2.2 R
10、ead和write模块的测试 测试的目的是保证Read和write函数中的参数正确具体是通过在程序中输入一些非法的参数来检测错误。要求系统能给出错误的正确提示如:输入read(5); write(6);结果为:ERROR:在第6行(rear的参数应为表识符) ERROR:在第7行(write的参数应为表识符)2.3语法和语义分析模块测试 测试的目的是保证语法和语义的正确具体是通过在程序中输入一些非法的语法和语义来检测错误。要求系统能给出错误的正确提示如:输入f:=2+3*(4+5;结果为:ERROR:在第5行(号没匹配 )3.软件需求测试结论经过软件的测试,系统基本上达到需求定义阶段所提出的功
11、能。设计思想: 1.算法思想: 首先预定单词的编码表如下: 单词符号种别编码12read3write4+5-6*7/8;9(10)11:=12131416=17=18,19标识符20数字211.1词法分析scaner()的算法思想:利用一个结构体来存放单词和种别码;对每个字符进行分析:如果是字母,并且下一个字符为字母或数字则继续读,把这些字符放到一个token数组中,直到不是字母或数字时看token中的字符是否为关键字,如果是为关键字赋相应种别码,否则赋上标识赋对应的种别码;如果为数字,并且下一个字符为字母或数字则继续读,把这些字符放到一个token数组中,直到不是字母或数字时看token中的
12、字符是否全为数字,如果是为数字赋对应的种别码,否则出错;如果是其他拼数(如*,/,等),为它们赋上对应的种别码。 其中部分单词的状态转换图如下: 识别标识符的状态转换图 识别数字的状态转换图1.2语法语义分析的入口模块P()的算法思想:利用词法分析的种别码来判断进行哪部分的分析,如果是常量,则调用常量说明函数stconst();如果是变量说明部分,则调用变量说明函数stvar();如果是赋值,则调用赋值的语句函数expression();如果是读和写语句,也就对应调用相应的函数stwtite()和stread();1.3填符号表模块的算法思想:利用一个结构体来存放变量名、变量值和类型这三个属性
13、;首先判断变量是哪种类型,然后给它们填上对应的变量名、变量值和类型。2.程序总流程图:设计体会:本次的课程设计我担任的任务是编码工作。通过一个星期的编译原理课程设计,我对词法分析、语法分析和语义分析有了更清晰的整体概念,对它们之间的联系更加清楚,总的来说基本顺利完成该课程设计。并且通过该课程设计,收获颇多。 对实验原理有更深的理解 通过该课程设计,掌握了什么是编译程序,编译程序工作的基本过程及其各阶段的基本任务,熟悉了编译程序总流程框图,了解了编译程序的生成过程、构造工具及其相关的技术对课本上的知识有了更深的理解。通过把该算法的内容,算法的执行顺序在计算机上实现,把原来以为很深奥的书本理论知识
14、变的更为简单,对实验原理有更深的理解。对该理论在实践中的应用有深刻的理解 通过把该算法的内容,算法的执行顺序在计算机上实现,知道和理解了该理论在计算机中是怎样执行的, 对该理论在实践中的应用有深刻的理解 。除此之外,通过这次的编码,对自己的编码有了些提高,尤其是对一些结构体的运用。源代码:C+语言实现#include#includeusing namespace std;#include #include char *rwtab4= CONST, VAR, read, write ;/关键字int tpos;int spos;int stpos=0;int k=1;int temp=0;cha
15、r* e(int& n);char* t(int& n);char* f(int& n);ofstream file4(四元式表.txt);struct save /四元组结构char ch1;int t1_place;int t2_place;int temp;sa100;struct store /词法分析结果,返回(种别码, 属性值)int id; /存放字符的种别编码char str8; /存放字符s100;struct symtable /符号表结构int type; char name20;char value8;st256;bool IsChar(char ch) /判断是否为字
16、母int sum=int(ch);if(sum=int(A)&(sum=int(a)&(sum=int(0)&(sum=int(9)return true;else return false;bool IsNull(char ch)/判断空格if(int(ch)= ) return true;else return false;/*词法分析,得到词法分析表*/void print(store s)/打印字符和对应的种别编码ofstream file1(词法分析表.txt);file1种别编码 自身值endl;for(int i=0;i100;i+) if(si.id!=-1) file1 si
17、.id si.strendl;cout si.id si.strendl;file1.close();int Row(int&n)/标记错误位置 int row=0; for(int i=0;in;i+) if(si.id=9) row=row+1; return row;int YNRdeclare(char cvar)int copare=-1;for(int i=0;istpos;i+)if(!strcmp(sti.name,cvar) if(sti.type=0) copare=1;/const else copare=2;/var break;return copare;void e
18、rror(int n ,int sign ,char *etemp=NULL)/输出错误信息switch(n)case 0:coutERROR: 在第+sign行 (出现非法变量或常量)endl;break;case 1:coutERROR: 在第+sign行 (未定义或重定义)endl;break;case 2:coutERROR: 在第+sign行 (应为等号)endl;break;case 3:coutERROR: 在第+sign行 (常量的值应为数字)endl;break;case 4:coutERROR: 在第+sign行 (应为字母)endl;break;case 5:coutER
19、ROR: 在第+sign行 (为非法变量)endl;break;case 6:coutERROR: 在第+sign行 (const后应为标识符)endl;break;case 7:coutERROR: 在第+sign行 (VAR后应为标识符)endl;break;case 8:coutERROR: 在第+sign行 (赋值应用“:=”号)endl;break;case 9:coutERROR: 在第+sign行 ((号没匹配)endl;break;case 10:coutERROR: 在第+sign行 (非法结束语句)endl;break;case 11:coutERROR: 在第+sign行
20、 (read参数应为标识符)endl;break;case 12:coutERROR: 在第+sign行 (write参数应不正确)endl;break;case 13:coutERROR: 在第+sign行 ()号没匹配)endl;break;case 14:coutERROR: 在第+sign行 (read语句后没;)endl;break;case 15:coutERROR: 在第+sign行 (write语句后没;)endl;break;case 16:coutERROR: 在第+sign行 (语法不正确)endl;break;case 17:coutERROR: 在第+sign行 et
21、emp 未定义endl;break;case 18:coutERROR: 在第+sign行 etemp 重定义endl;break;case 19:coutERROR: 在第+sign行 etemp 不能用常量endl;break;default:break;bool bcf=true;int scaner(char prog)/词法分析函数 char token8 ;spos=0;tpos=0;int j=0;int n=0;bool check=true;bool empty=false;for(spos;spos100;spos+) sspos.id=-1;spos=0;for ( n=
22、0; n8; n+ ) tokenn=NULL; for(int i=0;istrlen(prog)-1;i+)if(IsChar(progi) while(IsChar(progi)|IsNum(progi) tokentpos=progi; tpos+; i+; i-; bool bkey=false; for(j=0;j4;j+) if(!strcmp(token,rwtabj) sspos.id=j+1;strcpy(sspos.str,token);spos+;tpos=0;bkey=true;for(n=0;n8;n+) tokenn=NULL;break; if(!bkey) s
23、spos.id=20;strcpy(sspos.str,token);spos+;tpos=0;for(n=0;n8;n+) tokenn=NULL; elseif(IsNum(progi) int epro=Row(i); bool char_exit=false; while(IsNum(progi)|IsChar(progi) if(IsChar(progi) char_exit=true;tokentpos=progi;tpos+;i+; if(!char_exit) sspos.id=21; strcpy(sspos.str,token); for(n=0;ntpos;n+) tok
24、enn=NULL; tpos=0; spos+; i-; else error(0,epro); bcf=false; return 0; elseswitch(progi) case +: sspos.id=5; strcpy(sspos.str,+); spos+; break; case -: sspos.id=6; strcpy(sspos.str,-); spos+; break; case *: sspos.id=7; strcpy(sspos.str,*); spos+; break; case /: sspos.id=8; strcpy(sspos.str,/); spos+;
25、 break; case ;: sspos.id=9; strcpy(sspos.str,;); spos+; break; case (: sspos.id=10; strcpy(sspos.str,(); spos+; break; case ): sspos.id=11; strcpy(sspos.str,); spos+; break; case =: sspos.id=18; strcpy(sspos.str,=); spos+; break; case ,: sspos.id=19; strcpy(sspos.str,); spos+; break; case #: sspos.i
26、d=0; strcpy(sspos.str,#); spos+; break; case : i+; while(IsNull(progi) i+; if(progi=) sspos.id=12; strcpy(sspos.str,:=); spos+; break; else break; case : i+; while(IsNull(progi)i+; if(progi=) check=false; sspos.id=15; strcpy(sspos.str,) check=false; sspos.id=14; strcpy(sspos.str,); spos+; if(check)
27、sspos.id=13; strcpy(sspos.str,: i+; while(IsNull(progi) i+; if(progi=) sspos.id=17;strcpy(sspos.str,=);spos+; else sspos.id=16;strcpy(sspos.str,);spos+; break;if(bcf) print(s);return spos;/*词法分析完毕*/*语法/语义分析程序,得到符号表,*/bool bstconst=true;void stconst(int& n) /const声明处理 int epro=Row(n); ststpos.type=0;
28、 if(s+n.id=20) /为字母 int ynr=YNRdeclare(sn.str); if(ynr0) bstconst=false; error(18,epro,sn.str); return; strcpy(ststpos.name,sn.str); /为符号表填写变量名称 if(s+n.id=18) /为=号 if(s+n.id=21) /为数字 strcpy(ststpos+.value,sn.str); /为符号表填写变量值 if(s+n.id=19) /为逗号 stconst(n); else if(sn.id!=9) /语句结束,为分号,否则出错 error(10,ep
29、ro); bstconst=false; return; else bstconst=false; error(3,epro);/常量中的“=”后应为数字 return; else bstconst=false; error(6,epro);/常量后应为标识符 return; else error(6,epro); bstconst=false; bool bstvar=true;void stvar(int &n) /var声明处理 int epro=Row(n); ststpos.type=1; if(s+n.id=20) /为变量名 int ynr=YNRdeclare(sn.str);
30、 if(ynr=1) bstvar=false; error(18,epro,sn.str); return; strcpy(ststpos+.name,sn.str);/为符号表的变量名称赋值 if(s+n.id=19) /为逗号 stvar(n); elseif(sn.id!=9)/语句结束,为分号,否则出错error(10,epro);n-;bstvar=false;return; else error(7,epro);/VAR后应为标识符 bstvar=false; bool bstread=true;void stread(int &n) int epro=Row(n); if(s+
31、n.id=10) if(s+n.id=20) int ynr=YNRdeclare(sn.str); if(ynr0) bstvar=false; error(17,epro,sn.str); return; else if(ynr=1) bstvar=false; error(19,epro,sn.str); return; if(s+n.id!=11) error(13,epro);/)没匹配 else if(s+n.id!=9)error(14,epro);/没有;n-;bstread=false; else error(11,epro);/参数应为标识符 bstread=false;
32、else error(9,epro);/)没匹配 bstread=false; bool bstwrite=true;void stwrite(int &n) int epro=Row(n); if(s+n.id=10) if(s+n.id=20|sn.id=21) if(sn.id=20) int ynr=YNRdeclare(sn.str); if(ynr0) bstwrite=false; error(17,epro,sn.str); return; if(s+n.id!=11) error(9,epro);bstwrite=false; else if(s+n.id!=9) error
33、(15,epro);/没有;n-;bstwrite=false; else error(12,epro);/参数应为标识符 bstwrite=false; else error(9,epro);/)没匹配 bstwrite=false; bool bexpression=true;void expression(int &n) /遇到变量名,调用赋值函数 int epro=Row(n);char* ch1=sn.str;int ynr=YNRdeclare(sn.str);if(ynr=1) bexpression=false; error(18,epro,sn.str); return; if(ynr0) bexpression=false; error(17,epro,sn.str); return;if(sn+1.id!=12) /如果不是“:=”号k=0;error(8,epro);/赋值应用“:=”号bexpression=false;return;int sx=n+1;char* ch2=e(+n); /调用e函数if(