您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 能源与动力工程 > 广东工业大学2015编译原理课程设计
编译原理课程设计报告课程名称____编译原理课程设计_题目名称PL/0编译器的扩充学生学院__计算机学院______专业班级___学号______学生姓名____指导教师______张巍2015年12月27日一.课程设计目的及要求基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:+=,-=,*=和/=(2)扩充语句(Pascal的FOR语句):FOR变量:=表达式STEP表达式UNTIL表达式Do语句选做内容(成绩评定范围扩大到:“优”和“良”)增加注释;注释由/*和*/包含;二.概述1、源语言:PL/0语言,PL/0语言是PASCAL语言的子集,它的编译程序是一个编译解析执行系统,后缀名为.PL0;2、目标语言:生成文件后缀为*.COD的目标代码3、实现平台(平台):BorlandC++Builder64、运行平台:Windowsxp三.结构设计说明各功能模块概述过程或函数名简要功能说明pl0主程序error出错处理,打印出错位置和错误编码getsym词法分析,读取一个单词getch漏掉空格,读取一个字符gen生成目标代码,并送入目标程序区test测试当前单词符号是否合法block分程序分析处理过程enter登录名字表position查找标识符在名字表中的位置constdeclaration常量定义处理vardeclaration变量说明处理listode列出目标代码清单statement语句处理expression表达式处理term项处理factor因子处理condition条件处理interpret对目标代码的解释执行程序base(函数)通过静态链求出数据区的基地址四.主要成分描述(1)符号表为了组成一条指令,编译程序必须知道其操作码及其参数(数或地址)。这些值是由编译程序本身联系到相应标识符上去的。这种联系是在处理常数、变量和过程说明完成的。为此,标识符表应包含每一标识符所联系的属性;如果标识符被说明为常数,其属性值为常数值;如果标识符被说明成变量,其属性就是由层次和修正量(偏移量)组成的地址;如果标识符被说明为过程,其属性就是过程的入口地址及层次。常数的值由程序正文提供,编译的任务就是确定存放该值的地址。我们选择顺序分配变量和代码的方法;每遇到一个变量说明,就将数据单元的下标加一(PL/0机中,每个变量占一个存贮单元)。开始编译一个过程时,要对数据单元的下标dx赋初值,表示新开辟一个数据区。dx的初值为3,因为每个数据区包含三个内部变量RA,DL和SL。(2)运行时的存储组织和管理当源程序经过语法分析,如果未发现错误时,由编译程序调用解释程序,对存放在CODE中的代码CODE[0]开始进行解释执行.当废弃结束后,记录源程序中标识符的TABLE表已没有作用.因此存储区只需以数组CODE存主的只读目标程序和运行机制时的数据区S,S是由解释程序定义的一维整数型数组.解释执行时的数据空间S为栈式计算机的在座空间,遵循后进先出规则,对每个过程(包括主程序)当调用时,才分配数据空间,退出过程进,则所分配原则的数据空间被释放.解释程序还定义了4个寄存器:1、指令寄存器.存放当前正在解释的一条目标指令2、程序地址寄存器.指向下一条要执行的目标程序的地址3、栈顶寄存器.4、基址寄存器.指向每个过程被调用时,在数据区S中给它分配原则的数据段起始地址,也称基地址.为了实现过程被调用时给它分配数据段,过程运行结束后释放数据段以及嵌套过程之间结标志符引用的问题,当过程被调用时,在栈顶分配三个联系单元,这三个联系单元存放的内容分别为:SL静态链,动态链DL,RA返回地址。(3)语法分析方法语法分析的任务是识别由词法分析给出的单词符号序列在结构上是否符合给定的文法规则.PL/0编译程序的语法分析采用了自顶向下的递归子程序法.粗略地说:就是对应每个非终结符语法单元,编一个独立的处理过程(或子程序).语法分析研究从读入第一个单词开始由非终结符’程序即开始符出发,沿语法描述图箭头所指出的方向进行分析.当遇到非终结符时,则调用相应的处理过程,从语法描述图看也就进入了一个语法单元,再沿当前所进入的语法描述图的箭头方向进行分析,当遇到描述图中是终结符时,则判断当前读入的单词是否与图中的终结符相匹配,若匹配,则执行相应的语义程序(就是翻译程序).再读取下一个单词继续分析.遇到分支点时将当前的单词与分支点上的多个终结符逐个相比较,若都不匹配时可能是进入下一非终结符语法单位或是出错.如果一个PL/0语言程序的单词序列在整修语法分析中,都能逐个得到匹配,直到程序结束’.’,这时就说所输入的程序是正确的.对于正确的语法分析做相应的语义翻译,最终得出目标程序.程序分程序.变量说明部分语句VAR标识符;复合语句ABEGIN语句END读语句READ(标识符)APL/0编译程序对语法错误的处理采用两种办法:(1)对于一些易于校正的错误,如丢了逗号、分号等,指出出错的位置,加以校正,继续进行分析。(2)对于难于校正的错误,给出错误的位置与性质,跳过后面一些单词,直到下一个可以进行正常语法分析的语法单位。错误类型如下0过程开始部分说明不正确1常数说明中=写成:=2常数说明中=后应为整数或实数或字符3常数说明中的标识符后应是=4const,var,procedure后应为标识符5漏掉了,或;6过程说明后的符号不正确(应该是语句开始符,或过程定义符)7应是语句开始符8程序体内语句部分的后跟符不正确9程序结尾丢了句号.10语句间漏了;11标识符未说明12赋值语句中,赋值号左部标识符属性应是变量13变量后不能是此符号14call后应为标识符15call后标识符属性应为过程16条件语句中丢了then17丢了end或;18while型循环语句丢了do19语句后的符号不正确20应为关系运算符21表达式内标识符属性不能是过程22表达式中漏掉右括号(23因子后的非法符号24表达式的开始符不能是此符号31数越界(4)中间代码表示PL/0编译程序所产生的目标代码是一个假想栈式计算机的汇编语言,可称为类pcode指令代码,它不依赖任何实际计算机,其指令集极为简单,指令格式如下:fla其中f代表功能码,l表示层次差,也就是引用变量胡哦哦过程的分程序与说明该变量或过程的分程序之间的层次差。A的含义对不同的指令有所区别。对每条指令的解释说明如下。目标指令有8条:①LIT将常数值取到栈顶,a为常数值②LOD将变量值取到栈顶,a为偏移量,l为层差③STO将栈顶内容送入某变量单元中,a为偏移量,l为层差④CAL调用过程,a为过程地址,l为层差⑤INT在运行栈中为被调用的过程开辟a个单元的数据区⑥JMP无条件跳转至a地址⑦JPC条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行⑧OPR的l域为0,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行opr00过程调用结束后,返回调用点并退栈opr01栈顶元素取反opr02次栈顶与栈顶相加,退两个栈元素,结果值进栈opr03次栈顶减去栈顶,退两个栈元素,结果值进栈opr04次栈顶乘以栈顶,退两个栈元素,结果值进栈opr05次栈顶除以栈顶,退两个栈元素,结果值进栈opr06栈顶元素的奇偶判断,结果值在栈顶opr07opr08次栈顶与栈顶是否相等,退两个栈元素,结果值进栈opr09次栈顶与栈顶是否不等,退两个栈元素,结果值进栈opr010次栈顶是否小于栈顶,退两个栈元素,结果值进栈opr011次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈opr012次栈顶是否大于栈顶,退两个栈元素,结果值进栈opr013次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈opr014栈顶值输出至屏幕opr015屏幕输出换行opr016从命令行读入一个输入置于栈顶五.测试用例本次课设的测试用例共分为三个Test1,用于测试扩充赋值运算:+=,-=,*=和/=Test2用于测试扩充语句(Pascal的FOR语句):FOR变量:=表达式STEP表达式UNTIL表达式Do语句Test3用于测试/**/六.开发过程和完成情况1.扩充赋值运算:+=,-=,*=和/=代码修改:elseif(SYM==PLUSEQL)//+=语义分析{GetSym();GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//左值入栈EXPRESSION(FSYS,LEV,TX);//右表达式结果入栈GEN(OPR,0,2);//加法运算GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将结果送回左值}elseif(SYM==MINUSEQL)//-=语义分析{GetSym();GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//左值入栈EXPRESSION(FSYS,LEV,TX);//右表达式结果入栈GEN(OPR,0,3);//乘法运算GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将结果送回左值}elseif(SYM==MULSEQL)//*=语义分析{GetSym();GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//左值入栈EXPRESSION(FSYS,LEV,TX);//右表达式结果入栈GEN(OPR,0,4);//乘法运算GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将结果送回左值}elseif(SYM==DIVSEQL)///=语义分析{GetSym();GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//左值入栈EXPRESSION(FSYS,LEV,TX);//右表达式结果入栈GEN(OPR,0,5);//除法运算,注意原始的是求余运算!!!GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将结果送回左值}语法树:2.扩充语句(Pascal的FOR语句):FOR变量:=表达式STEP表达式UNTIL表达式Do语句代码修改:caseFORSYM:GetSym();if(SYM!=IDENT)//for后面必须跟变量来进行赋值Error(47);elsei=POSITION(ID,TX);//查找标识符在名字表中的位置并赋值给iif(i==0)//对i进行检查是否存在于符号表中Error(11);elseif(TABLE[i].KIND!=VARIABLE)//不是变量类型,错误{/*ASSIGNMENTTONON-VARIABLE*/Error(12);i=0;}GetSym();//读取下一个符号:=if(SYM==BECOMES)//读取到:=GetSym();elseError(13);ident………表达式表达式表达式;+=-=*=/=表达式EXPRESSION(SymSetUnion(SymSetNew(STEPSYM),FSYS),LEV,TX);//设置后跟符为stepif(i!=0)//变量存在GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将栈顶的值传给变量if(SYM==STEPSYM)//读取到stepGetSym();else//没有读到step,出错Error(46);CX1=CX;//记录此处地址GEN(JMP,0,0);//条件跳转,地址未知,后面回填CX3=CX;EXPRESSION(SymSetUnion(SymSetNew(UNTILSYM),FSYS),LEV,TX);//设置后跟符为untilGEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将变量送回栈顶GE
本文标题:广东工业大学2015编译原理课程设计
链接地址:https://www.777doc.com/doc-6435371 .html