广工编译原理实验报告.docx

上传人:b****4 文档编号:3683840 上传时间:2022-11-24 格式:DOCX 页数:25 大小:284.23KB
下载 相关 举报
广工编译原理实验报告.docx_第1页
第1页 / 共25页
广工编译原理实验报告.docx_第2页
第2页 / 共25页
广工编译原理实验报告.docx_第3页
第3页 / 共25页
广工编译原理实验报告.docx_第4页
第4页 / 共25页
广工编译原理实验报告.docx_第5页
第5页 / 共25页
点击查看更多>>
下载资源
资源描述

广工编译原理实验报告.docx

《广工编译原理实验报告.docx》由会员分享,可在线阅读,更多相关《广工编译原理实验报告.docx(25页珍藏版)》请在冰豆网上搜索。

广工编译原理实验报告.docx

广工编译原理实验报告

<<编译原理>>

课实验报告

项目名称PL/0编译器

学院____计算机学院_______

专业__

年级班别________

学号_

学生__________

辅导教师_______

成绩______________

 

一、课实验的容------------------------------------------4

二、实验修改部分--------------------------------------------4

三、概述-------------------------------------------------11

四、结构设计说明-------------------------------------------11

五、各功能模块描述-----------------------------------------14

六、主要成份描述------------------------------------------14

七、测试用例----------------------------------------------16

八、开发过程和完成情况--------------------------------------21

 

一、课实验的容

对PL/0作以下修改扩充:

(1)增加单词:

保留字ELSE,FOR,STEP,RETURN

运算符+=,-=,++,--,&,|,~

(2)修改单词:

不等号#改为<>

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

二、实验修改部分:

1、增加四个保留字和七个运算符,共十一个单词。

修改部分:

#definesymnum43//保留字从32增加到43个

2、增加五个保留字:

ELSE,FOR,STEP,RETURN

头文件pl0.h

enumsymbol{新增加单词:

elsesym,forsym,stepsym,returnsym,pluseq/*+=*/,plusone/*++*/,plus/*+*/,minuseq/*-=*/,minusone/*--*/,minus/*-*/,and,or,not}

头文件pl0.h

#definenorw24//关键字从13增加到24个

PL0.cpp

init();

新增加:

(增加后数组的容要再次根据字母顺序重新排列)

strcpy(&(word[0][0]),"begin");

strcpy(&(word[1][0]),"call");

strcpy(&(word[2][0]),"const");

strcpy(&(word[3][0]),"do");

strcpy(&(word[4][0]),"else");/*增加单词:

保留字else*/

strcpy(&(word[5][0]),"end");

strcpy(&(word[6][0]),"for");/*增加单词:

保留字for*/

strcpy(&(word[7][0]),"if");

strcpy(&(word[8][0]),"odd");

strcpy(&(word[9][0]),"procedure");

strcpy(&(word[10][0]),"read");

strcpy(&(word[11][0]),"return");/*增加单词:

保留字return*/

strcpy(&(word[12][0]),"step");/*增加单词:

保留字step*/

strcpy(&(word[13][0]),"then");

strcpy(&(word[14][0]),"while");

strcpy(&(word[15][0]),"write");

wsym[0]=beginsym;

wsym[1]=callsym;

wsym[2]=constsym;

wsym[3]=dosym;

wsym[4]=elsesym;/*else*/

wsym[5]=endsym;

wsym[6]=forsym;/*for*/

wsym[7]=ifsym;

wsym[8]=oddsym;

wsym[9]=procsym;

wsym[10]=readsym;

wsym[11]=returnsym;/*return*/

wsym[12]=stepsym;/*step*/

wsym[13]=thensym;

wsym[14]=whilesym;

wsym[15]=writesym;

3、增加四个运算符:

+=,-=,++,--,∧,∨,┓

●PL0.cpp

getsym();

增加对+,-,++,--,+=,-=的识别;

Statement();

增加对+,-,++,--,-=的语句的处理;

Init()中改动:

ssym[‘&’]=and;

ssym[‘|’]=or;

ssym[‘~’]=not;

facbegsys[plusone]=true;//添加前自加运算

facbegsys[minusone]=true;//添加前自减运算

Getsym()增加的容:

intgetsym()

