广工编译原理课程设计报告

合集下载

编译原理课程设计报告

编译原理课程设计报告

《编译原理》课程设计报告一、课程设计目的通过课程设计进一步理解高级语言在计算机中的执行过程,了解现代编译器的运作机制,加深对编译原理中重点算法和编译技术的理解,提高自己自学和理解的能力。

学会如何利用已有软件JFLex、Java_cup对词法分析器及语法分析器的构造。

二、设计概述本tiger语言编译器的编译过程涉及到编译五个阶段中的二个,即词法分析器、语法分析器。

其中语法分析后还完成了语法树的打印的构造以及类型检查。

词法分析器由JFLex编译正则式生成,词法分析器编译产生式生成,语法分析器由CUP生成。

结果通过GUI界面呈现在使用者面前。

编译程序需要在单词级别上来分析和翻译源程序,所以首先要识别出单词,而词法分析部分的任务是:从左至右扫描源程序的字符串,按照词法规则(正则文法规则)识别出一个个正确的单词,并转换成该单词相应的二元式(种别码、属性值)交给语法分析使用。

因此,词法分析是编译的基础。

执行词法分析的程序称为词法分析器。

语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作。

三、设计过程(一)设计构思程序主要完成三大功能模块:词法分析器、语法分析器、GUI人机交互界面。

词法分析器由JFLex编译正则式生成,其中必须为外界提供一个获取记号流的接口,实验中定为java_cup.runtime.Symbol next_token。

语法分析器是建立在词法分析器上的,故必须包含词法分析器以便获得记号流,next_token为语法分析器提供TOKEN,语法分析器的对外接口是:java_cup.runtime.Symbol debug_parse(),同时返回语法树的根节点。

GUI 界面是提供人机交互的,它能够依次显示词法分析阶段分析得到的所有TOKEN 的信息,语法阶段生成的语法树,另外对于词法和语法阶段出现的错误在“错误提示”文本框中一一列举出来,提供用户改进代码的信息。

编译原理课程设计报告

编译原理课程设计报告

课程设计报告( 2021--2022年度第一学期)名称:编译技术课程设计题目:算符优先分析法研究院系:班级:学号:学生姓名:指导教师:设计周数:一周成绩:日期:2021年12 月31日1 课程设计的目的和要求1.1 课程设计的目的本次设计的时间为1周,目的是通过使用高级语言实现部分算法加强对编译技术和理论的理解。

设计的题目要求具有一定的规模,应涵盖本课程内容和实际应用相关的主要技术。

1.2 课程设计的要求1. 文法使用产生式来定义;2. 分别给出每一个非终结符的FIRSTVT和LASTVT集。

3. 画出算符优先关系表;4. 判定给定的文法是否是算符优先文法;5. 给定符号串判定是否是文法中的句子,分析过程用分析表格的方式打印出来。

2 系统描述举例如下:本次实验使用Visual Studio 2019软件,利用只规定终结符之间的优先关系的自底向上移进-规约法实现对算符优先分析法的研究,输出非终结符的FIRSTVT和LASTVT集,算符优先关系表和对句子的分析表格,均在DOS窗口显示。

2.1 文法的描述G[S]: S->#E#;E->E+T|T;F-P!F|P;T->T*F|F;P->(E)|i2.2 属性文法的描述表2-1 条件语句及其语义规则3 概要设计3.1 概要设计(体现系统的设计思路和主要功能)主要步骤包括:用户自己输入文法,实质上是算数表达式的计算。

构建每个非终结符的FirstVT()和LastVT()集。

构建优先关系符号表。

构建词法分析的程序。

编写主函数,用户输入文法对语句利用算符优先文法进行判别。

算法的主体思想:用栈存储已经看到的输入符号,用优先关系指导移动归约语法分析器的动作,如果栈顶的终结符和下一个输入符之间的优先关系是<或=,则语法分析器移动,表示还没有发现句柄的右端,如果是>关系,就调用归约。

3.2 开发环境实验采用C++程序语言进行设计开发工具为Visual Studio 20194 详细设计4.1 系统的类图图4-1 文法类图4.2 主要算法的流程图图4-2 求非终结符的FIRSTVT 和LASTVT 集流程图求LASTVT 集的过程与此类似,但符号串的扫描顺序是从后开始若产生式右部第一个字符为非终结符 则直接将其加入first 集中else first[x].insert(str[0]);寻找该非终结符 的first 集 dfs(y);将该非终结符的first 集也加进去for (; it != first[y].end(); it++)first[x].insert(*it);if (isupper(str[0]))若产生式右部第一个字符为非终结符 string& left = VN_set[x].left;string&str = VN_set[x].right[i];产生产生式左部非终结符的FIRSTVT 集图4-3 构造算符优先关系表流程图图4-4 对输入串进行算符优先分析流程图4.3 数据分析与定义char relation[MAX][MAX]; //算符优先关系表vector<char> VT;vector<WF> VN_set; //类型为文法的数组VN_setmap<string, int> VN_dic; //map映射,一条产生式对应的第几条的序号set<char> first[MAX]; //FIRSTVT集set<char> last[MAX]; //LASTVT集4.4 系统界面设计用户输入文法个数和每条产生式的内容后,输出结果格式如下:分为:产生式、FIRSTVT集、;LASTVT集、算符优先关系表和分析过程图4-5 系统输出界面概况5 测试方法和测试结果5.1 测试用例1输入如程序5-1所示。

