合肥工业大学编译原理实验报告代码版.doc
-计算机与信息学院 编译原理 实验报告实验1 词法分析设计一、 实验目的 通过本实验的编程实践,使学生了解词法分析的任务,掌握词法分析程序设计的原理和构造方法,使学生对编译的根本概念、原理和方法有完整的和清楚的理解,并能正确地、熟练地运用二、 实验要求 1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。2、将标识符填写的相应符号表须提供应编译程序的以后各阶段使用。 3、根据测试数据进展测试。测试实例应包括以下三个局部: u 全部合法的输入。 u 各种组合的非法输入。 u 由记号组成的句子。 4、词法分析程序设计要求输出形式: 例:输入VC+语言的实例程序: If i=0 then n+; a= 3b %); 输出形式为: 单词 二元序列 类 型 位置行,列 单词种别,单词属性for (1,for ) 关键字 1,1 i ( 6,i ) 标识符 1,2 = ( 4,= ) 关系运算符 1,3 12 0 ( 5,0 ) 常数 1,4 then ( 1,then) 关键字 1,5 n (6,n ) 标识符 1,6 + Error Error 1,7 ; ( 2, ; ) 分界符 1,8a (6,a ) 标识符 2,1 = (4,<= ) 关系运算符 2,2 3b Error Error 2,4 % Error Error 2,4 ) ( 2, ) ) 分界符 2,5 ; ( 2, ; ) 分界符 2,6 三、 实验容用 VC+/VB/JAVA 语言实现对 C 语言子集的源程序进展词法分析。通过输入源程序从左到右对字符串进展扫描和分解,依次输出各个单词的部编码及单词符号自身值;假设遇到错误则显示“Error,然后跳过错误局部继续显示 ;同时进展标识符登记符号表的管理。 以下是实现词法分析设计的主要工作: 1从源程序文件中读入字符。 2统计行数和列数用于错误单词的定位。 3删除空格类字符,包括回车、制表符空格。 4按拼写单词,并用码,属性二元式表示。(属性值token的机表示) 5如果发现错误则报告出错 7 6根据需要是否填写标识符表供以后各阶段使用。四、实验步骤1、根据流程图编写出各个模块的源程序代码上机调试。 2、 编制好源程序后,设计假设干用例对系统进展全面的上机测试,并通过所设计的词法分析程序;直至能够得到完全满意的结果。 3、书写实验报告 ;实验报告正文的容: u 功能描述:该程序具有什么功能? u 程序构造描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图。 u 详细的算法描述程序总体执行流程图 。 u 给出软件的测试方法和测试结果。 u 实验总结 设计的特点、缺乏、收获与体会。 五、实验截图先创立salaryfile.t*t文件输入If i=0 then n+; a<= 3b %);6、 核心代码*include<iostream>*include<string>*include<fstream>*include <sstream>using namespace std;const char* salaryfile="salaryfile.t*t"const int ma*=40;string idma*="do","end","for","if","printf","scanf","then","while"/关键字表string sma*=",","","(",")","","","+","-","*","/","<","<=","=",">",">=","<>"/分界符表 算数运算符表 关系运算符表string kma*;/ 标识符string cima*;/ 常数int fjfpoint=5;/分界符表尾int mathpoint=9;/算数运算符表尾int cipointer=0;/常数表尾int idpointer=0;/关键字表尾int kpointer=0;/标识符表尾int fjf;/0 不是分界符 1是int rowy=1;/识别输入行位置int row*=1;/识别输入列位置int outkey=0;/打印控制 0为数字后有字母 其他可以void searcht(int i,string m)/根据已识别的首字母识别字符串/cout<<"enter searcht!"<<endl;int *;if(i=0)/首字符是字母识别关键字/cout<<" a word!"<<endl;for(*=0;*<ma*;*+)if(id*=m)cout<<"(1,"<<id*<<")"<<" 关键字 ("<<rowy<<","<<row*<<")"<<endl;break;if(*=ma*)/不是关键字再识别标识符for(*=0;*<ma*;*+) if(k*=m) cout<<"(6,"<<m<<") "<<"标识符 ("<<rowy<<","<<row*<<")"<<endl;break; if(*=ma*)/标识符表没有时插入标识符cout<<"(6,"<<m<<") "<<"标识符 ("<<rowy<<","<<row*<<")"<<endl;kkpointer=m;kpointer+;if(i=1)/识别常数/cout<<" a number!"<<endl;for(*=0;*<ma*;*+)if(ci*=m)cout<<"(5,"<<*<<")"<<endl;break;if(*=ma*) cout<<"(5,"<<m<<") 常数 ("<<rowy<<","<<row*<<")"<<endl;cicipointer=m;cipointer+;if(i=2)/识别 分界符 算数运算符 关系运算符/cout<<" a signal!"<<endl;for(*=0;*<ma*;*+)if(s*=m)break;/*-;if(*<6)fjf=1;if(*>5&&*<10)if(outkey=1) cout<<"(3,"<<s*<<") 算数运算符 ("<<rowy<<","<<row*<<")"<<endl; outkey=0;fjf=0;if(*>9&&*<ma*-1)if(outkey=1) cout<<"(4,"<<s*<<") 关系运算符 ("<<rowy<<","<<row*<<")"<<endl; outkey=0;fjf=0;if(*=ma*)if(outkey=1)cout<<"Error Error ("<<rowy<<","<<row*<<")"<<endl;outkey=0;fjf=0;void wordlook(char t,string sn)/识别首字符,分类识别字符串if(t>=48&&t<=57)searcht(1,sn);elseif(t>64&&t<91)|(t>96&&t<123) searcht(0,sn);else searcht(2,sn);void split(string s)/分割字符串/cout<<s<<endl;string nowma*;string sn;int nowpointer=0;int i=0;int *;int sign=2;/非法数字标志int diannumber=0;/数中点的个数for(*=0;*<s.length();*+)if(s*>64&&s*<91)|(s*>96&&s*<123)|(s*>=48&&s*<=57)|(*>0&&s*=46&&sign=1)/判断数字后跟字母还是字母后有数字if(i=0)if(s*>=48&&s*<=57)sign=1;else sign=2;elseif(sign=1)if(s*>=48&&s*<=57|s*=46)if(s*=46)if(diannumber=0)diannumber+;else sign=0;else sign=0;i+;if(*=(s.length()-1) sn=s.substr(*-i+1,i); if(i>0) / cout<<sn<<" i="<<i<<endl; cout<<sn<<" " if(sign=0)/数字后有字母的情况 cout<<" Error Error ("<<rowy<<","<<row*<<")"<<endl; else /字母开头的字符串 / cout<<" true"<<endl; wordlook(sn0,sn); row*+; elseif(*>0&&(s*-1>64&&s*-1<91)|(s*-1>96&&s*-1<123)|(s*-1>=48&&s*-1<=57)/遇到分界符运算符 如果前面是数字或字母 sn=s.substr(*-i,i); if(i>0) / cout<<sn<<" i="<<i<<endl; cout<<sn<<" " if(sign=0)cout<<" Error Error ("<<rowy<<","<<row*<<")"<<endl; else / cout<<" true"<<endl; wordlook(sn0,sn); row*+; i=0;string ll=s.substr(*,1);/判断是运算符还是分界符wordlook(s*,ll);if(fjf=0)/是运算符i+;if(s*+1>64&&s*+1<91)|(s*+1>96&&s*+1<123)|(s*+1>=48&&s*+1<=57)/如果后面是数字或字母sn=s.substr(*-i+1,i); / cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" "outkey=1; wordlook(sn0,sn); row*+; i=0;if(fjf=1) if(s*-1>64&&s*-1<91)|(s*-1>96&&s*-1<123)|(s*-1>=48&&s*-1<=57)/如果前面是数字或字母 else if(i>0) sn=s.substr(*-i,i); / cout<<sn<<"运算符 i="<<i<<endl;cout<<sn<<" "outkey=1; wordlook(sn0,sn); row*+; i=0; cout<<s*<<" (2,"<<s*<<") 分界符 ("<<rowy<<","<<row*<<")"<<endl; row*+;/* if(ll="") rowy+; row*=1; */;int main()int *;string instring;/读入一行string sn;/*getline(cin,sn);/ string带空格输入cout<<sn<<endl;char t=sn0;if(t>=48&&t<=57)searcht(1,sn);elseif(t>64&&t<91)|(t>96&&t<123) searcht(0,sn);else searcht(2,sn);*/ifstream inputfile;/in file streaminputfile.open(salaryfile);/inputfile>>noskipws;if(!inputfile)cout<<"no file"<<endl;string pp;while(!inputfile.eof() getline(inputfile,pp);istringstream istr(pp); string ppword;while(istr>>ppword)/按照空格分割字符串split(ppword);/*int begin = 0;/去掉字符串的所有空格begin = pp.find(" ",begin); /查找空格在str中第一次出现的位置while(begin != -1) /表示字符串中存在空格 pp.replace(begin, 1, ""); / 用空串替换str中从begin开场的1个字符 begin = pp.find(" ",begin); /查找空格在替换后的str中第一次出现的位置 */cout<<"good "<<pp<<endl;/row*+; rowy+;/换行row*=1;return 0;七、实验总结通过本次试验使我不仅对词法分析器有了更深的了解,而且提高了编程能力,希望在以后的学习中可以解决词法分析更多的问题。实验2 LL(1)分析法 一、实验目的通过完成预测分析法的语法分析程序,了解预测分析法和递归子程序法的区别和联系。使学生了解语法分析的功能,掌握语法分析程序设计的原理和构造方法,训练学生掌握开发应用程序的根本方法。有利于提高学生的专业素质,为培养适应社会多方面需要的能力。二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。 2、如果遇到错误的表达式,应输出错误提示信息。 3、对以下文法,用 LL1分析法对任意输入的符号串进展分析: 1E->TG 2G->+TG|TG 3G->4T->FS 5S->*FS|/FS 6S->7F->(E) 8F->i u三、实验容根据*一文法编制调试 LL 1 分析程序,以便对任意输入的符号串进展分析。 u 构造预测分析表,并利用分析表和一个栈来实现对上述程序设计语言的分析程序。 u 分析法的功能是利用 LL1控制程序根据显示栈栈顶容、向前看符号以及 LL1分析表,对输入符号串自上而下的分析过程。 四、实验步骤 1、根据流程图编写出各个模块的源程序代码上机调试。 2、 编制好源程序后,设计假设干用例对系统进展全面的上机测试,并通过所设计的 LL(1)分析程序;直至能够得到完全满意的结果。 3、书写实验报告 ;实验报告正文的容: u 写出 LL1分析法的思想及写出符合 LL1分析法的文法。 u 程序构造描述:函数调用格式、参数含义、返回值描述、函数功能;函数之间的调用关系图。 u 详细的算法描述程序执行流程图 。 u 给出软件的测试方法和测试结果。 u 实验总结 设计的特点、缺乏、收获与体会。五、实验截图6、 核心代码 *include<iostream>*include<string>using namespace std;string pp;/输出字符串string hh="rn"/换行const int ma*=50;int endfuma*;/终止符序号表int endfupointer=8;char endfurealma*='+','-','*','/','(','i',')','*'int unendfuma*;int unendfupointer=5;char unendfurealma*='E','G','T','S','F'string makemathma*="E->TG","G->+TG","G->-TG","G->$","T->FS","S->*FS","S->/FS","S->$","F->(E)","F->i"/0 E->TG,1 G->+TG,2 G->-TG,3 G->$,4 T->FS,5 S->*FS,6 S->/FS,7 S->$,8 F->(E),9 F->i/$代表空串string behaviorma*="初始化","POP"int smarttablema*ma*;/分析表int checkendfu(char fu)/查终结符序号int *;for(*=0;*<endfupointer;*+)if(endfureal*=fu)break;if(*<endfupointer)return *;else return -1;int checkunendfu(char fu)/查非终结符序号int *;for(*=0;*<unendfupointer;*+)if(unendfureal*=fu)break;if(*<unendfupointer)return *;else return-1;string checkmakemath(int *)/查产生式表return makemath*;int checksmarttable(int *,int y)/查分析表return smarttable*y;class smartbo*public:smartbo*()bo*0='*'bo*1='E'bo*pointer=1;void push(char fu)bo*pointer+;bo*bo*pointer=fu;char pop()char a=bo*bo*pointer;if(a!='*')/cout<<"pop: "<<bo*pointer<<" "<<a<<endl;/stringstream oss;/*pp=pp+"pop: "char bufferma*;sprintf(buffer,"%d",bo*pointer);string s=buffer;pp=pp+" "pp=pp+s;pp=pp+hh;*/bo*pointer-;return a;void check()if(checkendfu(bo*bo*pointer)!=-1)char a;/cout<<bo*bo*pointer<<checkendfu(bo*bo*pointer)<<" "/char bufferma*;/sprintf(buffer/pp=pp+bo*bo*pointer;/pp=pp+checkendfu(bo*bo*pointer);/pp=pp+" "a=pop();/cout<<"out "<<a<<endl;char bo*ma*;int bo*pointer;int main()/ TODO: Add e*tra validation here/pp=pp+"步骤 分析栈 剩余输入串 所用产生式 动作"+hh;/*string s1="sdsfs rnsdfsds"string s3="aaaaaaaaaaaaa"s3=s3+s1;CString s2(s3.c_str();/CString s2=CString(s1); SetDlgItemTe*t(IDC_EDIT2,s2);/用SetDlgItemTe*t(文本框ID,字符串),将文本框的容设置为字符串的容. SetDlgItemTe*t(IDC_EDIT2,s2);*/MessageBo*(str);string str;cin>>str;int *,y;for(*=0;*<ma*;*+) /初始化分析表 99为错误代号for(y=0;y<ma*;y+)smarttable*y=99; smarttable04=0;smarttable05=0;smarttable10=1;smarttable11=2;smarttable16=3;smarttable17=3;smarttable24=4;smarttable25=4;smarttable30=7;smarttable31=7;smarttable32=5;smarttable33=5;smarttable36=7;smarttable37=7;smarttable44=8;smarttable45=9;smartbo* mark;char fu;char enterfu;int endfunumber;int unendfunumber;string readyin;string enter;/cin>>enter; /enter="i+i*i*"enter=str;/enter="(i)*"int count=0;/步骤char buffer1ma*; sprintf(buffer1,"%d",count); string s1=buffer1;pp=pp+s1+" " /分析栈for(int qq1=0;qq1<=mark.bo*pointer;qq1+)pp=pp+mark.bo*qq1; for(qq1=0;qq1<10-mark.bo*pointer;qq1+)pp=pp+" "/剩余输入栈string jiequ1=enter.substr(0,enter.length();pp=pp+jiequ1;for(int t1=0;t1<20;t1+)pp=pp+" " pp=pp+" 初始化"+hh;for(*=0;*<enter.length();) /步骤 count+;char bufferma*; sprintf(buffer,"%d",count); string s=buffer;pp=pp+s+" " /分析栈for(int qq=0;qq<=mark.bo*pointer;qq+)pp=pp+mark.bo*qq; for(qq=0;qq<10-mark.bo*pointer;qq+)pp=pp+" "/剩余输入栈string jiequ=enter.substr(*,enter.length()-*);pp=pp+jiequ;for(int t=0;t<*+10;t+)pp=pp+" "enterfu=enter*;/cout<<"enterfu: "<<enterfu<<endl;mark.check();fu=mark.pop();/cout<<"fu: "<<fu<<endl;if(fu='*')/&&enterfu='*')/cout<<"sucessed! over!"<<endl;pp=pp+"sucessed! over!"+hh;break;unendfunumber=checkunendfu(fu);endfunumber=checkendfu(enterfu);/cout<<unendfunumber<<endl;/cout<<endfunumber<<endl;if(smarttableunendfunumberendfunumber=99)pp=pp+"error!"break;readyin=makemathsmarttableunendfunumberendfunumber;pp=pp+readyin;for(int ddd=0;ddd<14-readyin.length();ddd+)pp=pp+" " pp=pp+"POP,PUSH("for(y=readyin.length()-1;y>2;y-)pp=pp+readyiny;pp=pp+")"+hh;/cout<<"readyin: "<<readyin<<endl;int firsttime=0;for(y=readyin.length()-1;y>2;y-)/cout<<readyiny<<" "if(readyiny!='$') mark.push(readyiny); if(firsttime=0) if(checkendfu(readyiny)!=-1) / cout<<"now *: "<<*<<" " /步骤 count+;char bufferma*; sprintf(buffer,"%d",count); string s=buffer;pp=pp+s+" " /分析栈for(int qq=0;qq<=mark.bo*pointer;qq+)pp=pp+mark.bo*qq; for(qq=0;qq<10-mark.bo*pointer;qq+)pp=pp+" "/剩余输入栈string jiequ=enter.substr(*,enter.length()-*);pp=pp+jiequ;for(int t=0;t<*+10;t+)pp=pp+" " pp=pp+" GETNE*T(I)"+hh; *+;/ cout<<"ne*t *: "<<*<<" "<<endl;firsttime=1; mark.check();/cout<<endl;/pp=pp+hh;cout<<pp;return 0;/CDialog:OnOK();七、实验总结 通过本次试验使我不仅对ll(1)分析法有了更深的了解,而且提高了编程能力,希望在以后的学习中可以解决自动构造follow集的问题。 实验3 LR(1)分析法 一、实验目的构造 LR(1)分析程序,利用它进展语法分析,判断给出的符号串是否为该文法识别的句子,了解 LRK分析方法是严格的从左向右扫描,和自底向上的语法分析方法。 二、实验要求1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。 2、如果遇到错误的表达式,应输出错误提示信息。 3、程序输入/输出实例: 输入一以*完毕的符号串(包括+*i*):在此位置输入符号串 输出过程如下: 步骤 状态栈 符号栈 剩余输入串 动 作 1 0 * i+i*i* 移进 i+i*i 的 LR分析过程 步骤 状态栈 符号栈 输入串 动作说明 1 0 * i+i*i* ACTION0,i=S5,状态5入栈 2 05 *i +i*i* r6: Fi 归约,GOTO(0,F)=3 入栈 3 03 *F +i*i* r4: TF归约,GOTO(0,T)=3 入栈 4 02 *T +i*i* r2: ET归约,GOTO(0,E)=1 入栈 5 01 *E +i*i* ACTION1,+=S6,状态6入