编译原理课程设计报告PL0编译程序改进及完善.docx

上传人:b****3 文档编号:11615323 上传时间:2023-06-01 格式:DOCX 页数:30 大小:440.57KB
下载 相关 举报
编译原理课程设计报告PL0编译程序改进及完善.docx_第1页
第1页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第2页
第2页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第3页
第3页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第4页
第4页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第5页
第5页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第6页
第6页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第7页
第7页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第8页
第8页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第9页
第9页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第10页
第10页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第11页
第11页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第12页
第12页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第13页
第13页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第14页
第14页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第15页
第15页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第16页
第16页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第17页
第17页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第18页
第18页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第19页
第19页 / 共30页
编译原理课程设计报告PL0编译程序改进及完善.docx_第20页
第20页 / 共30页
亲,该文档总共30页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

编译原理课程设计报告PL0编译程序改进及完善.docx

《编译原理课程设计报告PL0编译程序改进及完善.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计报告PL0编译程序改进及完善.docx(30页珍藏版)》请在冰点文库上搜索。

编译原理课程设计报告PL0编译程序改进及完善.docx

编译原理课程设计报告PL0编译程序改进及完善

 

燕山大学

《编译原理课程设计》

 

题目:

《PL/0编译程序改进及完善》

姓名:

简越

班级:

06级计算机应用3班

学号:

060104010084

日期:

2009年7月15日

设计题目:

PL/0编译程序改进及完善。

设计目的:

阅读研究,改进设计和调试一个简单的编译程序。

加深对编译理论和过程的了解。

设计要求:

1.有选择的对PL/0编译源程序补充,完善.

2.设计编译典型的运行实例,以便反应出自己作出改进后的编具有的功能。

设计思想:

PL/0语言可以看成PASCAL语言的子集,它的编译程序是一个编译解释执行系统。

PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。

PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配备PASCAL语言的任何机器上实现。

其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需要生成相应的目标代码时,则调用代码生成程序。

用表格管理程序建立变量、常量和过程表示符的说明与引用之间的信息联系。

当源程序编译正确时,PL/0编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序的要求输入数据和输出运行结果。

主要变量说明:

/*变量说明*/

FILE*fas;/*输出名字表*/

FILE*fa;/*输出虚拟机代码*/

FILE*fa1;/*输出源文件及其各行对应的首地址*/

FILE*fa2;/*输出结果*/

boollistswitch;/*显示虚拟机代码与否*/

booltableswitch;/*显示名字表与否*/

charch;/*获取字符的缓冲区,getch使用*/

enumsymbolsym;/*当前的符号*/

charid[al+1];/*当前ident,多出的一个字节用于存放0*/

intnum;/*当前number*/

intcc,ll;/*getch使用的计数器,cc表示当前字符(ch)的位置*/

intcx;/*虚拟机代码指针,取值范围[0,cxmax-1]*/

charline[81];/*读取行缓冲区*/

chara[al+1];/*临时符号,多出的一个字节用于存放0*/

structinstructioncode[cxmax];/*存放虚拟机代码的数组*/

charword[norw][al];/*保留字*/

enumsymbolwsym[norw];/*保留字对应的符号值*/

enumsymbolssym[256];/*单字符的符号值*/

charmnemonic[fctnum][5];/*虚拟机代码指令名称*/

booldeclbegsys[symnum];/*表示声明开始的符号集合*/

boolstatbegsys[symnum];/*表示语句开始的符号集合*/

boolfacbegsys[symnum];/*表示因子开始的符号集合*/

/*目标指令*/

1、LIT:

将常量值取到运行栈顶.

2、LOD:

将变量放到运行栈顶.

3、STO:

将栈顶的内容送入某变量单元中.

4、CAL:

调用过程的指令.

5、INT:

为被调用的过程(或主程序)在运行栈中开辟数据区.

6、JMP:

无条件转移指令.

7、JPC:

条件转移指令,当栈顶的布尔值为真时,顺序执行,否则转向域的地址.

