..编译原理实验报告实验名称:编写词法分析程序_______实验类型:设计型实验指导教师:专业班级:姓名:学号:实验地点:实验成绩:日期:2017年4月15日..实验一编写语法分析程序一、实验目的1)通过设计、调试词法分析程序,掌握词法分析程序的设计工具,即有穷自动机,进一步理解自动机理论;2)掌握正则文法和正则表达式转换成有穷自动机的方法及有穷自动机的实现方法;3)会确定词法分析程序的输出形式及标识符与关键字的区分方法;4)加深对课堂教学的理解,提高词法分析方法的实践能力,掌握使用实验环境的技能技巧以及程序的调试方法。二、实验设计1、写出TEST语言每条词法规则对应的正则文法或者正则表达式1)标识符:字母打头,后接任意字母或数字。正则表达式:(a|b|……|z|A|B……|Z)(0|1|……|9|a|b|……|z|A|B……|Z)*2)保留字:标符的子集,包括:if,else,for,while,do,int,write,read。正则表达式:if|else|for|while|do|int|write|read3)无符号整数:由数字组成,但最高位不能为0,允许一位的0。正则表达式:((1……|9)(0|1|……|9)*)|04)分界符:(、)、;、{、}正则表达式:(|)|;|{|}5)运算符:+、-、*、/、=、、、=、=、!=、==正则表达式:+|-|*|/|=|||=|=|!=|==6)注释符:/**/正则表达式:/*(没有连续的*/的任意字符串|ℇ)*/2、对每个文法或者正则表达式分别构造NFA1)标识符:(a|b|……|z|A|B……|Z)(0|1|……|9|a|b|……|z|A|B……|Z)*AA1A2(a|b|z|A|BZ)(0|1|……|9|a|b|z|A|BZ)A3..2)无符号整数:((1|2|……|9)(0|1|……|9)*)|0BB1B2B3(1|2||9)(0|1||9)03)分界符:(|)|;|{|}(|)|;|{|}CC14)运算符:+|-|*|/|=|||=|=|!=|==DD2D3+|-|*|/=||!==D15)注释符:/*(没有连续的*/的任意字符串|ℇ)*/EE6E1E2/*E3E4非**E5*/非*|非/3、将NFA合并,确定化,化简得到最终的DFA。NFA:..AAA1A2(a|b|z|A|BZ)(0|1|……|9|a|b|z|A|BZ)A3BB1B2B3(1|2||9)(0|1||9)0(|)|;|{|}CC1DD2D3+|-|*=||!==D1EE6E2/*E3E4非**E5*/非*|非/E1DFA:..Aa|b|z|A|BZ0|1|……|9|a|b|z|A|BZ0|1||9E3/*E1非**E2*/非*|非/E1|2||9(|)|;|{|}+|-|*ABB10CDD1D2!==||=三、实验过程1、完成整个实验的先后步骤a)根据TEST语言的词法规则,分别写出每条规则的正则文法或者正则表达式;b)将每一个正则文法或者正则表达式转换为NFA;c)将多个NFA合并后进行确定化并化简;d)根据化简后的DFA画出流程图;e)参阅教材PP.69-71的TEST语言语法规则,确定单词分类、单词输出方案;f)编写词法分析程序;g)对下面的TEST语言源程序进行词法分析,将合法单词存入lex.txt,并报告词法错误及其位置。注:不能修改源程序..{/*Thisatestprogram.*/intabc;int123;intA$@;inti;intn;intb,c;int2a;inta2;readn;n=012345;for(i=1;i=n;i=i+1){abc=abc+i;}if(i!=n)n=n+i;if(!n)b=b+c;/*Theloopendedwriteabc;}2、实验调试记录(问题表现,分析原因,解决方案,解决结果)a)问题表现:1.不能处理除号2.不能处理不完整的注释符3.对于”0123”这类字符串的处理不正确,我之前处理为直接报错说一位以上的数字首位不能为0b)分析原因:问题1,2的原因都是在“/”符号处理时出现的问题导致的,程序中出现bug使得一遇到‘/’就会进入死循环。问题3,不应该直接报错说一位以上的数字首位不能为0,遇到0应该直接输出0这个单词,再接着读数字。c)解决方案:d)对于问题1,2,重新梳理逻辑,一步一步对照流程图和DFA来调试修改代码。对于问题3,遇到0应该直接输出0这个单词,再接着读数字。e)解决结果:成功解决了程序遇到‘/’进入死循环问题和“0123”这类字符串的处理。三、实验结果..列出实验结果并进行分析(含分步测试结果)。lex.txt文件(存放编译的合法内容)内容:1{{2/*Thisatestprogram.*//*Thisatestprogram.*/3intint3IDabc3;;4intint4NUM1234;;5intint5IDA5;;6intint6IDi6;;7intint7IDn7;;8intint8IDb8IDc8;;9intint9NUM29IDa9;;10intint..10IDa210;;11readread11IDn11;;12IDn12==12NUM012NUM1234512;;13forfor13((13IDi13==13NUM113;;13IDi13==13IDn13;;13IDi13==13IDi13++13NUM113))14{{15IDabc15==15IDabc15++15IDi15;;16}}..17ifif17((17IDi17!=!=17IDn17))17IDn17==17IDn17++17IDi17;;18ifif18((18IDn18))18IDb18==18IDb18++18IDc18;;四、讨论与分析1.你的编写词法分析程序满足最长匹配原则吗?如果满足请给出你的实现方案。如果不满足请给出改进方案。答:不满足,我的处理先后顺序是:标识符或保留字、数字、分界符、运算符(除开/)、除或者注释,我应该吧注释放在前面,因为一般来说注释都比其它类型符号长些。改进措施便是将注释这一条词法规则最早处理。2.给出你的单词分类方案,并说明理由。答:根据TEST语言可将单词分为六类:a)标识符:字母打头,后接任意字母或数字。b)保留字:标识符的子集,包括:if,else,for,while,do,int,write,read。c)无符号整数:由数字组成,但最高位不能为0,允许一位的0。d)分界符:(、)、;、{、}..e)运算符:+、-、*、/、=、、、=、=、!=、==f)注释符:/**/3.构建词法分析程序一般过程是怎样的?答:构建词法分析程序的一般过程:1、根据词法规则写出正则文法或者正则文法。2、为每一个正则表达式构造一个NFA,然后将多个NFA合并为一个NFA3、将NFA转化成DFA,并且化简最小化DFA4、确定单词的输出形式5、根据化简后的DFA和单词输出程序构造词法分析程序(主要部分:通过实验对课程知识点的理解;回答实验指导书的实验思考提出的问题等)五、附录:关键代码(给出适当注释,可读性高)#includeiostream#includefstream#includestdio.h#includestdlib.h#includestringusingnamespacestd;constintKWN=8;//关键字的个数constintMAXSIZE=400;//标识符最长个数charkword[KWN][10]={//关键字if,else,for,while,do,int,read,write};intline=1;//行号interrors=0;//记录错误个数ofstreamfout;//输出文件流ifstreamfin;//输入文件流..ofstreamlexout;//存放合法单词的文件流chartype[6][30]={ID,保留字,NUM,分界符,运算符,注释符};intmain(){intTEST();//函数声明TEST();if(errors==0){cout编译成功。endl;}else{cout编译失败。共发现errors个错误!endl;}return0;}////判断是否为字母intis_Char(charch){if((ch='a'&&ch='z')||(ch='A'&&ch='Z')){return1;}return0;}////判断是否为无符号整数..intis_Uint(charch){if('0'=ch&&ch='9'){return1;}return0;}////判断是否为分界符intis_Deli(charch){if(ch=='('||ch==')'||ch==';'||ch=='{'||ch=='}'){return1;}return0;}////判断是否为操作符intis_Oper(charch){charOperater[10]=+-*!=;//没有考虑/号for(inti=0;i8;i++){if(ch==Operater[i]){return1;}}return0;}////输入控制intin(char&ch)..{fin.get(ch);if('\n'==ch){line++;}if(fin.eof()){ch=EOF;}return1;}////输出控制voidout(char*type,char*buf){if(strcmp(type,ID)==0||strcmp(type,NUM)==0)lexoutlinetypebufendl;elselexoutlinebufbufendl;//couttype:bufendl;}////编译程序主要的函数intTEST(){intevent=0;//用于判断输入是否为文件末//charfilename[300];//存储文件的路径//////打开文件的操作//打开编译程序存放合法单词的文件lexout.open(lex.txt);//打开用户的文件//cout请输入要编译的文件的路径:endl;reinput_in://cin.get(filename,300,'\n');..//charfilename[300]={D:\Software\MicrosoftVisualC++6.0\MicrosoftVisualStudio\MyProjects\编译原理实验一\in.txt};fin.open(in.txt);if(fin==NULL){cout文件打开失败,请重新输入文件路径:endl;gotoreinput_in;}//cout请输入词法分析结果文件存储路径:endl;reinput_out:cin.clear();//清理输出缓冲cin.sync();//清空流//cin.get(filename,300,'\n');//charfilename[300]={D:\Software\MicrosoftVisualC++6.0\MicrosoftVisualStudio\MyProjects\编译原理实验一\out.txt};fout.open(out.txt);if(fout==NULL){cout文件打开失败,请重新输入文件路径:endl;gotoreinput_out;}//////开始判断charbuf[300];charch;cin.clear();//清理输出缓冲cin.sync();//清空流in(ch);while(!fin.eof()){while(ch==''||ch=='\n'||ch=='\t'||ch=='\r'){in(ch);}..//判断是否为标识符或保留字if