编译原理课程设计--PL0语言的扩充.doc_第1页
编译原理课程设计--PL0语言的扩充.doc_第2页
编译原理课程设计--PL0语言的扩充.doc_第3页
编译原理课程设计--PL0语言的扩充.doc_第4页
编译原理课程设计--PL0语言的扩充.doc_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

0 编译原理课程设计 项目名称 PL/0 语言的扩充语言的扩充 学 院 计算机学院 专业班级 学 号 姓 名 指导教师 2013 年 1 月 3 日 报告成绩 0 一一 课课程程设计设计目的目的.0 二二 课课程程设计设计要求要求.0 基本内容:基本内容:.0 选做内容:选做内容:.0 已实现的功能:已实现的功能:.0 三三 编译环编译环境与工具境与工具.0 四四 结结构构设计说设计说明明.0 1 1PL/0PL/0 编译程序的结构图编译程序的结构图0 2 2PL/0PL/0 编译程序的过程或函数的功能表编译程序的过程或函数的功能表1 3 3PL/0PL/0 编译程序的总体流程图编译程序的总体流程图1 4 4PL/0PL/0 编译程序的中间代码编译程序的中间代码2 5 5PL0PL0 的编译程序的过程和函数的功能的编译程序的过程和函数的功能3 五五 课课程程设计设计的的设计设计与步与步骤骤.3 1扩充赋值运算:扩充赋值运算:+= -= *= /= + 和和- -5 2增加增加 PASCAL的的 FOR 语句语句15 3一维数组一维数组.17 六六 调试测试调试测试.19 1.+=1.+= -=-= *=*= /=/= + -的测试的测试.19 2.FOR2.FOR 语句的测试语句的测试21 3.3.数组的调试数组的调试.22 4 4综合调试综合调试.23 七七 课课程程设计总结设计总结.25 【参考文献参考文献】 .26 0 1课课程程设计设计目的目的 在分析理解一个教学型编译程序(如 PL/0)的基础上,对其词法分析程序、语法分析 程序和语义处理程序进行部分修改扩充。达到进一步了解程序编译过程的基本原理和基本 实现方法的目的。 2课课程程设计设计要求要求 基本内容:基本内容: (1)扩充赋值运算:*= 和 /= (2)扩充语句(Pascal 的 FOR 语句): FOR := TO DO FOR := DOWNTO DO 其中,语句的循环变量的步长为 2,语句的循环变量的步长为-2。 (3)增加运算:+ 和 -。 选做内容:选做内容: (1)增加类型: 字符类型; 实数类型。 (2)扩充函数: 有返回值和返回语句; 有参数函数。 (3)增加一维数组类型(可增加指令) 。 (4)其他典型语言设施。 已实现的功能:已实现的功能: (1)扩充赋值运算:*=和 /= (另外也扩充了+= 和 -=) (2)扩充语句(Pascal 的 FOR 语句): FOR := TO DO FOR := DOWNTO DO (3)增加运算:+ 和 -。 (4)增加一维数组类型(可增加指令) 。 3编译环编译环境与工具境与工具 编译环境:编译环境:Microsoft Windows 7 (64bit) 编译工具:编译工具:Microsoft Visual C+ 6.0 4结结构构设计说设计说明明 1 1PL/0PL/0 编译程序的结构图编译程序的结构图 1 PL/0 源程序 词法分析程序 语法语义分析程序 代码生成 目标代码 表格 管理 程序 出错 管理 程序 2 2PL/0PL/0 编译程序的过程或函数的功能表编译程序的过程或函数的功能表 过程或函数名简要功能说明 pl0 主程序 error 出错处理,打印出错位置和错误编码 getsym 词法分析,读取一个单词 getch 漏掉空格,读取一个字符 gen 生成目标代码,并送入目标程序区 test 测试当前单词符号是否合法 block 分程序分析处理过程 enter 登录名字表 position(函数)查找标识符在名字表中的位置 constdeclaration 常量定义处理 vardeclaration 变量说明处理 listode 列出目标代码清单 statement 语句处理 expression 表达式处理 term 项处理 factor 因子处理 condition 条件处理 interpret 对目标代码的解释执行程序 base(函数)通过静态链求出数据区的基地址 表 4-1 PL/0 编译程序的过程或函数的功能表 3 3PL/0PL/0 编译程序的总体流程图编译程序的总体流程图 图 4-1 PL/0 编译程序的结构图 2 启启动动 置置初初值值 调调用用GETSYM取取单单词词 调调用用BLOCK过过程程 当当前前单单词词 是是否否为为源源程程序序结结束束符符 .? 出出错错 源源程程序序中中 是是否否有有错错误误? 调调用用解解释释过过程程INTERPRET 解解释释执执行行目目标标程程序序 打打印印错错误误 结结束束 N N Y Y Y Y N N 图 4-2 PL/0 编译程序的总体流程图 4 4PL/0PL/0 编译程序的中间代码编译程序的中间代码 对 PL/0 编译程序的目标代码的指令格式描述如下: f l a 其中 f 代表功能码,l 表示层次差,a 的含意对不同的指令有所区别,见下面对每条指 令的解释说明: Lit 0 a将常数值取到栈顶,a 为常数值 lod l a将变量值取到栈顶,a 为偏移量,l 为层差 sto l a将栈顶内容送入某变量单元中,a 为偏移量,l 为层差 cal l a调用过程,a 为过程地址,l 为层差 int 0 a在运行栈中为被调用的过程开辟 a 个单元的数据区 jmp 0 a无条件跳转至 a 地址 jpc 0 a条件跳转,当栈顶布尔值非真则跳转至 a 地址,否则顺序执行 opr 0 0过程调用结束后,返回调用点并退栈 opr 0 1栈顶元素取反 opr 0 2次栈顶与栈顶相加,退两个栈元素,结果值进栈 opr 0 3次栈顶减去栈顶,退两个栈元素,结果值进栈 opr 0 4次栈顶乘以栈顶,退两个栈元素,结果值进栈 opr 0 5次栈顶除以栈顶,退两个栈元素,结果值进栈 opr 0 6栈顶元素的奇偶判断,结果值在栈顶 opr 0 7 opr 0 8次栈顶与栈顶是否相等,退两个栈元素,结果值进栈 opr 0 9次栈顶与栈顶是否不等,退两个栈元素,结果值进栈 3 opr 0 10次栈顶是否小于栈顶,退两个栈元素,结果值进栈 opr 0 11次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈 opr 0 12次栈顶是否大于栈顶,退两个栈元素,结果值进栈 opr 0 13次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈 opr 0 14栈顶值输出至屏幕 opr 0 15屏幕输出换行 opr 0 16从命令行读入一个输入置于栈顶 表 4-2 PL/0 编译程序的目标指令 5 5PL0PL0 的编译程序的过程和函数的功能的编译程序的过程和函数的功能 Pl0:主程序 Error:出错处理,打印出错位置和错误编码 Getsym:词法分析,读取一个单词 Getch:漏掉空格,读取一个字符 Gen:生成目标代码,并送入目标程序区 Test:测试当前单词符号是否合法 Block:分程序分析处理过程 Enter:登陆名字表 Position:查找标识符在名字表中的位置 Constdeclaration:常量定义处理 Vardeclaration:变量说明处理 Listcode:列出目标代码清单 Statement:语句部分处理 Expression:表达式处理 Term:项处理 Factor:因子处理 Condition:条件处理 Interpret:对目标代码的解释执行程序 Base:通过静态链求出数据区的基地址 5课课程程设计设计的的设计设计与步与步骤骤 本次课程设计是在实验的基础上,在实验中,已经实现对 PL/0 作以下修改扩充: (1)增加单词:保留字 ELSE,FOR,STEP,UNTIL,RETURN 运算符 +=,-=,+,-, (2)修改单词:不等号# 改为 ssym;=semicolon; ssym!=not; /非 ssym=lepa;/一维数组的左括号 ssym=ripa;/一维数组的右括号 /*设置保留字名字,按照字母顺序,便于折半查找*/ strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( /*设置保留字符号*/ wsym0=beginsym; 5 wsym1=callsym; wsym2=constsym; wsym3=dosym; wsym4=elsesym; wsym5=endsym; wsym6=forsym; wsym7=ifsym; wsym8=oddsym; wsym9=procsym; wsym10=readsym; wsym11=returnsym; wsym12=stepsym; wsym13=thensym; wsym14=untilsym; wsym15=varsym; wsym16=whilesym; wsym17=writesym; 设置指令名称(粗体部分为课程设计更改部分): strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( 1扩充赋值运算:扩充赋值运算:+= -= *= /= + 和和- - 6 := += -= *= /= + - + - 变量表达式 表达式 +a 或者-a a+或者 a- 图 5-1 扩充赋值运算:+= -= *= /= + 和- - 1)在 symbol 增加字符: Plusbecomes:+= Minusbecomes:-= Slashbecomes:*= Timesbecomes:/= 2)对取字符 getsym()函数进行扩充,具体如下(粗体部分为更改部分): int getsym() ./此处省略部分未修改过的代码 else if(ch=+) /读到加号 getchdo; /再读一个字符 if(ch=) /读到等号,则与+号构成加等 sym=plusbecomes; 7 getchdo; else if(ch=+) /读到加号,则与加号构成+ sym=dplus; getchdo; else sym=plus; /那就是一个单独的加号 else if(ch=-) /读到减号 getchdo; if(ch=) /读到等号,则与减号构成减等 sym=minusbecomes; getchdo; else if(ch=-) /读到减号,则与减号构成- sym=dminus; getchdo; else sym=minus; /那就是一个单独的减号 else if(ch=*) getchdo; if(ch=) /读到乘号,则与减号构成乘等 sym=timesbecomes; getchdo; else sym=times; /那就是一个单独的乘 else if(ch=/) 8 getchdo; if(ch=) /读到乘号,则与减号构成除等 sym=slashbecomes; getchdo; else sym=slash; /那就是一个单独的除 ./此处省略部分未修改过的代码 3)对 statemen 函数进行扩展 int statement(bool* fsys,int * ptx,int lev) ./此处省略部分未修改过的代码 if(sym=ident) i=position(id,*ptx); if(i=0) error(11); else if(tablei.kind!=variable i=0; else getsymdo; if(sym=lepa)/如果是数组 getsymdo; /处理里的表达式 memcpy(nxtlev,fsys,sizeof(bool)* symnum); nxtlevripa=true; expressiondo(nxtlev,ptx,lev); gendo(tra,0,tablei.size);/生成将数组下标范围入栈指令 gendo(jud,0,0);/判断下标合法性 9 if(sym!=ripa) error(26); getsymdo; if(sym=becomes)/赋值:= getsymdo; flag=1; else if(sym=plusbecomes)/加赋值+= getsymdo; flag=2; else if(sym=minusbecomes)/减赋值-= getsymdo; flag=3; else if(sym=dplus)/+ getsymdo; flag=4; else if(sym=dminus)/- getsymdo; flag=5; else if(sym=timesbecomes)/*= getsymdo; flag=6; else if(sym=slashbecomes)/ /= getsymdo; flag=7; else error(13); 10 if(i!=0) if(flag=1) /:= memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev); else if(flag=2)/+= memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev); gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶 gendo(opr,lev-tablei.level,2);/执行加法 else if(i!=0 expressiondo(nxtlev,ptx,lev); gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶 gendo(opr,lev-tablei.level,3);/执行减法 gendo(opr,lev-tablei.level,1);/取反 else if(i!=0/先取值到栈顶 gendo(lit,lev-tablei.level,1);/将值为 1 入栈 gendo(opr,lev-tablei.level,2);/加法,即 加 1 if(tablei.kind=array) gendo(gar,lev- tablei.level,tablei.adr); gendo(lit,lev-tablei.level,1); gendo(opr,lev-tablei.level,2); 11 else if(i!=0/先取值到栈顶 gendo(lit,lev-tablei.level,1);/将值为 1 入栈 gendo(opr,lev-tablei.level,3);/减法,即- 1 if(tablei.kind=array) gendo(gar,lev- tablei.level,tablei.adr); gendo(lit,lev-tablei.level,1); gendo(opr,lev-tablei.level,3); else if(i!=0 expressiondo(nxtlev,ptx,lev); gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶 gendo(opr,lev-tablei.level,4);/乘法 else if(i!=0 gendo(lod,lev-tablei.level,tablei.adr);/ 先取值到栈顶 memcpy(nxtlev,fsys,sizeof(bool)* symnum); expressiondo(nxtlev,ptx,lev); gendo(opr,lev-tablei.level,5);/除法 if(tablei.kind=array) /数组,根据偏移地址存入数组 gendo(sar,lev-tablei.level,tablei.adr); gendo(del,0,0);/赋值语句需将存入数组后栈顶为偏移地 址出栈 else /变量 gendo(sto,lev-tablei.level,tablei.adr); 12 /根据变量地址存入变量 else if(sym=dplus) /+变量 getsymdo; if(sym=ident)/后面跟的是变量 i=position(id,*ptx); if(i=0) error(11); else if(tablei.kind!=variablei=0; else /+后跟变量,处理生成中间代码 if(tablei.kind=variable) gendo(lod,lev-tablei.level,tablei.adr);/先取 值到栈顶 gendo(lit,0,1);/将值为 1 入栈 gendo(opr,0,2);/加法,即+1,栈顶加次栈顶 gendo(sto,lev-tablei.level,tablei.adr);/出栈 取值到内存 getsymdo; else if(tablei.kind=array) /后跟数组 getsymdo; if(sym=lepa) getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); nxtlevripa=true; expressiondo(nxtlev,ptx,lev); 13 gendo(tra,0,tablei.size); /生成将数组下标范围 入栈指令 gendo(jud,0,0); /判断下标合法性 if(sym!=ripa) error(26); /缺少 else gendo(gar,lev- tablei.level,tablei.adr); gendo(lit,0,1); gendo(opr,0,2); gendo(sar,lev- tablei.level,tablei.adr); gendo(del,0,0); getsymdo; else error(27);/缺少 else if(sym=dminus)/-变量 getsymdo; if(sym=ident) /后面跟的是变量 i=position(id,*ptx); if(i=0) error(11); else if(tablei.kind!=variablei=0; 14 else /-后跟变量,处理生成中间代码 if(tablei.kind=variable)/后跟变量 gendo(lod,lev-tablei.level,tablei.adr);/先取 值到栈顶 gendo(lit,0,1); /将值为 1 入栈 gendo(opr,0,3);/加法,即-1,栈顶减次栈顶 gendo(sto,lev-tablei.level,tablei.adr);/出栈 取值到内存 getsymdo; else if(tablei.kind=array)/后跟数组变量 getsymdo; if(sym=lepa) getsymdo; memcpy(nxtlev,fsys,sizeof(bool)* symnum); nxtlevripa=true; expressiondo(nxtlev,ptx,lev); gendo(tra,0,tablei.size);/生成将数组下标范围入 栈指令 gendo(jud,0,0);/判断下标合法性 if(sym!=ripa) error(26);/缺少 else gendo(gar,lev- tablei.level,tablei.adr); gendo(lit,0,1); gendo(opr,0,3); gendo(sar,lev- tablei.level,tablei.adr); gendo(del,0,0); getsymdo; else error(27);/缺少 15 ./此处省略部分未修改过的代码 2增加增加 Pascal 的的 FOR 语句语句 本次课程设计中要求扩充的是 Pascal 的 FOR 语句: FOR := TO DO FOR := DOWNTO DO ,流程图如下: for变量:=表达式to/downto 表达式do语句 图 5-2 增加 Pascal 的 FOR 语句 1)在 symbol 增加字符 FORSYM。 strcpy(KWORD10,“for“); WSYM 10= forsym; strcpy(KWORD22,“to“); WSYM22=tosym; strcpy(KWORD 7,“downto“); WSYM 7=downtosym; 2)对 statement 函数进行扩充 int statement(bool* fsys,int * ptx,int lev) ./此处省略部分未修改过的代码 else if(sym= forsym) getsymdo; if(sym=ident) / ident 为变量的符号 i=position(id,*ptx); if(i=0) error(11); else 16 if(tablei.kind!=variable) /赋值语句中,赋值号左部标识符属性应是 变量 error(12); i=0; else getsymdo; if(sym!=becomes) error(13); else getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); if(nxtlevtosym=true) / tosym else nxtlevdowntosym=true; / downtosym expressiondo(nxtlev,ptx,lev); /处理赋值语句右部的表达式 gendo(sto,lev-tablei.level,tablei.adr); /保存初始值 getsymdo; cx1=cx; /保存循环开始点 memcpy(nxtlev,fsys,sizeof(bool)*symnum); if(sym=dosym) getsymdo; statement(fsys,ptx,lev); /循环体处理 gendo(lod,lev-tablei.level,tablei.adr); /将循环变 量取出放在栈顶 gendo(opr,0,2); /循环变量加长 gendo(sto,lev-tablei.level,tablei.adr); /将栈顶的 值存入循环变量 gendo(jmp,0,cx1);/无条件跳转到循环开始点 codecx2.a=cx; /回填循环结束点的地址 else error(29); /for 语句中少了 do else error(19); /for 后面为赋值语句,赋值语句左部是变量,缺少变量 ./ 此处省略部分未修改过的代码 17 3一维数组一维数组 1)设置一维数组的左右括号: ssym=lepa; /一维数组的左括号 ssym=ripa; /一维数组的右括号 2)增加指令: strcpy( strcpy( strcpy( strcpy( strcpy( strcpy( enum fct lit, opr, lod, sto, cal, inte, jmp, jpc, gar, sar, shd, del, jud, tra, ; 由于指令有原来的 8 条拓展到了 14 条,故进行如下修改 #define fctnum 14 增加的指令意义如下: gar:根据栈顶的偏移地址从数组中取值到新的栈顶 sar:根据次栈顶的偏移地址把栈顶的值存入数组 shd:将栈顶的值下移到次栈顶,栈顶出栈,即次栈顶成为栈顶 del:出栈顶 jud:判断数组下标合法性 tra:将数组的下标范围入栈,gendo(tra,0,数组下标最大值); 3)增加标识符类型属性: enum object constant, variable, procedur, array, /数组 ; 4)在 block 函数中添加如下代码: for(i=tx0+1;i=st) error(28); printf(“n 运行问题出错,程序退出!请输入任意数字退出:“); scanf(“%d“, exit(1); break; case tra:/将数组的下标范围入栈 st=i.a; t+; break; ./ 此处省略部分未修改过的代码 6 调试测试调试测试 1.+=1.+= -=-= *=*= /=/= + -的测试的测试 20 图 6-1 测试文件 PL0_1.TXT 图 6-2 += -= *= /= + -的测试结果 1 21 图 6-2 += -= *= /= + -的测试结果 2 2.FOR2.FOR 语句的测试语句的测试 图 6-4 FOR 语句的测试文件 PL0.TXT 图 6-5 FOR 语句的测试结果 22 3.3.数组的调试数组的调试 图 6-6 数组的测试文件 PL0_3.TXT 图 6-6 数组的测试结果 1 图 6-6 数组的测试结果 2 23 4 4综合调试综合调试 综合测试是定语一个 1 维数组,数组每个元素的值等于它的位置。然后依次输出数组元 素。再次,对数组元素分别进行+= -= *= /= + -运算,用 FOR 语句输出结果。最后用 FOR 语句对其进行求和,再次输出结果。 图 6-7 综合的测试文件 PL0_4.TXT 24 图 6-8 综合结果的代码 25 图 6-8 综合结果的中间代码及其运算结果 7课课程程设计总结设计总结 本次课程设计的过程中我主要根据课本中的实现思想及算法以及源程序的方法编写和 修改程序,体现以课

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论