8、OPR:

系运算符和算术运算指令.将栈顶和次栈顶的内容进行运算,结果存放栈顶.

/*函数说明*/

voiderror(intn,intline)

说明:

出错处理函数,打印出错信息,错误总数加1。

intgetch()

说明:

读取字符函数,返回字符。

intgetsym()

说明:

读取下一单词符号

intposition(char*idt,inttx);

说明:

字符在符号表中位置查询函数

返回值:

返回标识符在符号表中的索引

intgen(enumfctx,inty,intz);

说明:

生成P代码指令

inttest(bool*s1,bool*s2,intn);

说明:

测试当前符号是否合法,若不合法,打印出错信息并进行跳读

voidenter(enumobjectk,int*ptx,intlev,int*pdx);

说明:

在符号表中登录分程序说明部分出现的名字

intconstdeclaration(int*ptx,intlev,int*pdx);

说明:

处理常量说明,并将常量名及相应信息填入符号表

intvardeclaration(int*ptx,intlev,int*pdx);

说明:

处理变量说明,并将变量名及相应信息填入符号表

intstatement(bool*fsys,int*ptx,intlev);

说明:

分析处理各种语句

intcondition(bool*fsys,int*ptx,intlev);

说明:

分析处理条件式

返回值:

由参数x返回求值结果的类型

voidlistcode(intcx0);

说明:

打印P代码

intblock(intlev,inttx,bool*fsys);

说明:

PL0编译器对外的接口,由main()调用

voidinterpret();

说明:

解释执行P代码

intbase(intl,int*s,intb);

说明:

基地址处理函数

返回值:

返回变量的基地址值

intexpression(bool*fsys,int*ptx,intlev)

说明:

表达式处理,由参数返回结果类型

intterm(bool*fsys,int*ptx,intlev);

说明:

项处理,由参数返回结果类型

intfactor(bool*fsys,int*ptx,intlev);

说明:

因子处理,由参数返回结果类型

intinset(inte,bool*s);

intaddset(bool*sr,bool*s1,bool*s2,intn);

intsubset(bool*sr,bool*s1,bool*s2,intn);

intmulset(bool*sr,bool*s1,bool*s2,intn);

说明:

使用数组实现集合的集合运算

算法描述:

在原算法基础上我进行了一下修改

1.增加单词:

保留字ELSE

2.运算符+=,-=,++,――

3.增加条件语句的ELSE子句

为此添加了ELSESYM,为了实现如上要求的扩充,必须再正确地添加JIAJIA,JIANJIAN,JIADENG,JIANDENG等几个个SYMBOL,具体必须包括以下三个方面的修改或添加:

在枚举变量SYMBOL的定义内添加JIAJIA,JIANJIAN,JIADENG,JIANDENG和ELSESYM;然后在在源程序文件中加上保留字ELSE,为了识别例如A:

=++A之类的功能,还需在因子开始符号中加入JIAJIA,JIANJIAN。

这样,我们就正确地加入了五个将用来作为扩充语言功能的SYM。

为了实现功能首先需要在词法分析中加入识别单词功能

增加JIAJIA(++)、JIADENG(+=)、JIANJIAN(——)、JIANDENG(—=)的词法分析,代码修改如下:

if(ch=='+')

{

getchdo;

if(ch=='=')

{

sym=jiadeng;

getchdo;

}

else

{

if(ch=='+')

{

sym=jiajia;

getchdo;

}

else

{

sym=plus;

}

}

}

else