广东工业大学编译原理课设

广东工业大学编译原理课设

课程设计课程名称编译原理题目名称对PL/0的修改与扩充学生学院计算机学院专业班级学号学生姓名指导教师2014 年 1 月 3 日一.课程设计目的在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。

达到进一步了解程序编译过程的基本原理和基本实现方法的目的。

二.课程设计要求(1)扩充赋值运算:*= 和 /=(2)扩充语句(Pascal 的FOR 语句):FOR <变量>:=<表达式>STEP<表达式> UNTIL<表达式>Do<语句>三.课程设计环境与工具1. 程序运行环境:(1)运行平台:Windows XP(2)实现工具:Borland C++ Building 6.0(3)教学型编译程序:PL/0 2.源程序:PL/0 源代码四.结构设计说明PL/0编译程序的结构图Pl0 源 程 序词法分析程序语法分析程序代码生产程序目 标 程 序表 格 管 理程序出错 处 理 程 序各功能模块描述过程或函数名简要功能说明pl0 主程序error 出错处理,打印出错位置和错误编码getsym 词法分析,读取一个单词getch 漏掉空格,读取一个字符gen 生成目标代码,并送入目标程序区test 测试当前单词符号是否合法block 分程序分析处理过程enter 登录名字表position(函数) 查找标识符在名字表中的位置constdeclaration 常量定义处理vardeclaration 变量说明处理listode 列出目标代码清单statement 语句处理expression 表达式处理term 项处理factor 因子处理condition 条件处理interpret 对目标代码的解释执行程序base(函数) 通过静态链求出数据区的基地址PL/0编译程序的总体流程图五、主要成分描述 1、符号表全程量一维数组。

编译原理课程设计 期末实验报告 编译原理中重要的、有机联系的文法、词法、语法,作一个具体的了解和掌握

编译原理课程设计 期末实验报告 编译原理中重要的、有机联系的文法、词法、语法,作一个具体的了解和掌握

编译原理课程设计[课程设计目的]使学生能通过课程设计,对编译原理中重要的、有机联系的文法、词法、语法,作一个具体的了解和掌握。

[课程设计要求]要求对一个简单的数值表达式进行文法、词法、语法分析,并结合实验,写出课程设计报告。

[课程设计时数] 8学时。

[课程设计内容]对一个简单的数值表达式进行文法、词法、语法分析。

该表达式只含双目运算符:+、-、*、/ ,1位的数值和括号。

一:词法部分实验1,词法源程序代码:#include<stdio.h>#include<string.h>#include<iostream.h>char prog[80],token[8];char ch;int syn,p,m=0,n,row,sum=0;char *rwtab[6]={"begin","if","then","while","do","end"};void scaner(){for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' '){ch=prog[p];p++;}if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){m=0;while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){token[m++]=ch;ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){syn=n+1;break;}}else if((ch>='0'&&ch<='9')){{sum=0;while((ch>='0'&&ch<='9')){sum=sum*10+ch-'0';ch=prog[p++];}}p--;syn=11;if(sum>32767)syn=-1;}else switch(ch){case'<':m=0;token[m++]=ch;ch=prog[p++];if(ch=='>'){syn=21;token[m++]=ch;}else if(ch=='='){syn=22;token[m++]=ch;}else{syn=23;p--;}break;case'>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else{syn=20;p--;}break;case':':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=18;token[m++]=ch;}else{syn=17;p--;}break;case'*':syn=13;token[0]=ch;break; case'/':syn=14;token[0]=ch;break; case'+':syn=15;token[0]=ch;break; case'-':syn=16;token[0]=ch;break; case'=':syn=25;token[0]=ch;break; case';':syn=26;token[0]=ch;break; case'(':syn=27;token[0]=ch;break; case')':syn=28;token[0]=ch;break; case'#':syn=0;token[0]=ch;break; case'\n':syn=-2;break;default: syn=-1;break;}}void main(){p=0;row=1;cout<<"Please input string:"<<endl;do{cin.get(ch);prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11: cout<<"("<<syn<<","<<sum<<")"<<endl; break;case -1: cout<<"Error in row "<<row<<"!"<<endl; break;case -2: row=row++;break;default: cout<<"("<<syn<<","<<token<<")"<<endl;break;}}while (syn!=0);}2,词法实验结果验证:(1)给定源程序begin x:=10; if x>2 then x:=3*x+1/2; end#输出结果如下2,源程序(包括上式未有的while/,do以及判断错误语句),结果图如上:beginx<=$;whilea<2dob<>10-x;end#。

