广工编译原理课程设计报告Word文档格式.docx

上传人:b****1 文档编号:3469428 上传时间:2023-05-01 格式:DOCX 页数:19 大小:78.39KB
下载 相关 举报
广工编译原理课程设计报告Word文档格式.docx_第1页
第1页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第2页
第2页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第3页
第3页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第4页
第4页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第5页
第5页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第6页
第6页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第7页
第7页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第8页
第8页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第9页
第9页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第10页
第10页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第11页
第11页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第12页
第12页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第13页
第13页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第14页
第14页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第15页
第15页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第16页
第16页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第17页
第17页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第18页
第18页 / 共19页
广工编译原理课程设计报告Word文档格式.docx_第19页
第19页 / 共19页
亲,该文档总共19页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

广工编译原理课程设计报告Word文档格式.docx

《广工编译原理课程设计报告Word文档格式.docx》由会员分享,可在线阅读,更多相关《广工编译原理课程设计报告Word文档格式.docx(19页珍藏版)》请在冰点文库上搜索。

广工编译原理课程设计报告Word文档格式.docx

(2)教学型编译程序:

PL/0(C语言版)

四、设计方案

Error()出错处理,打印出错位置和错误编码

GetCh()漏掉空格,读取一个字符

GetSym()词法分析,读取一个单词

GEN()目标代码生成过程,本过程用于把生成的目标代码写入目标代码数组,供后面的解释器解释执行

TEST()测试当前单词是否合法过程test

ENTER()登陆符号表过程enter

POSITION()在符号表中查找指定符号所在位置的函数position,如果找不到就返回0

VARDECLARATION()变量声明

LISTCODE()列出目标代码清单;

FACTOR()因子处理过程factor

TERM()项处理过程term;

EXPRESSION()表达式处理过程

CONDITION()条件处理过程

STATEMENT()语句处理过程

BLOCK()语法分析过程

BASE()通过静态链求出数据区基地址的函数,

INTERPRET()对目标代码解释运行过程

五、主要成分描述

1.符号表

在编译程序中符号表用来存放语言程序中出现的有关标识符的属性信息,符号表中所登记的信息在编译的不同阶段都要用到。

在语义分析中,符号表所登记的内容将用于语义检查(如检查一个名字的使用和原先的说明是否一致)和产生中间代码。

在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。

对一个多遍扫描的编译程序,不同遍所用的符号表也往往各有不同。

因为每遍所关心的信息各有差异。

一张符号表的每一项(或称入口才包含两大栏(或称区段、字域),即名字栏(NAME)信息栏(INFORMATION)

 

信息栏包含许多子栏和标志位,用来记录相应名字和种种不同属性,由于查填符号表一般是通过匹配名字来寮现的,因此,名字栏也称主栏。

主栏的内容称为关键字(keyword)。

2.运行时存储组织和管理

由于编译时目标程序运行的数据空间大小已经规定,所以存储组织属于静态存储。

源程序的标识符存放在TABLE表中,目标代码存放在CODE中,S是由解释程序定义的一维整型数组,是程序运行时的数据存储空间。

解释程序还定义了4个寄存器:

1)P:

程序地址寄存器:

指向下一条要执行的目标程序的地址(相当目标程序CODE数组的下标)。

2)I:

指令寄存器:

存放着当前正在解释的下一条目标指令。

3)T:

栈顶寄存器:

由于每个过程当它被运行时,给它分配的数据空间(下边称数据段)包括静态部分和动态部分,对于动态部分,要注意的是,栈顶寄存器指出了当前栈中最新分配的单元。

4)B:

基址寄存器:

指向每个过程被调用时,在数据区S中给它分配的数据段的起始地址,也称基地址

3.中间代码表示

对PL/0编译程序的目标代码的指令格式描述如下:

fla

其中f代表功能码,l表示层次差,a的含意对不同的指令有所区别,见下面对每条指令的解释说明:

lit0a

将常数值取到栈顶,a为常数值

Lodla

将变量值取到栈顶,a为偏移量,l为层差

Stola

将栈顶内容送入某变量单元中,a为偏移量,l为层差

Calla

调用过程,a为过程地址,l为层差

Int0a

在运行栈中为被调用的过程开辟a个单元的数据区

jmp0a

无条件跳转至a地址

Jpc0a

条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行

opr00

过程调用结束后,返回调用点并退栈

opr01

栈顶元素取反

opr02

次栈顶与栈顶相加,退两个栈元素,结果值进栈

opr03

次栈顶减去栈顶,退两个栈元素,结果值进栈

opr04

次栈顶乘以栈顶,退两个栈元素,结果值进栈

opr05

次栈顶除以栈顶,退两个栈元素,结果值进栈

opr06

栈顶元素的奇偶判断,结果值在栈顶