{

if(ch=='-')

{

getchdo;

if(ch=='=')

{

sym=jiandeng;

getchdo;

}

else

{

if(ch=='-')

{

sym=jianjian;

getchdo;

}

else

{

sym=minus;

}

}

}

这样,我们就完成了对词法分析器的修改。

然后JIAJIA.,JIANJIAN操作的语法图有如下两个:

语句

因子

根据以上语法图,我们只要对语句处理程序和因子处理程序进行修改添加,即可实现增加INC和DEC操作,首先对语句处理程序进行如下修改:

语句中形如++A,——A修改:

if(sym==jiajia||sym==jianjian)//++a,--a

{

if(sym==jiajia)

{

getsymdo;

if(sym==ident)

{

i=position(id,*ptx);

if(i==0)

{

error(11);

}

else

{

if(table[i].kind!

=variable)

{

error(12);

i=0;

}

else

{

gendo(lod,lev-table[i].level,table[i].adr);//生成指令,将变量放到栈顶

gendo(lit,0,1);//生成指令,把常量取到运行栈顶

gendo(opr,0,2);//生成指令,栈顶加次栈顶

gendo(sto,lev-table[i].level,table[i].adr);//生成指令,结果写回变量地址单元

getsymdo;

}

}

}

}

else//--a

{

getsymdo;

if(sym==ident)

{

i=position(id,*ptx);

if(i==0)

{

error(11);

}

else

{

if(table[i].kind!

=variable)

{

error(12);

i=0;

}

else

{

gendo(lod,lev-table[i].level,table[i].adr);//生成指令,取变量放大栈顶

gendo(lit,0,1);//生成指令,取常数到栈顶

gendo(opr,0,3);//生成指令,栈顶减次栈顶

gendo(sto,lev-table[i].level,table[i].adr);//生成指令,结果写回变量地址单元

getsymdo;

}

}

}

}

随后修改如A++,A——

if(sym==jiajia||sym==jianjian)//a++,a--

{

addop=sym;

gendo(lod,lev-table[i].level,table[i].adr);//把变量的值压入栈

gendo(lit,0,1);

if(addop==jiajia)

{

gendo(opr,0,2);

gendo(sto,lev-table[i].level,table[i].adr);

}

else

{

gendo(opr,0,3);

gendo(sto,lev-table[i].level,table[i].adr);

}

getsymdo;

}

这样,对JIAJIA和JIANJIAN操作就扩充完成。

扩充+=和-=操作

这两个操作都是一种对变量进行赋值的形式,其合法的语句形式的语法图如下所示:

根据图3,在已经处理部分的基础上,添加对+=运算和-=运算的扩充,相关代码添加如下:

if(sym==jiadeng||sym==jiandeng)

{

addop=sym;

getsymdo;

gendo(lod,lev-table[i].level,table[i].adr);/*把变量的值压入栈*/

factordo(nxtlev,ptx,lev);

if(addop==jiadeng)

{

gendo(opr,0,2);/*生成加法指令*/

}

else

{

gendo(opr,0,3);/*生成减法指令*/

}

}

这样就完成了对+=运算和-=运算的添加。

增加条件语句else

该语句的语法图如

只要在STATEMENT修改如下代码:

if(sym==elsesym){

cx2=cx;

gendo(jmp,0,0);

code[cx1].a=cx;

getsymdo;

statementdo(nxtlev,ptx,lev);/*处理else后的语句*/

code[cx2].a=cx;

}

else

{

code[cx1].a=cx;

}

这样ELSE语句扩充完毕

为了显示错误更清晰我增加了显示错误原因的语句

具体代码在ERROR中实现

switch(n)

{

case1:

printf("常数说明中的“=”写成了“:

=”。

\n");

break;

case2:

printf("常数说明中的“=”后应是数字。

\n");

break;

case3:

printf("常数说明中的标识符后应是“=”。

\n");

break;

case4:

printf("const,var,procedure后应为标识符。

\n");

break;

case5:

printf("漏掉了“,”或“;”。

\n");

break;

case6:

printf("过程说明后的符号不正确(应是语句开始符,或过程定义符)。

\n");

break;

case7:

printf("应是语句开始符。

\n");

break;

case8:

printf("程序体内语句部分的后跟符号不正确。

\n");

break;

case9:

printf("程序结尾丢了句号“.”。

\n");

break;

case10:

printf("语句之间漏了“;”。

\n");

break;

case11:

printf("标志符未说明。

\n");

break;

case12:

printf("在“:

=”或“+=”或“-=”左部标志符属性应是变量。

\n");

break;

case13:

printf("缺少“:

=”或“+=”或“-=”。

\n");

break;

case14:

printf("call后应为标志符。

\n");

break;

case15:

printf("call后标志符属性应为过程。

\n");

break;

case16:

printf("条件语句中丢了“then”。

\n");

break;

case17:

printf("丢了“end”或“;”。

\n");

break;

case18:

printf("while型循环语句中丢了“do”。

\n");

break;

case19:

printf("语句后的符号不正确。

\n");

break;

case20:

printf("应为关系运算符。

\n");

break;

case21:

printf("表达式内标志符属性不能是过程。

\n");

break;

case22:

printf("表达式内中漏掉右括号“)”。

\n");

break;

case23:

printf("因子后的非法符号。

\n");

break;

case24:

printf("表达式的开始符不能是此符号。

\n");

break;

case30:

printf("number的最大位数为。

\n");

break;

case31:

printf("数越界。

\n");

break;

case32:

printf("最大的嵌套层数不能大于层。

\n");

break;

case33:

printf("格式错误,应是右括号。

\n");

break;

case34:

printf("格式错误,应是左括号。

\n");

break;

case35:

printf("read()中的变量名没有声明过。

\n");

break;

case36:

printf("“;”写成了“,”。

\n");

break;

}

这样代码修改完毕

我还改进了一个形如vara;b;或者consta;b;语句错误

添加错误编号36(“;”写成了“,”)。

if(sym==semicolon)

{

getsymdo

if(sym==ident)

{

error(36);

}

改变了声明符号时无法重复或无法改变声明顺序。

具体方法是讲源代码中

memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);

nxtlev[ident]=true;

nxtlev[period]=true;

testdo(nxtlev,declbegsys,7);

增加VARSYM与CONSTSYM后跟符号集

修改后变为

memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);

nxtlev[ident]=true;

nxtlev[period]=true;

nxtlev[constsym]=true;

nxtlev[varsym]=true;

testdo(nxtlev,declbegsys,7);

最后为了实行人性化操作我增加了编译程序循环执行的方法

具体方法是在主函数中加入

while

(1)

{//保证用户连续运行程序

..............

..............

..............

getchar();//退出程序的字符标号

printf("\n退出程序请按q键,继续运行请按其它键!

\t");

scanf("%c",&ch);

if(ch=='q')

break;//退出程序

else

system("cls");//清屏*/

}

调试情况:

形如vara;b;或者consta;b;语句错误

文件名为test1.txt

vara;

constd=2;

varb;

constc=1;

begin

a:

=d;

b:

=c;

write(a);

write(b)

end.

改动前程序执行情况

改动后程序执行情况

我还改进了一个形如vara;b;或者consta;b;语句错误

添加错误编号36(“;”写成了“,”)。

文件名为test2.txt

vara;b;

constc=1;b:

=2;

begin

a:

=c;

write(a)

end.

程序执行情况:

调试ifthenelse

文件名为else.txt

vara,b;

begin

read(a);

ifa<0

then

b:

=-1

else

b:

=1;

write(a);

write(b)

end.

运行结果:

调试++,――

文件名为++.txt

vara,b,c,d;

begin

a:

=1;

b:

=2;

c:

=9;

c++;

c--;

--c;

++c;

a+=--c;

a-=c--;

d:

=(++b)+c;

write(b);

write(c);

write(d);

write(a)

end.

运行结果:

 

设计技巧:

万事无捷径,只有一步一步脚踏实地。

只有相对的技巧,就是对原程序的错误编号,标记。

对改动的错误利用编译程序的断点功能检查错误。

书写程序的时候,首先画语法图列出框架,在根据框架书写程序。

心得体会:

这次改进还有不完善的地方,例如检查形为CONSTA=1;B=2;时的错误的时候,如果把语句放入BEGIN语句体内会出现新的错误。

所以完善此编译程序还得考虑的更加仔细

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2