广工编译原理实验报告

广工编译原理实验报告

<<编译原理>>课内实验报告项目名称 PL/0编译器学院____ 计算机学院_______专业_ _年级班别________学号 _学生姓名_______ ___辅导教师_______成绩_______ _______目录一、课内实验的内容------------------------------------------4二、实验修改部分--------------------------------------------4三、概述-------------------------------------------------11四、结构设计说明-------------------------------------------11五、各功能模块描述-----------------------------------------14六、主要成份描述------------------------------------------14七、测试用例----------------------------------------------16八、开发过程和完成情况--------------------------------------21一、课内实验的内容对PL/0作以下修改扩充:(1)增加单词:保留字 ELSE,FOR, STEP,RETURN运算符 +=,-=,++,--,&,|,~(2)修改单词:不等号# 改为 <>(3)增加条件语句的ELSE子句二、实验修改部分:1、增加四个保留字和七个运算符,共十一个单词。

修改部分:#define symnum 43 //保留字从32增加到43个2、增加五个保留字:ELSE,FOR,STEP,RETURN○1头文件pl0.henum symbol { 新增加单词: elsesym, forsym, stepsym,returnsym, pluseq/* += */,plusone/* ++ */,plus/* + */,minuseq/* -= */,minusone/* -- */,minus/* - */,and,or,not}○2头文件pl0.h#define norw 24 //关键字从13增加到24个○3PL0.cppinit();新增加:(增加后数组的内容要再次根据字母顺序重新排列)strcpy(&(word[0][0]),"begin");strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"else"); /*增加单词:保留字else*/strcpy(&(word[5][0]),"end");strcpy(&(word[6][0]),"for"); /*增加单词:保留字 for*/strcpy(&(word[7][0]),"if");strcpy(&(word[8][0]),"odd");strcpy(&(word[9][0]),"procedure");strcpy(&(word[10][0]),"read");strcpy(&(word[11][0]),"return");/*增加单词:保留字 return*/strcpy(&(word[12][0]),"step"); /*增加单词:保留字step*/strcpy(&(word[13][0]),"then");strcpy(&(word[14][0]),"while");strcpy(&(word[15][0]),"write");wsym[0]=beginsym;wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=elsesym; /*else*/wsym[5]=endsym;wsym[6]=forsym; /*for*/wsym[7]=ifsym;wsym[8]=oddsym;wsym[9]=procsym;wsym[10]=readsym;wsym[11]=returnsym; /*return*/wsym[12]=stepsym; /*step*/wsym[13]=thensym;wsym[14]=whilesym;wsym[15]=writesym;3、增加四个运算符:+=,-=,++,-- ,∧,∨,┓PL0.cppgetsym();增加对+,-,++,--,+=,-=的识别;Statement();增加对+,-,++,--,-=的语句的处理;○1Init()中改动:ssym[‘&’]=and;ssym[‘|’]=or;ssym[‘~’]=not;facbegsys[plusone]=true; // 添加前自加运算facbegsys[minusone]=true;// 添加前自减运算○2Getsym()增加的内容:int getsym() {int i,j,k;while( ch==' '||ch==10||ch==9){getchdo;}if(ch>='a'&&ch<='z'){k=0;do{if(k<al){a[k]=ch;k++;}getchdo;}while(ch>='a'&&ch<='z'||ch >='0'&&ch<='9');a[k]=0;strcpy(id,a);i=0;j=norw-1;do{k=(i+j)/2;if(strcmp(id,word[k])<=0){j=k-1;}if(strcmp(id,word[k])>=0){i=k+1;}}while(i<=j);if(i-1>j){sym=wsym[k];}else{sym=ident;}}else{if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';k++;getchdo;}while(ch>='0'&&ch<='9'); /*获取数字的值*/k--;if(k>nmax){error(30);}}else{if(ch==':')/*检测赋值符号*/{getchdo;if(ch=='='){sym=becomes;getchdo;}else{sym=nul; /*不能识别的符号*/}}else{if(ch=='<')/*检测小于或小于等于符号*/{getchdo;if(ch=='='){sym=leq;getchdo;}else{sym=lss;}}else if(ch=='>') /*检测大于或大于等于符号*/{getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}/*这里之间为添加的内容*/else if(ch=='+'){ /*检测+,+=,++符号*/getchdo;if(ch=='='){sym=pluseq;getchdo;}elseif(ch=='+'){sym=plusone;getchdo;}else{sym=plus;}}elseif(ch=='-'){/*检测-,-=,--符号*/getchdo;if(ch=='='){sym=minuseq;getchdo;}elseif(ch=='-'){sym=minusone;getchdo;}else{sym=minus;}}/*这里之间为添加的内容*/else{sym=ssym[ch];/* 当符号不满足上述条件时,全部按照单字符号处理*///getchdo;//richardif(sym!=period){getchdo;}//end richard}}}}return 0; }○3Statement()增加的内容:(将本来“if(sym==becomes)……”部分的内容修改为处理++,+=,--,-=),并在Statement()中定义变量int sym2;if(sym==becomes||sym==pluseq||sy m==minuseq||sym==plusone||sym==minusone){sym2=sym;getsymdo;gendo(lod,lev-table[i].level,tab le[i].adr);}else{error(13);}if(sym2==plusone||sym2==minusone )/* 准备按照a++、a--语句处理,与read类似*/{if(i!=0){if(sym2==plusone){gendo(lit,0,1);gendo(opr,0,2);gendo(sto,lev-table[i].level,table[ i].adr);}if(sym2==minusone){gendo(lit,0,1);gendo(opr,0,3);gendo(sto,lev-table[i].level,table[ i].adr);}}}else{memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){if(sym2==becomes)gendo(sto,lev-table[i].level,tab le[i].adr);if(sym2==pluseq){gendo(opr,0,2);gendo(sto,lev-table[i].level,tab le[i].adr);}if(sym2==minuseq){gendo(opr,0,3);gendo(sto,lev-table[i].level,tab le[i].adr);}}}//else}}}4、修改单词:不等号# 改为 <>●PL0.cppinit();移除: ssym['#']=neq;○1在getsym()里增加对<>的识别(在<或<=基础上修改)。