opr07

opr08

次栈顶与栈顶是否相等,退两个栈元素,结果值进栈

opr09

次栈顶与栈顶是否不等,退两个栈元素,结果值进栈

opr010

次栈顶是否小于栈顶,退两个栈元素,结果值进栈

opr011

次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈

opr012

次栈顶是否大于栈顶,退两个栈元素,结果值进栈

opr013

次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈

opr014

栈顶值输出至屏幕

opr015

屏幕输出换行

opr016

从命令行读入一个输入置于栈顶

4.语法分析方法

自顶向下的语法分析:

<

程序>

<

分程序>

.

变量说明部分>

<

VAR<

标识符>

复合语句>

ABEGIN<

END

读语句>

READ(<

A

六、测试用例

vara,b,c,d;

结果:

输入3

begin

read(a);

b:

=a;

c:

=b--;

d:

=(b+2)/++c;

ifa=3

then

begin

//a=3

write(a);

//b=2

write(b);

//c=4

write(c);

//d=1

write(d);

end

else结果:

输入1

//test

//百慕大

c:

=4;

c+=-4;

fora:

=1to100do

c++;

a-=1;

end.

七、开发过程和完成情况

1)增加保留字ELSE,FOR,TO,DOWN,RETURN.

增加运算符+=,-=,++,--

首先,在pl0.h中添加保留字(黑体字部分)

enumsymbol{//此处需要修改

nul,ident,number,plus,minus,

times,slash,oddsym,eql,neq,

lss,leq,gtr,geq,lparen,

rparen,comma,semicolon,period,becomes,

beginsym,endsym,ifsym,thensym,whilesym,

writesym,readsym,dosym,callsym,constsym,

varsym,procsym,elsesym,forsym,tosym,

downtosym,returnsym,plusplus,minusminus,

plusequal,minusequal,

};

#definesymnum41//改为相应的个数

然后:

由于是二分查找,在如下位置按顺序排关键字

/*设置保留字名字,按照字母顺序,便于折半查找*/

strcpy(&

(word[0][0]),"

begin"

);

(word[1][0]),"

call"

(word[2][0]),"

const"

(word[3][0]),"

do"

(word[4][0]),"

downto"

(word[5][0]),"

else"

(word[6][0]),"

end"

(word[7][0]),"

for"

(word[8][0]),"

if"

(word[9][0]),"

odd"

(word[10][0]),"

procedure"

(word[11][0]),"

read"

(word[12][0]),"

return"

(word[13][0]),"

then"

(word[14][0]),"

to"

(word[15][0]),"

var"

(word[16][0]),"

while"

(word[17][0]),"

write"

/*设置保留字符号*/

wsym[0]=beginsym;

wsym[1]=callsym;

wsym[2]=constsym;

wsym[3]=dosym;

wsym[4]=downtosym;

wsym[5]=elsesym;

wsym[6]=endsym;

wsym[7]=forsym;

wsym[8]=ifsym;

wsym[9]=oddsym;

wsym[10]=procsym;

wsym[11]=readsym;

wsym[12]=returnsym;

wsym[13]=thensym;

wsym[14]=tosym;

wsym[15]=varsym;

wsym[16]=whilesym;

wsym[17]=writesym;

2)修改单词:

首先,将这句ssym['

#'

]=neq;

删除

然后,在getsym()函数中,把分析到的<

定义为不等号

if(ch=='

'

)/*检测小于或小于等于符号*/

{

getchdo;

='

){

sym=leq;

getchdo;

}elseif(ch=='

){

sym=neq;

getchdo;

}else{

sym=lss;

}

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

在statement函数中改为

if(sym==ifsym)/*准备按照if语句处理*/

{

getsymdo;

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

nxtlev[thensym]=true;

nxtlev[dosym]=true;

/*后跟符号为then或do*/

conditiondo(nxtlev,ptx,lev);

/*调用条件处理(逻辑运算)函数*/

if(sym==thensym){getsymdo;

}

else{error(16);

/*缺少then*/}

cx1=cx;

/*保存当前指令地址*/

gendo(jpc,0,0);

/*生成条件跳转指令,跳转地址暂写*/

statementdo(fsys,ptx,lev);

/*处理then后的语句*/

//addkeywordelse

if(sym==elsesym){

getsymdo;

intcx2=cx;

gendo(jmp,0,0);

code[cx1].a=cx;

statementdo(fsys,ptx,lev);

code[cx2].a=cx;

}else{code[cx1].a=cx;

/*经statement处理后,cx为then后语句执行

完的位置,它正是前面未定的跳转地址*/

}

4)添加++,--,+=,-=

首先,在getsym函数中添加