{

inti,j,k;

while(ch==''||ch==10||ch==9)

{

getchdo;

}

if(ch>='a'&&ch<='z')

{

k=0;

do{

if(k

{

a[k]=ch;

k++;

}

getchdo;

}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');

a[k]=0;

strcpy(id,a);

i=0;

j=norw-1;

do{

k=(i+j)/2;

if(strcmp(id,word[k])<=0)

{

j=k-1;

}

if(strcmp(id,word[k])>=0)

{

i=k+1;

}

}while(i<=j);

if(i-1>j)

{

sym=wsym[k];

}

else

{

sym=ident;

}

}

else

{

if(ch>='0'&&ch<='9')

{

k=0;

num=0;

sym=number;

do{

num=10*num+ch-'0';

k++;

getchdo;

}while(ch>='0'&&ch<='9');/*获取数字的值*/

k--;

if(k>nmax)

{

error(30);

}

}

else

{

if(ch==':

')/*检测赋值符号*/

{

getchdo;

if(ch=='=')

{

sym=bees;

getchdo;

}

else

{

sym=nul;/*不能识别的符号*/

}

}

else

{

if(ch=='<')/*检测小于或小于等于符号*/

{

getchdo;

if(ch=='=')

{

sym=leq;

getchdo;

}

else

{

sym=lss;

}

}

elseif(ch=='>')/*检测大于或大于等于符号*/

{

getchdo;

if(ch=='=')

{

sym=geq;

getchdo;

}

else

{

sym=gtr;

}

}

/*这里之间为添加的容*/

elseif(ch=='+'){/*检测+,+=,++符号*/

getchdo;

if(ch=='='){

sym=pluseq;

getchdo;

}elseif(ch=='+'){

sym=plusone;

getchdo;

}else{

sym=plus;

}

}elseif(ch=='-'){/*检测-,-=,--符号*/

getchdo;

if(ch=='=')

{

sym=minuseq;

getchdo;

}

elseif(ch=='-')

{

sym=minusone;

getchdo;

}

else

{

sym=minus;

}

}

/*这里之间为添加的容*/

else{

sym=ssym[ch];/*当符号不满足上述条件时,全部按照单字符号处理*/

//getchdo;

//richard

if(sym!

=period)

{

getchdo;

}

//endrichard

}

}

}

}

return0;

}

Statement()增加的容:

(将本来“if(sym==bees)……”部分的容修改为处理++,+=,--,-=),并在Statement()中定义变量intsym2;

if(sym==bees||sym==pluseq||sym==minuseq||

sym==plusone||sym==minusone)

{

sym2=sym;

getsymdo;

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

}

else

{

error(13);

}

if(sym2==plusone||sym2==minusone)/*准备按照a++、a--语句

处理,与read类似*/

{

if(i!

=0)

{

if(sym2==plusone)

{

gendo(lit,0,1);

gendo(opr,0,2);

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

 

}

if(sym2==minusone)

{

gendo(lit,0,1);

gendo(opr,0,3);

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

}

}

}

else

{

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

expressiondo(nxtlev,ptx,lev);

if(i!

=0)

{

if(sym2==bees)

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

if(sym2==pluseq)

{

gendo(opr,0,2);

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

}

if(sym2==minuseq)

{

gendo(opr,0,3);

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

}

}

}//else

}

}

}

 

4、修改单词:

不等号#改为<>

●PL0.cpp

init();

移除:

ssym['#']=neq;

在getsym()里增加对<>的识别(在<或<=基础上修改)。

下面为在<基础上修改,注意在if(ch==’<’)中修改,不包括elseif(ch=='>')那部分:

if(ch=='<')/*检测小于或小于等于符号*/

{

getchdo;

if(ch=='=')

{

sym=leq;

getchdo;

}

/*在之间添加*/

elseif(ch=='>')//addneq

{

sym=neq;

getchdo;

}

/*在之间添加*/

else

{

sym=lss;

}

}

5、增加条件语句的ELSE子句

●PL0.cpp

在statement()里的“if...then”语句处理的基础上添加对else子句的处理,使之能处理if……then……else……的语句。

else

{

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);/*生成条件跳转指

令,跳转地址暂写0*/

/*这里之间开始添加*/memcpy(nxtlev,fsys,sizeof(bool)*symnum);

//添加后跟符号

nxtlev[elsesym]=true;

statementdo(nxtlev,ptx,lev);/*处理

then后的语句*/

code[cx1].a=cx;/*经statement处理后

,cx为then后语句执行完的位置,它正是前面未定的跳转地址*/

if(sym==elsesym)

{

cx2=cx;

getsymdo;

gendo(jmp,0,0);

code[cx1].a=cx;

statementdo(fsys,ptx,lev);

code[cx2].a=cx;

}/*这里之间开始添加*/

}

else