《编译原理》设计方案报告

《编译原理》设计方案报告

《编译原理》课程设计报告设计题目:pl0编译器设计一、PL0程序的文法及,指令及属性翻译简化c语言文法定义(LL(1)文法)C程序::=void main(){函数体}函数体::=变量定义部分语句列变量定义部分::=变量定义变量定义部分| ɛ变量定义::=int 变量表变量表::=标识符|标识符,变量表语句列::=语句语句列| ɛ语句::=条件语句| 循环语句| 读语句| 写语句| 复合语句| 表达式语句| 空语句条件语句::=if(表达式)语句循环语句::=while(表达式)语句读语句::=read(变量表);写语句::=write(表达式表);复合语句::={语句列};表达式语句::=表达式;空语句::=;表达式定义(算符优先文法)表达式::=变量=表达式| 变量+=表达式| 变量-=表达式| 变量*=表达式| 变量/=表达式| 变量%=表达式| 表达式1表达式1::=表达式1 || 表达式2 | 表达式2表达式2::=表达式2&&表达式3 | 表达式3表达式3::=表达式3==表达式4 | 表达式3!=表达式4 | 表达式3>=表达式4 | 表达式3>表达式4 | 表达式3<=表达式4 | 表达式3<表达式4 | 表达式4表达式4::=表达式4+表达式5 | 表达式4-表达式5 | 表达式5表达式5::=表达式5*表达式6 | 表达式5/表达式6 |表达式5/表达式6 |表达式6表达式6::=!表达式7表达式7::=(表达式) | 变量| 常量PL0文法定义《程序》::=《分程序》.《分程序》::=《常量定义》;《常后分程序》|《常后分程序》《常后分程序》::=《变量定义》;《变后分程序》|《变后分程序》《变后分程序》::=《过程定义》;《变后分程序》|《语句》《常量定义》::=const 《常量定义表》《常量定义表》::=id = number | id = number,《常量定义表》《变量定义》::= var 《变量表》《变量表》::=id | id,《变量表》《过程定义》::=procedure id ;《分程序》《语句》::=《赋值语句》|《条件语句》|《循环语句》|《读语句》|《写语名》|《复合语句》| 《过程调用语句》|ε《赋值语句》::=id := 《表达式》《读语句》::=read(《变量表》)《写语句》::=write(《表达式表》)《表达式表》::=《表达式》| 《表达式》,《表达式表》《条件语句》::=if 《条件表达式》then 《语句》《循环语句》::=while 《条件表达式》do 《语句》《复合语句》::=begin 《语句列》end《过程调用语句》::=call id《参量表》::=《有参表》|ε《有参表》::=《表达式》,《有参表》|《表达式》《表达式》::=+《表达式1》|-《表达式1》|《表达式1》《表达式1》::=《表达式1》+《表达式2》|《表达式1》-《表达式2》|《表达式2》《表达式2》::=《表达式2》*《表达式3》|《表达式2》/《表达式3》| 《表达式2》mod 《表达式3》|《表达式3》《表达式3》::=id | number | (《表达式》)《条件表达式》::=《条件表达式》or 《条件表达式1》|《条件表达式1》《条件表达式1》::=《条件表达式1》and 《条件表达式2》| 《条件表达式2》《条件表达式2》::=not 《条件表达式3》|《条件表达式3》《条件表达式3》::=(《条件表达式》)|《关系表达式》《关系表达式》::=《表达式》>《表达式》《关系表达式》::=《表达式》>=《表达式》《关系表达式》::=《表达式》<《表达式》《关系表达式》::=《表达式》<=《表达式》《关系表达式》::=《表达式》=《表达式》《关系表达式》::=《表达式》#《表达式》PL0栈式机指令指令格式:指令码(f) 所在层数差(l),操作数(a)PL0栈式机指令:LIT:将常数a取到栈顶LOD:将位于(当前层-l)层处的变量a取到栈顶STO:将栈顶处值存储到指定位置,l,a同上CALL 调用当前-l层处的过程aINT:为调用过程在栈中开辟数据区,a为单元个数JMP:无条件转移指令,a目标地址JPC:条件转移指令,栈顶值的布尔值为非真时转移到a处,否则执行下面语句OPR:关系运算或算术运算PL0属性翻译MCONST(const:常量定义开始), V AR(var:变量定义开始), PROCEDURE(procedure:过程定义开始),CALL(call:过程调用语句),BEGIN(begon:复合语句开始),END(end:复合语句结束),IF(if:条件语句开始),THEN(then:条件结束),WHILE(while:循环语句开始), DO(do:循环条件结束), READ(read:读语句),WRITE(write:输出语句), ODD(odd:判奇运算),//分隔符、运算符号DOT(点:.),COMMA(逗号:,), SEMICOLON(分号:;), LPAREN(左括号:(), RPAREN(右括号:)), ASSIGNOP(赋值::=), PLUSOP(加法运算符号:+), MINUSOP(减法运算符:-), MULTOP(乘法运算符:*), DIVOP(除法运算符:/),GT(大于:>),GE(大于等于:>=),LT(小于:<),LE(小于等于:<=),EQ(等于:=),NE(不等:#),ENDF(输入结束符),//分析过程中需要的非终结符号SERVERKEY(保留字), FACTOR(因子),ROP(关系运算), CONSTANT(常量部份定义), V ARIABLE(变量部份定义), IDENT(自定义标识符), NUMBER(常数)二、符号表的结构,组织,填写及查找1、符号表结构const char *pName; //符号名称int kind; //符号类别,由上面单词分类确定int val; //符号表中的位置值int level; //符号的层数int parent; //符号的作用域int size; //过程长度char strBuff[MAXLENSTR]; //符号堆2、符号表的组织符号表的组织方式有:线性表、散列表、树结构等,其必须维持源程序中的作用域信息。