+'

){///pluspluspluseqal

if(ch=='

sym=plusplus;

getchdo;

sym=plusequal;

}else{sym=plus;

}elseif(ch=='

-'

){//minusminusminusequal

sym=minusminus;

sym=minusequal;

然后,在statement函数中,修改

switch(sym){

casebecomes:

expressiondo(nxtlev,ptx,lev);

break;

//++

caseplusplus:

gendo(lit,0,1);

gendo(opr,0,2);

//+=

caseplusequal:

//--

caseminusminus:

gendo(opr,0,3);

//-=

caseminusequal:

default:

error(13);

再次,由于++,--运算要用到在表达式处理中,而且又有前加,前减,后加后减之类的,所以因子函数factor中也要有相应的处理。

switch(table[i].kind)

caseconstant:

/*名字为常量*/

gendo(lit,0,table[i].val);

/*直接把常量的值入栈*/

break;

casevariable:

/*名字为变量*/

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

/*找到变量地址并将其值入栈*/

//加加减减

if(forhead){

gen(lit,0,1);

if(temp==plusplus)gen(opr,0,2);

elsegen(opr,0,3);

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

gen(lod,lev-table[i].level,table[i].adr);

forhead=false;

end=true;

}else{forhead=true;

caseprocedur:

/*名字为过程*/

error(21);

/*不能为过程*/

//增加加加与减减运算(后加后减)

if(sym==plusplus||sym==minusminus){

if(end)error(2000);

if(forhead){

gen(lit,0,1);

if(sym==plusplus)gen(opr,0,2);

elsegen(opr,0,3);

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

gen(lod,lev-table[i].level,table[i].adr);

if(sym==plusplus)gen(opr,0,3);

elsegen(opr,0,2);

end=false;

getsym();

}else{

temp=sym;

forhead=true;

5)添加for语句

在statement函数中修改

if(sym==forsym){

getsymdo;

if(sym==ident){

i=position(id,*ptx);

if(i==0)error(11);

//变量没有说明

else{

if(table[i].kind!

=variable)error(1000);

getsym();

if(sym!

=becomes)error(1000);

else{

getsym();

expression(nxtlev,ptx,lev);

if(sym==tosym||sym==downtosym){

symboltmp=sym;

cx1=cx;

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

gen(lod,lev-table[i].level,table[i].adr);

getsym();

expression(nxtlev,ptx,lev);

if(tmp==tosym)gen(opr,0,13);

elsegen(opr,0,11);

cx2=cx;

gen(jpc,0,0);

if(sym==dosym){

getsym();

statement(fsys,ptx,lev);

gen(lod,lev-table[i].level,table[i].adr);

gen(lit,0,1);

if(tmp==tosym)gen(opr,0,2);

elsegen(opr,0,3);

gen(jmp,0,cx1);

code[cx2].a=cx;

}elseerror(1000);

}elseerror(1000);

}

}elseerror(1000);

6)添加单行注释

对于单行注释,在getch函数中,将以//开头的文字去掉即可以实现单行注释的功能。

//增加单行注释

/'

if(EOF!

=fscanf(fin,"

%c"

&

ch)){

while(EOF!

ch)&

&

ch!

\n'

if(EOF==fscanf(fin,"

line[ll]=0;

break;

}else{

printf("

'

fprintf(fa1,"

line[ll]='

ll++;

printf("

注释出错!

!

"

return-1;

八、学习体会

这次编译原理的实验和课程设计,首先要求我们要对PL0的源程序和使用的编译方法要有一定的理解,如果没有这一方面的基础,我们根本就没法下手。

经过自己认真地阅读程序以及在同学和老师的热情帮助下,终于对PL0程序有了不少的理解,终于找到了下手的方法。

当然,在改写程序的过程中,由于自己粗心导致一些不必要的麻烦,这也使我体会到细心,认真的重要性。

经过这次实验,我进一步了解程序编译过程的基本原理和基本实现方法,加深了对课本知识的理解,我更深地认识到了语法分析,词法分析,语义分析等等并不是相对独立的,而是相互联系,互成一体的。

只有理解了各部分的作用才到更好地完成实验。

在理解的PCODE的指令格式时,自己犯了一个很不应该犯的错误。

比如课本上提到,“将栈顶和次栈顶内容做算术运算,结果放到次栈顶”对这一句话,我原以为,比如说减法,是栈顶的内容减去次栈顶的内容,其实不然,而是次栈顶的内容减去栈顶的内容。

由于这一点误解,造成了很多的郁闷,不过后来经过断点调试和不断的跟踪,终于知道了自己的误解。

这使我感到了,正确理解的重要性,同时,也使我知道了调试能力的重要性。

总之,这次实验,对自己的动手能力有了更好的训练,也使我对编译原理有了更深的认识,真是受益匪浅。

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

当前位置:首页 > 幼儿教育 > 育儿理论经验

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

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