{

if(sym==beginsym)/*准备按照复合语句处理*/

{

getsymdo;

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

nxtlev[semicolon]=true;

nxtlev[endsym]=true;/*后跟符号为分号或

end*/

/*循环调用语句处理函数,直到下一个符号不

是语句开始符号或收到end*/

statementdo(nxtlev,ptx,lev);

while(inset(sym,statbegsys)||

sym==semicolon)

{

if(sym==semicolon)

{

getsymdo;

}

else

{

error(10);/*缺少分号*/

}

statementdo(nxtlev,ptx,lev);

}

if(sym==endsym)

{

getsymdo;

}

else

{

error(17);/*缺少end或分

号*/

}

}

写出相关文法:

G(S):

S→ifSelseS|ifS|a

Else语法图:

三、概述

源语言:

PL/0语言

目标语言:

假想栈式计算机的汇编语言

实现工具:

VC++6.0运行平台:

Windows7

四、结构设计说明

1、PL/0编译程序的结构图如下:

由于PL/0编译程序采用一趟扫描方法,所以语法语义分析过程block是整个编译程序的核心。

下面给出编译程序的总体流程图,以弄清block过程在整个编译程序中的作用。

在流程图中可以看出,主程序置初值后先调整用读单词过程getsym取一个单词,然后再调用语法分析过程block,直到遇源程序的结束符“.”为止。

五、各功能模块描述

GetSym():

词法分析,从源文件中读出若干有效字符,组成token串,识别它的类型为保留字/标识符/数字或其它符号。

GEN():

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

TEST():

测试当前单词是否合法

ENTER():

在名字表中加入一项

POSITION():

查找名字的位置,找到则返回名字表中的位置,否则返回0

ConstDeclaration():

常量声明处理

VarDeclaration():

变量声明处理

ListCode():

输出目标代码清单

FACTOR():

因子处理过程

TERM():

项处理过程

EXPRESSION():

表达式处理过程

CONDITION():

条件处理过程

STATEMENT():

语句处理过程

Block():

编译程序主体,参数:

lev:

这一次语法分析所在的层次,tx:

符号表指针,

fsys:

用于出错恢复的单词集合

BASE():

通过过程基址求上一层过程的基址

Interpret():

解释程序,PL/0编译器产生的类PCODE目标代码解释运行过程

六、主要成份描述

1.符号表

在编译程序中符号表用来存放语言程序中出现的有关标识符的属性信息,这些信息集中反映了标识符的语义特征属性.符号表的主要功能如下:

、收集符号属性

、上下文语义合法性检查的依据

、作为目标代码生成阶段地址分配的依据.

、符号表的数据结构:

structtablestruct

{

charname[al];/*名字*/

enumobjectkind;/*类型:

const,var,arrayorprocedure*/

intval;/*数值,仅const使用*/

intlevel;/*所处层,仅const不使用*/

intadr;/*地址,仅const不使用*/

intsize;/*需要分配的数据区空间,仅procedure使用*/

};

structtablestructtable[txmax];/*名字表*/

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

当源程序经过语法分析,如果未发现错误时,由编译程序调用解释程序,对存放在CODE中的代码CODE[0]开始进行解释执行.当废弃结束后,记录源程序中标识符的TABLE表已没有作用.因此存储区只需以数组CODE存主的只读目标程序和运行机制时的数据区S,S是由解释程序定义的一维整数型数组.解释执行时的数据空间S为栈式计算机的在座空间,遵循后进先出规则,对每个过程(包括主程序)当调用时,才分配数据空间,退出过程进,则所分配原则的数据空间被释放.

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

1、指令寄存器.存放当前正在解释的一条目标指令2、程序地址寄存器.指向下一条要执行的目标程序的地址3、栈顶寄存器.4、基址寄存器.指向每个过程被调用时,在数据区S中给它分配原则的数据段起始地址,也称基地址.

为了实现过程被调用时给它分配数据段,过程运行结束后释放数据段以及嵌套过程之间结标志符引用的问题,当过程被调用时,在栈顶分配三个联系单元,这三个联系单元存放的容分别为:

SL静态链,动态链DL,RA返回地址。

3.语法分析方法

语法分析的任务是识别由词法分析给出的单词符号序列在结构上是否符合给定的文法规则.PL/0编译程序的语法分析采用了自顶向下的递归子程序法.粗略地说:

就是对应每个非终结符语法单元,编一个独立的处理过程(或子程序).语法分析研究从读入第一个单词开始由非终结符’程序即开始符出发,沿语法描述图箭头所指出的方向进行分析.当遇到非终结符时,则调用相应的处理过程,从语法描述图看也就进入了一个语法单元,再沿当前所进入的语法描述图的箭头方向进行分析,当遇到描述图中是终结符时,则判断当前读入的单词是否与图中的终结符相匹配,若匹配,则执行相应的语义程序(就是翻译程序).再读取下一个单词继续分析.遇到分支点时将当前的单词与分支点上的多个终结符逐个相比较,若都不匹配时可能是进入下一非终结符语法单位或是出错.

如果一个PL/0语言程序的单词序列在整修语法分析中,都能逐个得到匹配,直到程序结束’.’,这时就说所输入的程序是正确的.对于正确的语法分析做相应的语义翻译,最终得出目标程序.

4.中间代码表示

PL/0编译程序所产生的目标代码是一个假想栈式计算机的汇编语言,可称为类pcode指令代码,它不依赖任何实际计算机,其指令集极为简单,指令格式如下:

f

L

a

 

lit0a

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

Lodla

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

Stola

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

Cala

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

Int0a

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

jmp0a

无条件跳转至a地址

Jpc0a

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

opr00

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

opr01

栈顶元素取反

opr0

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

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1