广工编译原理课程设计

广工编译原理课程设计

广工编译原理课程设计一、课程目标知识目标:1. 理解编译原理的基本概念,掌握编译器各阶段的工作原理及相互关系。

2. 学会使用一种编程语言(如C语言)进行词法分析、语法分析、语义分析及中间代码生成。

3. 掌握基本的代码优化和目标代码生成方法。

技能目标:1. 能够运用所学编译原理知识,独立完成一个简单的程序设计语言的编译器设计。

2. 培养学生运用形式语言和自动机理论解决实际问题的能力。

3. 提高学生的编程实践能力,培养良好的编程习惯。

情感态度价值观目标:1. 培养学生对编译原理课程的兴趣,激发学习热情,形成积极的学习态度。

2. 培养学生的团队协作意识,学会与他人共同分析问题、解决问题。

3. 增强学生的创新意识,鼓励尝试不同的编译技术,培养勇于探索的精神。

课程性质:本课程为计算机科学与技术专业核心课程,旨在教授编译原理的基本知识,提高学生的编程实践能力。

学生特点:学生已具备一定的编程基础,具有较强的逻辑思维能力和抽象思维能力。

教学要求:结合课程性质和学生特点,注重理论与实践相结合,强调动手实践,培养学生解决实际问题的能力。

通过课程目标的具体分解,使学生在掌握编译原理知识的同时,提高编程技能和团队协作能力。

二、教学内容1. 编译原理概述:介绍编译器的定义、编译过程、编译器的结构及其各阶段的作用。

教材章节:第1章 编译原理概述2. 词法分析:讲解词法分析的基本概念、词法分析器的功能、词法规则及其实现方法。

教材章节:第2章 词法分析3. 语法分析:介绍语法分析的基本概念、自上而下和自下而上的语法分析方法、语法分析器的实现技术。

教材章节:第3章 语法分析4. 语义分析:讲解语义分析的作用、类型检查、语义分析器的实现方法。

教材章节:第4章 语义分析5. 中间代码生成:介绍中间代码的定义、中间代码的表示形式、中间代码生成的方法。

