您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 能源与动力工程 > 广东工业大学编译原理课设
课程设计课程名称编译原理题目名称对PL/0的修改与扩充学生学院计算机学院专业班级学号学生姓名指导教师2014年1月3日一.课程设计目的在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。达到进一步了解程序编译过程的基本原理和基本实现方法的目的。二.课程设计要求(1)扩充赋值运算:*=和/=(2)扩充语句(Pascal的FOR语句):FOR变量:=表达式STEP表达式UNTIL表达式Do语句三.课程设计环境与工具1.程序运行环境:(1)运行平台:WindowsXP(2)实现工具:BorlandC++Building6.0(3)教学型编译程序:PL/02.源程序: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、符号表全程量一维数组。表项主要有5个:名字(NAME),类型(KIND),值/层次(VAL/LEVEL),过程名的ADR域,过程所需要的空间(SIZE)。对于常量,变量和过程说明这三种情况,都需要把其相关的信息登记入符号表中。这三种情况需要登记到符号表的内容分别如下:(1)常量:记录下该常量的名字(TBLE.NAME),登记该名字属于常量(TABLE.KIND),记录下该常量的值(TABLE.VAL)。(2)变量:记录该变量的名字(TABLE.NAME),记录下该名字为变量的类型(TABLE.KIND),登记下该变量所在的层次(TABLE.LEVEL),登记该变量存储位置(TABLE.ADR)。(3)过程名:记录下该过程名字(TABLE.NAME),记录下该名字属于过程(TABLE.KIND),记录下该过程所在的层次(TABLE,LEVEL),记录下存储位置(TABLE.ADR),过程所需要的数据空间(TABLE.SIZE)。启动置初值调用getsym取单词调用block过程是否为源程序结束符源程序是否有错误调用解释过程interpret解释执行目标执行目标程序结束出错打印错误NNYY2、运行时存储组织和管理解释程序定义了4个寄存器:(1)I指令寄存器。存放当前正在解释的一条目标指令。(2)P程序地址寄存器。指向下一条要执行的目标程序的地址(相当于目标程序CODE数组的下标。(3)T栈顶寄存器。栈顶寄存器T指向当前栈中最新分配的单元。(4)B基址寄存器。指向每个过程被调用时,在数据区S中给该过程分配的数据段起始地址,称基地址。而在存储组织上则采用栈式动态存储分配。主要涉及到三个单元:(5)SL静态链:指向定义该过程的直接外过程(或主程序)运行时最新数据段的基地址。(6)DL动态链:指向调用该过程前正在运行过程的数据段的基地址。(7)RA返回地址:记录调用该过程时目标程序的断点,即当时的程序地址寄存器P的值。3、语法分析方法语法分析会从词法分析结束后接受到一个标志SYM,该标志用来说明取到的这个单词是常量(CONSTSYM)还是变量(VARSYM)还是过程定义(PROCEDURE),然后分别对其进行不同的处理。如果是常量定义,则调用常量声明函数constdeclaration,如果是变量定义,则调用变量声明函数vardeclration。4、中间代码表示目标指令有8条:(1)LIT将常量取到运行栈顶。具体说明:该指令的作用是将常量取到运行栈顶,其中a域为常量域。(2)LOD将变量放到栈顶。由于此次课程设计的需要,这里先说明一下LOD的具体含义:gendo(LOD,l,a);其中l为调用层与说明层的层次差,由于该操作针对变量,所以我们可以用该变量与符号表中的元素进行匹配,如果匹配成功,那么就可以得到该变量说明层的层次,然后用这一层lev的值减去table[i].level就是要得到的层次差了;而对于a域,则是用来说明(定义)变量的过程,给变量分配的存储空间,相对该过程在运行栈基地址的偏移量,对于变量而言就是table[i].adr的值。(3)STO将栈顶的内容送入某个变量单元中。(4)CAL调用过程的指令。(5)INT为被调用的过程在运行栈中开辟数据区。(6)JMP无条件跳转指令。(7)JPC条件转移指令。这里我觉得有必要注意下指令JMP和JPC的区别。对于JMP,代码生成时候表示为:gen(jmp,0,a)属于无条件跳转指令,就是说该条指令执行完后接下来就是执行地址a所在的指令,而对于JPC,代码生成时表示为:gen(jpc,0,a)属于有条件跳转指令,而要注意的是:他是当栈顶的布尔值为非真的时候才转向a地址所在的指令,否则顺序执行。(8)OPR指令。程序中的代码生成是由过程GEN完成的。GEN过程有3个参数,分别代表目标的功能码、层差和位移量。生成的代码顺序存放在数组CODE中。六、源代码修改1、添加运算符*=、/=,基本与添加关键字操作一样,只是由于这四个为运算符,不属于关键字,因此头文件中的关键字个数不用修改。//voidGetSym()elseif(CH=='*'){//添加运算符*=GetCh();if(CH=='='){SYM=MULEQL;GetCh();}}elseif(CH=='/'){//添加运算符/=GetCh();if(CH=='='){SYM=DIVEQL;GetCh();}}elseif(CH=='&'){//添加运算符&&GetCh();if(CH=='&'){SYM=AND;GetCh;}else{SYM=NUL;}}elseif(CH=='|'){//添加运算符||GetCh();if(CH=='|'){SYM=OR;GetCh;}else{SYM=NUL;}}elseif(CH=='!'){//添加运算符!SYM=NOT;GetCh;}…………………………………………//voidSTATEMENTif(SYM==BECOMES){GetSym();EXPRESSION(FSYS,LEV,TX);if(i!=0)GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);}elseif(SYM==MULEQL)//添加*=运算{GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将左边变量放到栈顶GetSym();//获取下一个保留字;EXPRESSION(FSYS,LEV,TX);//计算右边表达式的值放入栈顶GEN(OPR,0,4);//将栈顶与次栈顶的值相乘GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//取栈顶值到原来左边的变量中}elseif(SYM==DIVEQL)//添加/=运算{GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将左边变量放到栈顶GetSym();//获取下一个保留;EXPRESSION(FSYS,LEV,TX);//计算右边表达式的值放入栈顶if(i!=0)GEN(OPR,0,5);//将栈顶与次栈顶的值相除GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//取栈顶值到原来左边的变量中}elseError(13);break;2、增加Pascal的FOR语句:caseFORSYM:GetSym();if(SYM==IDENT){i=POSITION(ID,TX);if(i==0)Error(11);elseif(TABLE[i].KIND!=VARIABLE){Error(12);i=0;}GetSym();if(SYM==BECOMES)GetSym();elseError(8);EXPRESSION(SymSetUnion(SymSetNew(STEPSYM),FSYS),LEV,TX);//FOR后面的表达式赋值语句if(i!=0)GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将栈顶内容送到变量中CX1=CX;GEN(JMP,0,0);//无条件跳转跳到UNTIL那里判断CX2=CX;//记录地址方便DO语句执行后的跳回再执行stepGEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);//将变量放到栈顶if(SYM==STEPSYM){GetSym();EXPRESSION(SymSetUnion(SymSetNew(UNTILSYM),FSYS),LEV,TX);//step后面的语句表达式处理}elseError(8);GEN(OPR,0,2);//把栈顶和次栈顶的相加放到栈顶GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);CODE[CX1].A=CX;//回填if(SYM==UNTILSYM)GetSym();elseError(8);GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);EXPRESSION(SymSetUnion(SymSetNew(DOSYM),FSYS),LEV,TX);//表达式处理GEN(OPR,0,12);//大于比较CX1=CX;GEN(JPC,0,0);//条件为假跳转intCX3;//由于CX3没有定义所以要定义CX3=CX;GEN(JMP,0,0);//无条件跳转跳到程序结束if(SYM==DOSYM)GetSym();elseError(8);CODE[CX1].A=CX;STATEMENT(FSYS,LEV,TX);//DO语句GEN(JMP,0,CX2);//由于已经记录了CX2的地址所以直接跳转就行了CODE[CX3].A=CX;//当条件不满足时跳到此处结束FOR循环}break;七、测试用例1、测试*=和/=运算:===COMPILEPL0===0PROGRAMTEST;0VARA,B;1BEGIN2READ(A);4READ(B);6A*=B;10WRITE(A);13END.0JMP011INI052OPR0163STO034OPR0165STO046LOD037LOD048OPR049STO0310LOD0311OPR01412OPR01513OPR00~~~RUNPL0~~~?2?612~~~ENDPL0~~~===COMPILEPL0===0PROGRAMTEST;0VARA,B;1BEGIN2READ(A);4READ(B);6A/=B;10WRITE(A);13END.0JMP011INI052OPR0163STO034OPR0165STO046LOD037LOD048OPR059STO0310LOD0311OPR01412OPR01513OPR00~~~RUNPL0~~~?9?33~~~ENDPL0~~~测试Pascal的FOR语句:===COMPILEPL0===0PROGRAMEX01;0VARD;1BEGIN2FORD:=03STEP17UNTIL1011DOWRITE(D);18END.0JMP011INI042LIT003
本文标题:广东工业大学编译原理课设
链接地址:https://www.777doc.com/doc-2456656 .html