PL0编译器功能扩充

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

1NingxiaNormalUniversityPL0编译器题目Pl0编译器功能扩充姓名学号院(系)数学与计算机科学学院专业班级计算机技术与科学2班时间2014-1-512目录一、实验目的----------------------------3二、实验内容----------------------------3三、实验框图----------------------------4四、过程分析----------------------------61、词法过程分析-----------------------62、语法过程分析-----------------------63、整体过程分析-----------------------74、扩充过程分析-----------------------9五、测试结果---------------------------11六、问题及感受---------------------------1223一、实验目的本次实验设计主要是在分析理解PL/0编译程序的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充,使其增加并且实现了更多的功能。二、实验内容PL/0语言是Pascal语言的一个子集,这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。词法分析和代码生成作为独立的子程序供语法分析程序调用。语法分析的同时,提供了出错报告和出错恢复的功能。在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。扩充PL0语言是在PL0语言的基础上增加对整型一维数组的支持、扩充IF-THEN-ELSE条件语句、增加REPEAT语句。如下所示:(1)整型一维数组,数组的定义格式为:VAR数组标识名(下界:上界)其中上界和下界可以是整数或者常量标识名访问数组元素的时候,数组下标是整型的表达式,包括整数、常量或者变量和它们的组合(2)扩充条件语句,格式为:条件语句::=IF条件THEN语句[ELSE语句](3)增加REPEAT语句,格式为:重复语句::=REPEAT语句UNTIL条件(4)注释单行注释以{开始,以}结束,注释内容不包括{和}34三、实验框图1、基本工作流程图2、语法分析图语法分析词法分析语义分析代码生成代码执行源程序执行结果符号表管理错误诊断处理程序程序体语句条件表达式项因子453、if-then-else语句的流程图进入if语句条件判断YN执行then后语句执行else后语句退出该语句4、增加++a,--a功能开始程序读入a值a=a+1或a=a-1a原值参与运算退出该语句56四、过程分析1、词法分析:词法分析子程序名为GETSYM,功能是从源程序中读出一个单词符号,把它的信息放入全局变量SYM、ID和NUM中,字符变量放入CH中,语法分析器需要单词时,直接从这三个变量中获得。Getch过程通过反复调用Getch子过程从源程序过获取字符,并把它们拼成单词。GETCH过程中使用了行缓冲区技术以提高程序运行效率。词法分析器的分析过程:调用GETSYM时,它通过GETCH过程从源程序中获得一个字符。如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把SYM变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把SYM置为IDENT,把这个单词存入ID变量。查保留字表时使用了二分法查找以提高效率。如果Getch获得的字符是数字,则继续用Getch获取数字,并把它们拼成一个整数或实数,然后把SYM置为INTEGER或REAL,并把拼成的数值放入NUM变量。如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把SYM则成相应的类型。如果遇到不合法的字符,把SYM置成NUL。2、语法分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。语法分析主要由分程序分析过程、参数变量分析过程、参数变量处理过程、数组处理过程、常量定义分析过程、变量定义分析过程、语句分析过程、表达式处理过程、项处理过程、因子处理过程和条件处理过程构成。这些过程在结构上构成一个嵌套的层次结构。除此之外,还有出错报告过程、代码生成过程、测试单词合法性及出错恢复过程、登录名字表过程、查询名字表函数以及列出类PCODE代码过程作过语法分析的辅助过程。673、整体分析:语法分析开始后,首先调用分程序处理过程处理分程序。过程入口参数置为:0层、符号表位置0、出错恢复单词集合为句号、声明符或语句开始符。进入Block过程后,首先把局部数据段分配指针设为3,准备分配3个单元供运行期存放静态链SL、动态链DL和返回地址RA。然后用Tx0记录下当前符号表位置并产生一条Jmp指令,准备跳转到主程序的开始位置,由于当前还没有知到主程序究竟在何处开始,所以Jmp的目标暂时填为0,稍后再改。同时在符号表的当前位置记录下这个Jmp指令在代码段中的位置。在判断了嵌套层数没有超过规定的层数后,开始分析源程序。首先判断是否遇到了常量声明,如果遇到则开始常量定义,把常量存入符号表。接下去用同样的方法分析变量声明,变量定义过程中会用Dx变量记录下局部数据段分配的空间个数。然后如果遇到Procedure保留字则进行过程声明和定义,声明的方法是把过程的名字和所在的层次记入符号表,过程定义的方法就是通过递归调用Block过程,因为每个过程都是一个分程序。由于这是分程序中的分程序,因此调用Block时需把当前的层次号Lev加一传递给Block过程。分程序声明部分完成后,即将进入语句的处理,这时的代码分配指针CX的值正好指向语句的开始位置,这个位置正是前面的Jmp指令需要跳转到的位置。于是通过前面记录下来的地址值,把这个Jmp指令的跳转位置改成当前cx的位置。并在符号表中记录下当前的代码段分配地址和局部数据段要分配的大小(DX的值)。生成一条INT指令,分配DX个空间,作为这个分程序段的第一条指令。下面就调用语句处理过程Statement分析语句。分析完成后,生成操作数为0的OPR指令,用于从分程序返回。常量定义过程:通过循环,反复获得标识符和对应的值,存入符号表。符号表中记录下标识符的名字和它对应的值。变量定义过程:与常量定义类似,通过循环,反复获得标识符,存入符号表。符号表中记录下标识符的名字、它所在的层及它在所在层中的偏移地址。78参变量定义过程:类似变量定义,将参变量,存入符号表中。参变量处理过程:如果函数用参变量,依照形参的类型、个数,由实参进行赋值。数组处理过程:计算数组括号内的偏移值,存入栈顶用于后面生成的STOARR和LODARR指令调用实际的数组中元素的地址。语句处理过程:语句处理过程是一个嵌套子程序,通过调用表达式处理、项处理、因子处理等过程及递归调用自己来实现对语句的分析。语句处理过程可以识别的语句包括赋值语句、read语句、write语句、++语句、--语句、+=语句、-=语句、if-else-then语句、while语句、For语句、repeat语句。当遇到begin/end语句时,就递归调用自己来分析。分析的同时生成相应的类PCODE指令。赋值语句的处理:首先获取赋值号左边的标识符,从符号表中找到它的信息,并确认这个标识符确为变量名。然后通过调用表达式处理过程算得赋值号右部的表达式的值并生成相应的指令保证这个值放在运行期的数据栈顶。最后通过前面查到的左部变量的位置信息,生成相应的STO指令,把栈顶值存入指定的变量的空间,实现了赋值操作。返回函数值也是用赋值语句进行返回值的储存。对函数与过程调用的处理:首先判断读入的标识符属性为FUNCTION或PROCEDURE,从符号表中找到此标识符,获得其所在层次和偏移地址。然后生成相应的cal指令。至于调用子过程所需的保护现场等工作是由类PCODE解释程序在解释执行cal指令时自动完成的。如果此标识符不在第0层而且是该层函数的函数名则作为返回值返回。read语句的处理:在read语句合理前提下,由变量的类型生成相应的指令:89对于整型,第一条是16号操作的opr指令,实现从标准输入设备上读一个整数值,放在数据栈顶。如果读入是实数就报错,第二条是sto指令,把栈顶的值存入read语句括号中的变量所在的单元。对于实型,第一条是15号操作的opr指令,实现从标准输入设备上读一个实数值,放在数据栈顶。第二条是sto指令,把栈顶的值存入read语句括号中的变量所在的单元。对于字符型,第一条是20号操作的opr指令,实现从标准输入设备上读一个字符值,第二条是sto指令,把栈顶的值存入read语句括号中的变量所在的单元。write语句的处理:与read语句相似。在语法正确的前提下,生成指令:通过循环调用表达式处理过程分析write语句括号中的每一个表达式,生成相应指令保证把表达式的值算出并放到数据栈顶并生成指令,输出表达式的值,如果是数字类型则生成14号操作的opr指令,如果是字符类型则生成19号操作的opr指令。4、扩充分析:增加错误分析功能在编译程序的过程中,往往我们的程序中存在着一些错误。而在编译主体的时候我们已经列出了出错编号,为了清晰的了解出错原因,因此在初始化过程后增加了出错处理,打印出错位置和错误编码。voiderror(intn){charspace[81];memset(space,32,81);space[cc-1]=0;//出错时当前符号已经读完,所以cc-1printf(****%s!%d\n,space,n);switch(n){………………………………}err++;}910增加if-then-else当编译程序编译到条件语句时,并不直到条件为假时的转移地址,必须等到条件为真的语句编译完后才知道转移地址。还有当条件为真时语句执行完毕后,必须跳出if语句,否则就会接着执行else后语句。即再then后else前语句的最后加上一条无条件转移指令:jmp0?,此时该地址也未知,因为编译程序还未编译else后语句,等到编译完else后语句时,才知道该地址,所以必须保存该代码的地址,等下次回填。在初始化与头文件中作相应改动初始化:strcpy(&(word[5][0]),else);strcpy(&(word[14][0]),to);wsym[5]=elsesym;/*addelse*/wsym[14]=tosym;头文件:enumsymbol{nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,period,becomes,pluseq,minuseq,plusone,minusone,beginsym,endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,callsym,constsym,varsym,procsym,elsesym,tosym}增加++a与--a、增加a++与a--功能和增加+=与-=功能++a与--a的操作是将a的值自加与自减1,但是参与程序中与a值相关的运算的时候,使用的仍然是未经过自加或自减的a值。a++与a--的操作是将a的值自加与自减1,而后参与程序中与a值相关的运算的时候,使用的是已经过自加或自减的a值。+=与-=首先在词法分析getsym中加入识别+=与-=的功能。同时在头文件中作相应改变头文件。1011五、测试结果1、测试文件:TEST1:varx,y,z;TEST2:varx,y;Beginbeginx:=-3;x:=10;y:

1 / 14
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功