教材章节:第5章 中间代码生成6. 代码优化:讲解代码优化的目的、基本优化方法、目标代码生成。

编译原理课程设计报告

编译原理课程设计报告

实验1:用Lex设计词法分析器1实验目的:学会用lex设计一个词法分析器。

实验内容:使用lex为下述文法语言写一个词法分析器。

实验要求:输入为用该语言所写的源程序文件;输出为记号序列,每个记号显示为二元组(记号名,记号属性值)的形式。

输出可以在屏幕上,也可以输出到文件中。

不要求建立符号表。

在cygwin下用flex和gcc工具将实验调试通过,并能通过例子parser0中testcases 目录下的测试例的测试。

实验参考:和。

语言文法:<程序> PROGRAM <标识符> ; <分程序><分程序> <变量说明> BEGIN <语句表> END.<变量说明> VAR <变量说明表>;<变量说明表><变量表>: <类型> | <变量表>: <类型>; <变量说明表><类型> INTEGER | REAL<变量表> <变量> | <变量>, <变量表><语句表> <语句> | <语句>; <语句表><语句> <赋值语句> | <条件语句> | <WHILE语句> | <复合语句><赋值语句><变量> := <算术表达式><条件语句> IF <关系表达式> THEN <语句> ELSE <语句><WHILE语句> WHILE <关系表达式> DO <语句><复合语句> BEGIN <语句表> END<算术表达式> <项> | <算术表达式> + <项> | <算术表达式> - <项><项> <因式> | <项> * <因式> | <项> / <因式><因式> <变量> | <常数> | (<算术表达式>)<关系表达式> <算术表达式> <关系符> <算术表达式><变量> <标识符><标识符> <标识符><字母> | <标识符><数字> | <字母><常数> <整数> | <浮点数><整数> <数字> | <数字> <整数><浮点数> .<整数> | <整数>.<整数><关系符> < | <= | = | > | >=| <><字母> A | B | …| X | Y | Z | a | b | …| x | y | z<数字>0|1|2|…|9程序代码:%{#include <>#define LT 1#define LE 2#define GT 3#define GE 4#define EQ 5#define NE 6#define PROGRAM 7#define END 13#define VAR 9#define IF 10#define THEN 11#define ELSE 12#define WHILE 18#define DO 19#define ID 20#define NUMBER 21#define RELOP 22#define NEWLINE 23#define ERRORCHAR 24%}delim [ \t \n]ws {delim}+letter [A-Za-z]digit [0-9]id _|{letter}({letter}|{digit})*number {digit}+(\.{digit}+)?(E[+-]?{digit}+)?int1 {digit}|{digit}{int1}*/%s COMMENT%%<INITIAL>"/*" {BEGIN COMMENT;ECHO;} <COMMENT>"*/" {BEGIN INITIAL;ECHO;} <COMMENT>.|\n {ECHO;}/* ECHO是一个宏,相当于 fprintf(yyout, "%s", yytext)*/ <INITIAL>{ws} {;}<INITIAL>while {return (WHILE);}<INITIAL>do {return (DO);}<INITIAL>PROGRAM {return (PROGRAM);}<INITIAL>end {return (END);}<INITIAL>VAR {return (VAR);}<INITIAL>if {return (IF);}<INITIAL>then {return (THEN);}<INITIAL>else {return (ELSE);}<INITIAL>{id} {return (ID);}<INITIAL>{number} {return (NUMBER);}<INITIAL>"<" {return (RELOP);}<INITIAL>"<=" {return (RELOP);}<INITIAL>"=" {return (RELOP);}<INITIAL>"<>" {return (RELOP);}<INITIAL>">" {return (RELOP);}<INITIAL>">=" {return (RELOP);}<INITIAL>"+" {return (RELOP);}<INITIAL>"-" {return (RELOP);}<INITIAL>"*" {return (RELOP);}<INITIAL>"/" {return (RELOP);}<INITIAL>":=" {return (RELOP);}<INITIAL>";" {return (RELOP);}<INITIAL>"." {return (RELOP);}<INITIAL>"," {return (RELOP);}<INITIAL>. {return ERRORCHAR;}%%int yywrap (){return 1;}void writeout(int c){switch(c){case ERRORCHAR: fprintf(yyout, "(ERRORCHAR, \"%s\") ", yytext);break;case RELOP: fprintf(yyout, "(RELOP, \"%s\") ", yytext);break;case WHILE: fprintf(yyout, "(WHILE, \"%s\") ", yytext);break;case DO: fprintf(yyout, "(DO, \"%s\") ", yytext);break;case NUMBER: fprintf(yyout, "(NUM, \"%s\") ", yytext);break;case ID: fprintf(yyout, "(ID, \"%s\") ", yytext);break;case NEWLINE: fprintf(yyout, "\n");break;case PROGRAM: fprintf(yyout, "(PROGRAM, \"%s\") ", yytext);break;case END: fprintf(yyout, "(END, \"%s\") ", yytext);break;case VAR: fprintf(yyout, "(VAR, \"%s\") ", yytext);break;case IF: fprintf(yyout, "(IF, \"%s\") ", yytext);break;case THEN: fprintf(yyout, "(THEN, \"%s\") ", yytext);break;case ELSE: fprintf(yyout, "(ELSE, \"%s\") ", yytext);break;default:break;}return;}int main (int argc, char ** argv){int c,j=0;if (argc>=2){if ((yyin = fopen(argv[1], "r")) == NULL){printf("Can't open file %s\n", argv[1]);return 1;}if (argc>=3){yyout=fopen(argv[2], "w");}}while (c = yylex()){writeout(c);j++;if (j%5 == 0) writeout(NEWLINE);}if(argc>=2){fclose(yyin);if (argc>=3) fclose(yyout);}return 0;}测试文件为:PROGRAM test;VAR i, j, k: INTEGER;f0: REAL;BEGINi := 1;j := 1;k := 0;f0 := ;WHILE k<=100 DOBEGINIF j <20 THENBEGINj := i;k := k+1;f0 := f0*ENDELSEBEGINj := k;k := k-2;f0 := f0/.2ENDENDEND.运行结果:实验2:用Lex设计词法分析器2实验目的:学会用lex设计一个词法分析器,并考虑其与后续语法分析器的链接问题。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

课程设计课程名称___编译原理__________题目名称___PL/0编译器的扩充__学生学院___计算机学院_________专业班级_计算机科学与技术13(9)学号学生姓名指导教师___林志毅________________2016年1月2日一、已完成的内容:(1)扩充赋值运算:*=和/=(2)扩充语句(Pascal的FOR语句)FOR<变量>:=<表达式>STEP<表达式>UNTIL<表达式>Do<语句> (3)增加类型:①字符类型;②实数类型。

VARIABLE*/GetSym();if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){TABLE[i].;}GetSym();}elseError(13);EXPRESSION(FSYS,LEV,TX);if(RELOP==TIMESBECOMES){GEN(OPR,0,4);}elseif(RELOP==SLASHBECOMES){GEN(OPR,0,5);}elseif(RELOP==PLUSBECOMES){GEN(OPR,0,2);}elseif(RELOP==MINUSBECOMES){GEN(OPR,0,3);}GEN(STO,LEV-TABLE[i].,TABLE[i].;}(1)运行测试(测试的PL0源码扩充单词的测试并贴运行结果截图)PL0源码:PROGRAMEX01;VARA,B,C,D;BEGINA:=16;A/=2;(2)WRITE(A);运行结果:(3)出现的问题及解决开始时在实现/=和*=操作时,*=的实现很顺利,而/=却一直没有得到理想的结果,通过与同学的讨论得知代码中除号指令的解析中,其实为除余操作,于是将%改为/,但是结果还是错误,经过调试发现是两个相除的数在栈中的位置相反了,正确的状态应该是除数位于次栈顶,而被除数位于栈顶。

