版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 编译原理课程设计PL0 Experiment Report(燕山大学 信息科学与工程学院) 姓 名 班 级 : 计算机* 学 生 学 号 : 130104010*&* 课 程 名 称 : 编译原理 指 导 教 师 : 888 2015年 12 月 24 日 一、设计目的研究、 改进或自行设计、 开发一个简单的编译程序或其部分功能, 加深对编译理论和编译过程的理解。 编程语言不限。二、设计任务扩展 PL/0 编译程序功能目的: 扩充 PL/0 编译程序功能要求: (1)阅读、 研究 PL/0 编译程序源文件。 (2)在上述工作基础上, 可有选择地补充、完善其中词法分析、语法分析、语义分
2、析、目标代码生成、目标代码解释执行等部分的功能。如以语法分析部分为例,则可以增加处理更多语法成分的功能,如可处理一维数组、+、-、+=、-=、*=、/=、%(取余)、!(取反)、repeat、for、else、开方、处理注释、错误提示、标示符或变量中可以有下划线等。还可以增加类型,如增加字符类型、实数类型; 扩充函数如有返回值和返回语句的,有参数函数等; (3)设计编制典型的运行实例,以便能反映出自己所作的改进。 三、设计思想:PL/0 语言可以看成PASCAL 语言的子集,它的编译程序是一个编译解 释执行系统。PL/0 的目标程序为假想栈式计算机的汇编语言,与具体计算 机无关。 P
3、L/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写 的,因此PL/0 语言可在配备PASCAL 语言的任何机器上实现 。其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序, 而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序。 用表格管理程序建立变量、常量和过程表示符的说明与引用之间的信息联系。当源程序编译正确时,PL/0 编译程序自动调用解释执行程序,对目标 代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。四、设计内容:1 扩充语句for(<语句>;<条
4、件>;<语句>)<语句>;2 扩充语句if <条件> then <语句> else <语句>;3 扩充语句repeat <语句>;until <条件>;4 增加自增自减运算+和和+=,-=运算;5 修改不等号#,为!=;6 增加一维数组声明格式:<ident><ident>/<number>:<ident>/<number>;赋值格式:<ident><index>:=<表达式>;调用格式:<ident&g
5、t;<index>五、程序结构:程序pl0程序block语句statement条件condition表达式expression项term因子factorPL/0源程序 词法分析程序表格管理程序语法分析程序出错管理程序代码生成程序目标程序图1 编译程序结构 图2功能模块调用1.功能模块作用如下:Pl0.c:主程序Error:出错处理,打印出错位置和错误编码Getsym:词法分析,读取一个单词Getch:漏掉空格,读取一个字符Gen:生成目标代码,并送入目标程序区Test:测试当前符号是否合法Block:分程序分析处理过程,词法语法分析Enter:登陆名字表Position:查找标识符
6、在名字表中的位置Constdeclaration:常量定义处理Vardeclaraction:变量说明处理Listcode:列出目标代码清单Statement:语句处理Expression:表达式处理Term:项处理Factor:因子处理Condition:条件处理Interpret:对目标代码的解释执行程序Base:通过静态链求出数据取得基地址增加两个功能:Arraydeclaration:数组声明处理Arraycoef:数组索引计算和“虚拟机”动作生成2.保留字:enum symbol nul,ident,number,plus,minus, times,slash,oddsym,eql,
7、neq, lss,leq,gtr,geq,lparen, rparen,comma,semicolon,period,becomes, beginsym,endsym,ifsym,thensym,elsesym,forsym, inc,dec,whilesym, writesym, readsym,dosym,callsym, constsym,varsym, procsym,repeatsym, untilsym, plusbk,minusbk, lbrack,rbrack,colon,共43个,其中补充保留字为:else, for, repeat, until, plusbk, minus
8、bk, Lbrack, rbrack, colon3.名字表中的类型enum object constant, variable, procedure, arrays, 共4个,扩充arrays,以便实现数组4.虚拟机代码enum fct lit, opr, lod, sto, cal, inte, jmp, jpc,lda, sta, 共10个,补充的lda,sta用于数组操作6. 错误信息(1)const,var,procedure后应为标识符(2) 常数说明中的=后应是数字(3)常数说明中的标识符后应是=(4)常数说明中的=写成了:=(5)漏掉了,或;(6)过程说明后的符号不正确(应是语
9、句开始符,或过程定义符)(7)应是语句开始符(8)标识符未说明(9)程序结尾丢了句号。(10)语句之间漏了;(11)call后应为标识符(12)赋值语句中,赋值号左部标识符属性应是变量(13)赋值号左部标识符属性应是赋值号(14)程序体内语句部分的后跟符不正确(15)call后标识符属性应为过程(16)条件语句中丢了then(17)丢了end或;(18)while循环语句中丢了do(19)语句后的符号不正确6.名字表结构struct tablestructchar nameal;enum object kind;int val;int level;int adr;int size;/扩充名字表
10、结构,增加一个data域保存数组的下界int data; /* 其他数据,对arrays来说是下界*/7.语法描述图:程序分程序 .图3 程序语法描述图,。;,;=语句constidentnumbervaridentprocedureident分程序图4 分程序语法描述图语句语句until表达式表达式:=if条件endthen语句条件do语句(表达式),(ident,)begin语句语句;identcallidentwhilerepeatreadwritedecsincsincsdecselse语句for条件语句图5 语句语法描述图 条件=<>#>=odd表达式表达式<
11、=图6条件语法描述图表达式项项+ 图7 表达式语法描述图项因子因子/*%图8 项语法描述图因子)(表达式identnumberincsdecsdecsincs图9 因子语法描述图四、功能扩充1.语句处理中加入for循环语句if(sym = forsym)getsymdo;if(sym != lparen) error(34);/没有左括号出错else getsymdo;statementdo(nxtlev, ptx, lev); /S1代码if(sym != semicolon) error(10); /语句缺少分号出错elsecx1=cx;getsymdo;conditiondo(nxtle
12、v, ptx, lev); /E代码if(sym!=semicolon)error(10);/语句缺少分号出错else cx2=cx;gendo(jpc,0,0);cx3=cx;gendo(jmp,0,0);getsymdo;cx4=cx;statementdo(nxtlev, ptx, lev);/S2代码if(sym != rparen) error(22);/缺少右括号出错else gendo(jmp,0,cx1);getsymdo;cx5=cx;statementdo(nxtlev, ptx, lev); /S3代码codecx3.a=cx5;gendo(jmp,0,cx4);code
13、cx2.a=cx;2.在语句处理中增加repeat-until语句if(sym = repeatsym)cx1 = cx;getsymdo;statementdo(nxtlev, ptx, lev);if(sym = untilsym)getsymdo;conditiondo(nxtlev, ptx, lev);cx2=cx;gendo(jpc, 0, 0);codecx2.a=cx1; else error(33); /没有写until出错3.扩充+和运算符对于+和-运算符,扩充时要注意存在两个情况:1)作为语句的时候;2)作为表达式中的因子的时候。 注意:扩充时增加因子开始符facbegs
14、ysincs=true和facbegsysdecs=true。 扩充的语法描述见结构设计中的PL/0分程序和主要语句的语法描述中的描述图,详细代码见程序。 1)作为语句的时候,有四种情况: a+; a-; +a; -a; 文法的EBNF表示形式为: <自增自减语句>:=<标识符>+ |-|+|- <标识符> 文法分析过程大体如下图: 语句开始符SYM=+或者-读下个SYM,如是ident,确定为自增自减语句语句开始符SYM=ident读下个SYM,如是+或者-,确定为自增自减语句 +a和a a+和a生成中间代码对于a+;+a;和a-;-a;语句的处理如下:
15、先将变量的值取出放在栈顶,后将1入栈,后执行加法或减法运算oprv指令的2(加法)、3(减法),后将运算后的栈顶值存回变量。 a+;和+a;语句的中间代码:lod 0 3;lit 0 1;opr 0 2;sto 0 3;a-;和-a;语句的中间代码:lod 0 3;lit 0 1;opr 0 3;sto 0 3; 2) 作为因子的时候,有两种情况: a+和a-作为因子,比如:b:=a+*a-;语句 +a和-a作为因子,比如:b:=-a+2*+a;语句 文法的EBNF表示形式为: <表达式>:=. +|-<标识符>|<标识符>+| -. 其中的.表示前后都可以
16、有其他的项或因子 生成中间代码A对于因子+a和-a的中间代码生成处理和a+;等语句处理一样; B对于因子a+和a的中间代码生成处理如下:a+:lod 0 3;lit 0 1;opr 0 2;sto 0 3;lod 0 3;lit 0 1;opr 0 3; a-:lod 0 3;lit 0 1;opr 0 3;sto 0 3;lod 0 3;lit 0 1;opr 0 2; 先将变量的值取出放在栈顶,后将1入栈,后执行加法或减法运算opr指令的2(加法)、3(减法),后将运算后的栈顶值存回变量,后将变量的值又取出来放入栈顶,后将1入栈,如果是a+就执行减法,如果是a就执行加法,以实现先用a的值后
17、再加1。4.语句处理中加入if-then-else语句在原有程序if(sym=then).后加入下列代码:cx1 = cx;gendo(jpc, 0, 0);statementdo(fsys, ptx, lev);if(sym = elsesym)getsymdo;cx2 = cx;gendo(jmp, 0, 0);codecx1.a = cx;statementdo(fsys, ptx, lev);codecx2.a = cx;elsecodecx1.a = cx;5.修改不等号#为!=注释源程序中的ssym'#' = neq语句,在getsym中加入下列代码:/修改不等号为
18、!=else if(ch='!')getchdo;if(ch='=')sym=neq;getchdo; else sym=nul; 6.加入对一维数组的支持本程序将数组看做变量的一种,由var声明函数调用array声明函数完成数组声明,这样就处加入文件输出的相关语句外,可以完全保留block函数和enter函数;通过改写factor函数使数组因子包括了后缀的索引号,这样就可以调用通用的表达式函数赋值数组了。为了方便完成数组相关功能,扩充了虚拟机处理代码。数组的越界及非法调用错误处理没有完善,仅给出了错误代码。在头文件pl0.h中:/*定义两个全局变量,用来保存数
19、组定义的下界和容量*/static int g_arrBase = 0;static int g_arrSize = 0;/* 虚拟机代码*/增加lda,sta专门由于数组的处理/增加两个虚拟机指令lda,sta,分别用来从数组中取数和存到数组中/数组元素的访问和存储,是将()后的当成表达式,先处理,得到元素的索引,放在栈顶/最后根据数组的首地址,得到某个元素的地址enum fct .lda, sta /扩充名字表结构,增加一个data域保存数组的下界struct data; /* 其他数据,对arrays来说是下界*/* 名字表中的类型*/enum objec
20、t .arrays /添加数组类型/数组声明处理, 下界和上界允许已经定义过的常量标识符int arraydeclaration(int* ptx, int lev, int* pdx);/数组元素索引计算与“虚拟机”生成int arraycoef(bool *fsys,int *ptx,int lev);在源程序文件pl0.c中:编写相关的arraydeclaration,arraycoef两个功能函数:/* 数组声明处理, 下界和上界允许已经定义过的常量标识符*/int arraydeclaration(int* ptx, int lev, int* pdx) char arrIdal;
21、/* 暂存数组标识名,避免被覆盖*/ int cstId; /* 常量标识符的位置*/ int arrBase=-1, arrTop=-1; /* 数组下界、上界的数值*/getsymdo; if(sym=lbrack) /* 标识符之后是'',则识别为数组*/ strcpy(arrId, id); /* 检查下界*/ getsymdo; if(sym=ident) if(cstId=position(id,(*ptx)!=0)arrBase=(constant=tablecstId.kind)?tablecstId.val:-1; elsearrBase=(sym=numbe
22、r)?num:-1; if(-1=arrBase)error(50);return -1; /* 检查冒号*/getsymdo;if(sym!=colon) error(50);return -1; /* 检查上界*/ getsymdo; if(sym=ident) if(cstId=position(id,(*ptx)!=0)arrTop=(constant=tablecstId.kind)?tablecstId.val:-1; elsearrTop=(number=sym)?num:-1; if(arrTop=-1)error(50);/随意指定,因为原程序对错误号的规划极差!return
23、 -1; /* 检查'' */ getsymdo; if(sym!=rbrack) error(50);return -1; /* 上下界是否符合条件检查*/ g_arrSize=arrTop-arrBase+1; g_arrBase=arrBase; if(g_arrSize<=0)error(50);return -1; /* 恢复数组的标识符*/ strcpy(id, arrId); return 1; return 0;/* 数组元素索引计算与“虚拟机”生成*/int arraycoef(bool *fsys,int *ptx,int lev) bool nxtl
24、evsymnum; int i = position(id,*ptx); getsymdo; if (sym=lbrack) /* 索引是括号内的表达式*/ getsymdo; memcpy(nxtlev,fsys,sizeof(bool)*symnum); nxtlevrbrack=true; expressiondo(nxtlev,ptx,lev); if (sym=rbrack) gendo(lit,0,tablei.data); gendo(opr,0,3); /* 系数修正,减去下界的值*/ return 0; elseerror(22); /* 缺少右括号*/ elseerror(
25、51); /* 数组访问错误*/ return -1;修改函数enter,block,vardeclaration,factor及statement,使其具备处理数组的功能:/将数组变量登陆名字表void enter(enum object k, int * ptx, int lev, int * pdx).case arrays: /* 数组名,进行记录下界等*/ table(*ptx).level = lev; table(*ptx).adr = (*pdx); table(*ptx).data = g_arrBase; table(*ptx).size = g_arrSize; *pdx
26、 = (*pdx)+g_arrSize; break;./输出数组名字表到控制台和文件fas.tmpint block(int lev, int tx, bool * fsys).case arrays:printf("%d array %s ", i, );printf("lev=%d addr=%d size=%dn", tablei.level, tablei.adr, tablei.size);fprintf(fas, "%d array %s ", i, );fprintf(fas
27、, "lev=%d addr=%d size=%dn", tablei.level, tablei.adr, tablei.size);/加入数组声明int vardeclaration(int * ptx, int lev, int * pdx)int arrayRet=-1; if (sym=ident) arrayRet=arraydeclaration(ptx,lev,pdx); /* 先判断数组*/ switch(arrayRet) case 1: enter(arrays,ptx,lev,pdx); / 填写数组名getsymdo; break; case 0:
28、 enter(variable,ptx,lev,pdx); / 填写名字表 /getsymdo; break; default: return -1; /* 数组定义解析出错*/ elseerror(4); /* var后应是标识*/ return 0;/*当因子是数组型变量时,调用arraycodefdo将数组的索引入栈顶,之后按vatiabler变量操作*/int factor(bool * fsys, int * ptx, int lev).switch (tablei.kind).case arrays: /* 名字为数组名*/arraycoefdo(fsys,ptx,lev);gen
29、do(lda,lev-tablei.level,tablei.adr); /* 找到变量地址并将其值入栈*/. . int statement(bool * fsys, int * ptx, int lev).if (sym = ident).if (tablei.kind != variable)&&(tablei.kind != arrays)error(12); i = 0;elseenum fct fct1 = sto; switch(tablei.kind)case arrays:arraycoefdo(fsys, ptx, lev);fct1 = sta; /* 数
30、组保存,要多读一个栈*/case variable:./增加的两个虚拟机代码的处理:lda,stavoid interpret().case lda: /* 数组元素访问,当前栈顶为元素索引,执行后,栈顶变成元素的值*/st-1 = sbase(i.l,s,b) + i.a + st-1;break;case sta: /* 栈顶的值存到数组中,索引为次栈顶*/t-=2;sbase(i.l,s,b) + i.a + st = st+1;break;.五、调试及运行结果1.测试repeat.until.语句功能 测试文件:4.txt 测试结果: var a,b,n; begin b:=4; a:=1; read(n); repeat a:=a+1;b:=b+1; until a>n; write(a); write(b);end.当输入的n为3时,repeat.until.语句中的循环体执行3次,所以a=4,b=72.测试增加的+,-功能 测试文件:2.txt 测试结果:var a,b;begin a:=1; b:=3; a
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024企业员工盈利分配合作合同
- 2024廉租物业服务合同
- 2024年度许可使用合同:影视作品授权播放与发行协议3篇
- 2024年度文化传播机构员工劳动合同标准模板3篇
- 2024年智慧城市建设聘请博士规划设计合同3篇
- 2024购销合同样式
- 2024年婚前合同范本:权益与责任明细一
- java课程设计+计算器阶乘
- 2024平面模特形象代言聘用合同-时尚界合作典范3篇
- 大数据分析工具课程设计
- GB/T 44770-2024智能火电厂技术要求
- 大学与文化传承智慧树知到期末考试答案章节答案2024年浙江大学
- 浙西南红军歌曲赏析智慧树知到期末考试答案章节答案2024年丽水学院
- 室内设计意向书
- 液氨制冷系统排氨实施方案和应急预案
- 修复知情同意书
- 《0-6岁儿童中医药健康管理技术规范》
- 基于单片机的多功能秒表的课程设计
- 物流战略规划
- 化工原理设计--苯—甲苯分离过程板式精馏塔设计
- 压力容器计算书
评论
0/150
提交评论