版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、编译原理课程设计 题 目 _ _PL0编辑器扩充_ _ 学 院 计算机学院 专 业 软件工程 年级班别 学 号 学生姓名 指导教师 答辩程序设计报告撰写平时总成绩2013 年 1 月 4 日一 课程设计目的与要求 1、课程设计目的:在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。达到进一步了解程序编译过程的基本原理和基本实现方法的目的。2、课程设计要求:基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:*= 和 /=扩充语句(Pascal的FOR语句):FOR <变量>:=<表达式>
2、TO <表达式> DO <语句>FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句> 其中,语句的循环变量的步长为2,语句的循环变量的步长为-2。(3)增加运算:+ 和 -。选做内容(成绩评定范围扩大到:“优”和“良”)(1)增加类型: 字符类型; 实数类型。(2)扩充函数: 有返回值和返回语句; 有参数函数。(3)增加一维数组类型(可增加指令)。(4)其他典型语言设施。二、结构设计方案 1、 结构设计说明: PL/0的编译程序以语法分析程序为核心,词法分析程序和代码生成程序都作为一个独立的过程,当语法
3、分析需要读单词时就用词法分析程序,而当语法分析正确需生成相应的目标代码时,则调用代码生成程序。此外,用表格管理程序建立变量,常量和过程标识符的说明与引用之间的信息联系。用出错处理程序对词法和语法分析遇到的错误给出在源程序中出错的位置和错误性质。2、 各功能模块图示:3. 各功能模块作用表:1PL0主程序2Error出错处理,打印出错位置和错误编码 3GetCh漏掉空格,读取一个字符 4GetSym词法分析,读取一个单词 5Gen生成目标代码,并送入目标程序区 6TEST测试当前单词符号是否合法 7ENTER登录名字表 8POSITION查找标识符在名字表中的位置 9ConstDeclarati
4、on常量定义处理10VarDeclaration变量说明处理11ListCode列出目标代码清单12FACTOR因子处理13TERM项处理14EXPRESSION表达式处理15CONDITION条件处理16STATEMENT语句部分处理17Block分程序分析处理过程18BASE通过静态链求出数据区的基地址19Interpret对目标代码的解释执行程序3. 符号名字表结构:struct tablestruct char nameal; /*名字*/ enum object kind; /*类型:const,var,array or procedure*/ int val; /*数值,仅cons
5、t使用*/ int level; /*所处层,仅const不使用*/ int adr; /*地址,仅const不使用*/ int size; /*需要分配的数据区空间,仅procedure使用*/;4. 保留关键字枚举结构:enum symbolnul, ident, number, plus,minus,times, slash, oddsym, eql, neq,lss, leq, gtr, geq,lparen,rparen, comma, semicolon, period, becomes,beginsym, endsym,ifsym, thensym, whilesym,write
6、sym, readsym, dosym, callsym, constsym,varsym, procsym, elsesym, forsym, tosym,downtosym, returnsym, pluseql, minuseql, plusplus,minusminus, ;5.名字表中标识符枚举类型:enum object constant, /*常量*/ variable, /*变量*/ procedur, /*过程*/;6. 运行时存储组织和管理对于源程序的每一个过程(包括主程序),在被调用时,首先在数据段中开辟三个空间,存放静态链SL、动态链DL和返回地址RA。静态链记录了定义
7、该过程的直接外过程(或主程序)运行时最新数据段的基地址。动态链记录调用该过程前正在运行的过程的数据段基址。返回地址记录了调用该过程时程序运行的断点位置。对于主程序来说,SL、DL和RA的值均置为0。静态链的功能是在一个子过程要引用它的直接或间接父过程(这里的父过程是按定义过程时的嵌套情况来定的,而不是按执行时的调用顺序定的)的变量时,可以通过静态链,跳过个数为层差的数据段,找到包含要引用的变量所在的数据段基址,然后通过偏移地址访问它。在过程返回时,解释程序通过返回地址恢复指令指针的值到调用前的地址,通过当前段基址恢复数据段分配指针,通过动态链恢复局部段基址指针。实现子过程的返回。对于主程序来说
8、,解释程序会遇到返回地址为0的情况,这时就认为程序运行结束。解释程序过程中的base函数的功能,就是用于沿着静态链,向前查找相差指定层数的局部数据段基址。这在使用sto、lod、stoArr、lodArr等访问局部变量的指令中会经常用到。类PCODE代码解释执行的部分通过循环和简单的case判断不同的指令,做出相应的动作。当遇到主程序中的返回指令时,指令指针会指到0位置,把这样一个条件作为终至循环的条件,保证程序运行可以正常的结束。7. 扩充赋值运算:+= 和 -= 设计:对于+=、-=、*=和/=赋值运算符,在程序中出现的情况只有如下一种,文法的EBNF 表示为:赋值语句:= <标识符
9、> += | -= <表达式>(1)扩充的语法描述见结构设计中的 PL/0 分程序和主要语句的语法描述中的描述图;(2)分析区别赋值运算符采用:读标识符后再读一个字符,后根据读到的字符转去不同的赋值语句执行。(3)中间代码生成情况:+=运算符,其他赋值运算符架构是一样的,只是执行加法改为相应的算数运算。读到+=运算符单词求+=运算符后的表达式expressiondo(nxtlev,ptx,lev);取+=左部的标识符的值到栈顶gendo(lod,lev-tablei.level,tablei.adr);执行加法gendo(opr,lev-tablei.level,2);保存赋
10、值后的结果gendo(sto,lev-tablei.level,tablei.adr);else if(sym=pluseql) /检测到+符号i=position(id,*ptx); /把类x+=3的x的地址取出来gendo(lod,lev-tablei.level,tablei.adr); /*找到变量地址并将其值入栈*/getsymdo;if(sym=semicolon)getsymdo;memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);gendo(opr,0,2);if(i!=0)gendo(st
11、o,lev-tablei.level,tablei.adr);else if(sym=minuseql) /检测到-符号i=position(id,*ptx); /把类x-=3的x的地址取出来gendo(lod,lev-tablei.level,tablei.adr); /*找到变量地址并将其值入栈*/getsymdo;if(sym=semicolon)getsymdo;memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);gendo(opr,0,3);if(i!=0)gendo(sto,lev-tablei
12、.level,tablei.adr); 8.扩充语句(Pascal的FOR语句):FOR <变量>:=<表达式> TO <表达式> DO <语句>FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句> 其中,语句的循环变量的步长为2,语句的循环变量的步长为-2For i:= E1 to E2 do S1 循环语句ALGOL等价于: i:= E1; goto OVER;AGAIN :i:= i+2OVER : if i<E2 then Begin S1;goto again e
13、nd;注意程序中基础用到循环控制变量i,因此 entry(i)必须被保存下来,而Pascal这样的语言中,循环变量在循环外也是可见的,本次扩充约定循环步长为 2或者-2。具体需要在程序staement()添加for的句法判断:else if(sym=forsym) /检测到for语句getsymdo;if(sym=ident)i=position(id,*ptx);if(i=0) error(11);elseif(tablei.kind!=variable) /赋值语句中,赋值号左部标识符属性应是变量error(12);i=0;elsegetsymdo;if(sym!=becomes) err
14、or(13); /赋值语句左部标识符后应是赋值号:=else getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlevtosym=true; /后跟符to和downtonxtlevdowntosym=true;expressiondo(nxtlev,ptx,lev); /处理赋值语句右部的表达式E1gendo(sto,lev-tablei.level,tablei.adr); /保存初值switch(sym)case tosym: /步长为的向上增加getsymdo;cx1=cx; /保存循环开始点 /将循环判断变量取出放到栈顶gendo
15、(lod,lev-tablei.level,tablei.adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum); /处理表达式E2nxtlevdosym=true; /后跟符doexpressiondo(nxtlev,ptx,lev);gendo(opr,0,13); /生成比较指令,i是否小于等于E2的值cx2=cx; /保存循环结束点/生成条件跳转指令,跳出循环,跳出的地址未知gendo(jpc,0,0);if(sym=dosym) /处理循环体Sgetsymdo;statement(fsys,ptx,lev); /循环体处理 /增加循环变量步长为 /
16、将循环变量取出放在栈顶gendo(lod,lev-tablei.level,tablei.adr); gendo(lit,0,1); /将步长取到栈顶gendo(opr,0,2); /循环变量加步长/将栈顶的值存入循环变量gendo(sto,lev-tablei.level,tablei.adr); gendo(jmp,0,cx1); /无条件跳转到循环开始点codecx2.a=cx; else error(29); /for语句中少了do break;case downtosym: /步长为的向下减少getsymdo;cx1=cx; /保存循环开始点/将循环判断变量取出放到栈顶gendo(l
17、od,lev-tablei.level,tablei.adr); memcpy(nxtlev,fsys,sizeof(bool)*symnum); /处理表达式E2nxtlevdosym=true; /后跟符doexpressiondo(nxtlev,ptx,lev); gendo(opr,0,11); /生成比较指令,i是否大于等于E2的值cx2=cx; /保存循环结束点/生成条件跳转指令,跳出循环,跳出的地址未知gendo(jpc,0,0); if(sym=dosym) /处理循环体Sgetsymdo;statement(fsys,ptx,lev); /循环体处理 /增加循环变量步长为/将
18、循环变量取出放在栈顶gendo(lod,lev-tablei.level,tablei.adr); gendo(lit,0,1); /将步长取到栈顶gendo(opr,0,3); /循环变量加步长/将栈顶的值存入循环变量gendo(sto,lev-tablei.level,tablei.adr); gendo(jmp,0,cx1); /无条件跳转到循环开始点codecx2.a=cx;else error(29);/for语句中少了dobreak;else error(19); /for语句后跟赋值语句,赋值语句左部是变量,缺少变量11. 增加运算:+ 和 - :对于+和-运算符,扩充时要注意存
19、在+,-有两个情况:1、作为语句的时候;2、作为表达式中的因子的时候.(1) 作为语句的时候,有四种情况: A+ +A A- -A文法的 EBNF 表示形式为:<自增自减语句>:=<标识符> + | - | + | - <标识符>(2) 作为因子的时候,有两种情况 a+和 a-作为因子,比如:b:=a+*a-;语句+a 和-a 作为因子,比如:b:= -a+2*+a;语句文法的 EBNF 表示形式为:<表达式>:=. + | - <标识符>|<标识符> + | - .其中的.表示前后都可以有其他的项或因子(1)作为语句 +
20、 - 符号分为以下两种情况考虑:情况1对于自增自减符号置后的只需要在判断+= -=后面添加句法分析即可:/*后置自增符号 a+ a-类型添加代码*/else if(sym=plusplus) /检测到后置+符号gendo(lit,0,1);gendo(lod,lev-tablei.level,tablei.adr); /*找到变量地址并将其值入栈*/gendo(opr,0,2); /执行加操作,if(i!=0) gendo(sto,lev-tablei.level,tablei.adr);getsymdo;else if(sym=minusminus) /检测到后置-符号gendo(lod,l
21、ev-tablei.level,tablei.adr); /*找到变量地址并将其值入栈*/gendo(lit,0,1);gendo(opr,0,3); /执行减操作,if(i!=0) gendo(sto,lev-tablei.level,tablei.adr);getsymdo;情况2对于+ -前置的需要添加因子开始符号: facbegsysplusplus=true; /*增加符号+开始因子plusplus*/facbegsysminusminus=true; /*增加符号-开始因子minusminus*/*前置自增符号 +a - -a类型添加代码*/if(sym=plusplus)gets
22、ymdo;if(sym=ident) /后面跟的是变量i=position(id,*ptx);if(i=0)error(11);elseif(tablei.kind!=variable) /+后没跟变量,出错error(12);i=0;else /+后跟变量,处理生成中间代码if(tablei.kind=variable)gendo(lod,lev-tablei.level,tablei.adr);/先取值到栈顶gendo(lit,0,1); /将值为入栈gendo(opr,0,2); /加法,即+1,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/
23、出栈取值到内存getsymdo;else if(sym=minusminus)getsymdo;if(sym=ident) /后面跟的是变量i=position(id,*ptx);if(i=0)error(11);elseif(tablei.kind!=variable) /-后没跟变量,出错error(12);i=0;else /-后跟变量,处理生成中间代码if(tablei.kind=variable) /后跟变量gendo(lod,lev-tablei.level,tablei.adr);/先取值到栈顶gendo(lit,0,1); /将值为入栈gendo(opr,0,3); /加法,即
24、-1,栈顶减次栈顶gendo(sto,lev-tablei.level,tablei.adr);/出栈取值到内存getsymdo;(2)作为因子的时候也有两种情形考虑: 添加int factor(bool*fsys,int *ptx,int lev)函数如下:/*如果因子可能出现b:=a+或b:=a-类型的处理*/if(sym=plusplus)gendo(lit,lev-tablei.level,1); /将值为入栈gendo(opr,lev-tablei.level,2); /加法,即+1,栈顶加次栈顶gendo(sto,lev-tablei.level,tablei.adr); /出栈取
25、值到内存gendo(lod,lev-tablei.level,tablei.adr); /取值到栈顶gendo(lit,0,1);gendo(opr,0,3); /栈顶值减getsymdo;else if(sym=minusminus)gendo(lit,lev-tablei.level,1); /将值为入栈gendo(opr,lev-tablei.level,3); /减法,即-1,栈顶减次栈顶gendo(sto,lev-tablei.level,tablei.adr); /出栈取值到内存gendo(lod,lev-tablei.level,tablei.adr);gendo(lit,0,1
26、);gendo(opr,0,2); /栈顶值加getsymdo; /*/*如果因子是表达式的时候,则有可能是包含+a或者-a,如b:=+a或b:=-a */ else if(sym=plusplus)getsymdo;if(sym=ident)getsymdo;i=position(id,*ptx);if(i=0)error(11);elseif(tablei.kind=variable) /变量 /先加后再用agendo(lod,lev-tablei.level,tablei.adr);/先取值到栈顶gendo(lit,0,1);/将值为入栈gendo(opr,0,2);/加法,即+1,栈顶
27、加次栈顶gendo(sto,lev-tablei.level,tablei.adr);/出栈取值到内存gendo(lod,lev-tablei.level,tablei.adr); /取值到栈顶else if(sym=minusminus)getsymdo;if(sym=ident)getsymdo;i=position(id,*ptx);if(i=0)error(11);elseif(tablei.kind=variable) /变量 /先减后再用agendo(lod,lev-tablei.level,tablei.adr);/先取值到栈顶gendo(lit,0,1); /将值为入栈gend
28、o(opr,0,3); /减法,即-1,栈顶减次栈顶gendo(sto,lev-tablei.level,tablei.adr);/出栈取值到内存gendo(lod,lev-tablei.level,tablei.adr); /取值到栈顶testdo(fsys,facbegsys,23); /*因子后有非法符号*/四. 程序测试1. 扩充赋值运算:*= 和 /= 测试文件 “test1”: 运行结果: 结果分析: a = 5 ,b = 48 , a*=3 结果为15正确,b/=6结果为8正确,扩充成功! 2. 扩充语句(Pascal的FOR语句):测试文件“test2”:运行结果:结果分析:
29、For i=1 to 4 do “write(i)” 结果i= 1,3, For i=5 downto 1 do write(i) 结果i= 5,3,1 结果正确, For循环功能扩充成功!3. 增加运算:+ 和 -。 测试文件“test3”: 运行结果: 结果分析: a=5 ,b:=6, a-结果为4,b+结果为7,结果正确 + ,-功能符号测试通过!五. 实验总结本次课程设计主要是在读懂课本附带的PL/0 编译器程序C语言版本后进行扩展和修改相关程序功能。通过课程设计,我对编译器的工作原理和实现机制有了实际的了解和认识,进一步培养的编译技术的设计思想,仔细阅读 PL/0 的编译程序C语言版
30、本代码,对词法分析,句法分析在编程技巧和实际意义有了深刻的理解,从枯燥的理论学习到现在实际应用过程对于我自身知识面的提升是巨大的。语法分析、句法分析在编译原理中处于核心的地位,如何正确有效的对它们分析提取决定了编译后期工作方向,当然中间代码的如何有效的生成在编译中也是个不小的难题,特别是其中堆栈的运用,当然在理论上对于它们的理解程度大小也是决定设计调试难度的高低。 扩展 += -= 符号相对比较简单,只需要在语句分析模块接着赋值符号的判断添加就可以,对于for循环也是类似,只需要在语句分析模块添加对于for关键字的判断,当然要注意后继符号to 还是 downto的判断以决定步长递增还是递减。完成了基本功能扩展,我尝试了+ -符号的添加,这两个符号添加比较复杂,大体讲有两个用途情况,一个就是用在用户标识符,另一个就是在因子上也可能用到该功能,需要添加因子的功能判断,具体来讲这两个符号又有两种实现形式,分别是后置符号和前置符号,后置符号类似前面的+= -= 直接添加判断即可,前置符号则除了要添加+ -的开始因子符号集外,还得在语句分析模块添加功能处理! 总的来说,经历了数次的调试,功
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 4944-2026玻璃纤维增强塑料层合板层间拉伸强度试验方法
- 吴文英《梦窗词》讲解
- 苻坚的前秦霸业
- DB51∕T 3366-2026 发电用燃料电池堆电性能测试规范
- 2026年语文教学方法策略研究报告
- 2026年固定资产规范化管理方案设计
- 2026年奶茶店经营策略与管理
- 2026年安全防范技术未来发展趋势分析
- 2026年实验安全问题及其教学研究
- 2026年导游职业发展初期目标
- 2026年高考真题-语文(全国二卷) 含解析
- 2026年湖南岳阳市初二学业水平地生会考真题试卷(含答案)
- 2026春人教版三年级下册语文全册看拼音写词语专项练习(可打印)
- 2026年外贸应聘人员测试题及答案
- 2026云南临沧国投宏华招聘综合业务开单员3人备考题库附答案详解(典型题)
- 西安铁路局集团有限公司招聘笔试题库2026
- 2025福建福州市闽侯县水务投资发展有限公司招聘3人笔试历年参考题库附带答案详解
- 2026年生物制药疫苗研发关键技术知识考察试题及答案解析
- 街道办公室工作制度
- 无废工厂培训资料
- 岳飞传课件教学课件
评论
0/150
提交评论