解决:在调用EXPRESSION函数解析/=右边表达式前,先将其左边变量的值放入栈中。

1.扩充语句(Pascal的FOR语句)FOR<变量>:=<表达式>STEP<表达式>UNTIL<表达式>Do<语句>(1)语法图(2)修改GetSym()方法(写出修改的代码)此处无修改,FOR、STEP、UNTIL及DO等关键字已放置关键字数组中,通过该数组便可识别。

(3)修改STATEMENT()方法(写出修改的代码)caseFORSYM:GetSym();(4)STATEMENT(SymSetUnion(SymSetNew(STEPSYM),FSYS),LEV,TX);=CX;=CX;运行结果:(5)出现的问题及解决实现FOR循环的前提是理解表达式处理函数及语句处理函数,关键是处理好跳转关系,例如第一次进入FOR循环时,生成FOR后面的表达式后应该有一个直接跳转跳过STEP语句进入UNTIL的条件判断;而调用CONDITION处理UNTIL后的条件语句后,便有一个条件跳转跳到STEP后的表达式代码位置。

由于有了之前IF...ELSE...的参考及大致理解相关函数,因此实现时没出现太大问题。

2.增加类型:①字符类型;②实数类型。

(1)在GetSym中增加字符型及实数型数据的识别elseif(CH=='\''){GetCh();NUM=CH;GetCh();if(CH=='\''){SYM=CHARACTER;GetCh();}elseError(8);}elseif(CH>='0'&&CH<='9'){/*NUMBER*/K=0;NUM=0;SYM=NUMBER;do{NUM=10*NUM+(CH-'0');K++;GetCh();}while(CH>='0'&&CH<='9');if(CH=='.'){IND==CHARTYPE||TABLE[i].KIND==VARIABLE||TABLE[i].KIND==F LOATTYPE){/*ASSIGNMENTTONON-VARIABLE*/if(SYM==BECOMES||SYM==TIMESBECOMES||SYM==SLASHBECOMES ||SYM==PLUSBECOMES||SYM==MINUSBECOMES){RELOP=SYM;if(SYM!=BECOMES){TABLE[i].;}GetSym();}elseError(13);EXPRESSION(FSYS,LEV,TX);if(RELOP==TIMESBECOMES){GEN(OPR,0,4);}elseif(RELOP==SLASHBECOMES){GEN(OPR,0,5);}elseif(RELOP==PLUSBECOMES){GEN(OPR,0,2);}elseif(RELOP==MINUSBECOMES){GEN(OPR,0,3);}GEN(STO,LEV-TABLE[i].,TABLE[i].;}else{Error(12);i=0;}break;caseWRITESYM: IND){caseCHARTYPE:GEN(OPR,0,17);break;caseFLOATTYPE:GEN(OPR,0,18);break;default:{GEN(OPR,0,14);}}}while(SYM==COMMA);if(SYM!=RPAREN)Error(SBNUM);elseGetSym();}GEN(OPR,0,15);break;/*WRITESYM*/(2)修改FACTOR中的方法(包含字符的识别处理)while(SymIn(SYM,FACBEGSYS)){if(SYM==IDENT){i=POSITION(ID,TX);if(i==0)Error(11);elseswitch(TABLE[i].KIND){caseCONSTANT:GEN(LIT,0,TABLE[i].VAL);break;caseVARIABLE:GEN(LOD,LEV-TABLE[i].,TABLE[i].;break;casePROCEDUR:Error(21);break;caseFLOATTYPE:GEN(LOD,LEV-TABLE[i].,TABLE[i].;break;caseCHARTYPE:GEN(LOD,LEV-TABLE[i].,TABLE[i].;break;}GetSym();}elseif(SYM==NUMBER){if(NUM>AMAX){Error(31);NUM=0;}GEN(LIT,0,NUM);GetSym();LEV;TABLE[TX].=DX;DX++;break;caseFLOATTYPE:TABLE[TX].=LEV;TABLE[TX].=DX;DX++;break;(3)在Interpret指令OPR中增加字符输出和实数输出case17:Form1->printcs(S[T]);fprintf(FOUT,"%c\n",S[T]);(4)T--;运行结果:(5)出现的问题及解决字符型的实现主要问题是在赋值、字符表达式的处理及输出三个方面。

赋值刚开始没有思路,之后借鉴VAR型的赋值,才清楚需要使用到栈这个媒介进入赋值:先把字符值放入栈中,在将栈顶值传给字符型变量。

而字符表达式的处理在Factor里进行识别处理。

关于输出则需要在WRITESYM的识别处理中进行类型判断采取不同输出方式,并需新建一条指令专门用于字符输出实数型的实现主要问题为:1、数据获取:小数点后的值的获取需要用到循环帮助实现;2、变量更改:在没有引入实数型前,用来模拟栈的数组类型为int型,而引入后,则需要将其更改为实数型,在程序中与栈值有关的那些变量类型也同样改为实数型。

(1)增加注释;多行注释由/*和*/包含,单行注释为运行结果(2)出现问题及解决刚开始就认为注释功能的实现比较容易,但是在实现过程还是出现不少问题。

我的思路是在getSym方法中使用循环滤去注释的内容,过程不断调用getCh读取下一个字符。

在循环处理注释结束后需要调用自身GetSym,因为上次调用的GetSym方法都用于处理注释了。

然而/**/这种情况却一直有报19号错误,经过查找发现该情况的循环执行完后,当前CH为符号’/’,而不是’/’后的字符,因此需要在调用GetSym前先调用getCh以便获取下一个新字符用于GetSym中的switch判断。

//不存在此情况,其循环结束CH为注释结束的下一字符。

二、心得经过了一周多的奋战,此次课程设计的实现过程让我收获颇多,同时也让我意识到自己在编码过程中的不足。

在没做课程设计之前,我对代码编译的实现过程和对PL0代码的体系结构都很陌生,而当一步一步从实现/=等、for循环、注释及增加类型等功能后,我对代码编译过程有了一个整体而深入的认识。

在实现的过程中,虽然出现很多问题,但是通过自己的思考和请教同学都能得到解决。

在实现的过程中,我发现自己在考虑功能的实现方面不够全面仔细,例如字符型的增加,我只考虑到了字母这一种字符型,而没有考虑其他符号也为字符型,因此先前字符的识别我是通过判别当前SYM是否为ident型且其字符串长度是否为1这两个条件进行识别出来的。

当完成过后才发现该方法存在缺陷,才在GetSym里面另起分支进行识别处理。

这也提醒我以后考虑问题应当尽量周全。

源码下载地址:。

相关文档
最新文档