编译原理课设报告最终版Word文件下载.docx
- 文档编号:16661212
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:22
- 大小:219.65KB
编译原理课设报告最终版Word文件下载.docx
《编译原理课设报告最终版Word文件下载.docx》由会员分享,可在线阅读,更多相关《编译原理课设报告最终版Word文件下载.docx(22页珍藏版)》请在冰豆网上搜索。
6增加一维数组
声明格式:
ident>
[<
/<
number>
:
];
赋值格式:
index>
]:
=<
表达式>
调用格式:
]
五、程序结构:
PL/0源程序
图1编译程序结构图2功能模块调用
1.功能模块作用如下:
Pl0.c:
主程序
Error:
出错处理,打印出错位置和错误编码
Getsym:
词法分析,读取一个单词
Getch:
漏掉空格,读取一个字符
Gen:
生成目标代码,并送入目标程序区
Test:
测试当前符号是否合法
Block:
分程序分析处理过程,词法语法分析
Enter:
登陆名字表
Position:
查找标识符在名字表中的位置
Constdeclaration:
常量定义处理
Vardeclaraction:
变量说明处理
Listcode:
列出目标代码清单
Statement:
语句处理
Expression:
表达式处理
Term:
项处理
Factor:
因子处理
Condition:
条件处理
Interpret:
对目标代码的解释执行程序
Base:
通过静态链求出数据取得基地址
增加两个功能:
Arraydeclaration:
数组声明处理
Arraycoef:
数组索引计算和“虚拟机”动作生成
2.保留字:
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,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,minusbk,
Lbrack,rbrack,colon
3.名字表中的类型
enumobject{constant,variable,procedure,arrays,}
共4个,扩充arrays,以便实现数组
4.虚拟机代码
enumfct{lit,opr,lod,sto,cal,inte,jmp,jpc,
lda,sta,}
共10个,补充的lda,sta用于数组操作
6.错误信息
(1)const,var,procedure后应为标识符
(2)常数说明中的=后应是数字
(3)常数说明中的标识符后应是=
(4)常数说明中的=写成了:
=
(5)漏掉了,或;
(6)过程说明后的符号不正确(应是语句开始符,或过程定义符)
(7)应是语句开始符
(8)标识符未说明
(9)程序结尾丢了句号。
(10)语句之间漏了;
(11)call后应为标识符
(12)赋值语句中,赋值号左部标识符属性应是变量
(13)赋值号左部标识符属性应是赋值号
(14)程序体内语句部分的后跟符不正确
(15)call后标识符属性应为过程
(16)条件语句中丢了then
(17)丢了end或;
(18)while循环语句中丢了do
(19)语句后的符号不正确
6.名字表结构
structtablestruct{
charname[al];
enumobjectkind;
intval;
intlevel;
intadr;
intsize;
//扩充名字表结构,增加一个data域保存数组的下界
intdata;
/*其他数据,对arrays来说是下界*/}
7.语法描述图:
图3程序语法描述图
图4分程序语法描述图
图5语句语法描述图
图6条件语法描述图
图7表达式语法描述图
图8项语法描述图
图9因子语法描述图
四、功能扩充
1.语句处理中加入for循环语句
if(sym==forsym){
getsymdo;
if(sym!
=lparen)error(34);
//没有左括号出错
else{
statementdo(nxtlev,ptx,lev);
//S1代码
if(sym!
=semicolon)error(10);
//语句缺少分号出错
else{
cx1=cx;
getsymdo;
conditiondo(nxtlev,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代码
code[cx3].a=cx5;
gendo(jmp,0,cx4);
code[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);
code[cx2].a=cx1;
}
elseerror(33);
//没有写until出错
}}
3.扩充++和—运算符
对于++和--运算符,扩充时要注意存在两个情况:
1)作为语句的时候;
2)作为表达式中的因子的时候。
注意:
扩充时增加因子开始符facbegsys[incs]=true和facbegsys[decs]=true。
扩充的语法描述见结构设计中的PL/0分程序和主要语句的语法描述中的描述图,详细代码见程序。
1)作为语句的时候,有四种情况:
a++;
a--;
++a;
--a;
文法的EBNF表示形式为:
<
自增自减语句>
标识符>
[++|--]|[++|--]<
文法分析过程大体如下图:
++a和—aa++和a—
生成中间代码对于a++;
++a;
和a--;
--a;
语句的处理如下:
先将变量的值取出放在栈顶,后将1入栈,后执行加法或减法运算oprv指令的2(加法)、3(减法),后将运算后的栈顶值存回变量。
a++;
和++a;
语句的中间代码:
lod03;
lit01;
opr02;
sto03;
a--;
和--a;
opr03;
2)作为因子的时候,有两种情况:
a++和a--作为因子,比如:
b:
=a++*a--;
语句++a和--a作为因子,比如:
=--a+2*++a;
语句
=...[++|--]<
|<
[++|--]...其中的...表示前后都可以有其他的项或因子生成中间代码
A对于因子++a和--a的中间代码生成处理和a++;
等语句处理一样;
B对于因子a++和a—的中间代码生成处理如下:
a++:
a--:
先将变量的值取出放在栈顶,后将1入栈,后执行加法或减法运算opr指令的2(加法)、3(减法),后将运算后的栈顶值存回变量,后将变量的值又取出来放入栈顶,后将1入栈,如果是a++就执行减法,如果是a—就执行加法,以实现先用a的值后再加1。
4.语句处理中加入if-then-else语句
在原有程序if(sym==then){...}后加入下列代码:
cx1=cx;
gendo(jpc,0,0);
statementdo(fsys,ptx,lev);
if(sym==elsesym){
cx2=cx;
gendo(jmp,0,0);
code[cx1].a=cx;
statementdo(fsys,ptx,lev);
code[cx2].a=cx;
}
else
5.修改不等号#为!
注释源程序中的ssym['
#'
]=neq语句,在getsym中加入下列代码:
//修改不等号为!
elseif(ch=='
!
'
){
getchdo;
if(ch=='
='
sym=neq;
getchdo;
elsesym=nul;
6.加入对一维数组的支持
本程序将数组看做变量的一种,由var声明函数调用array声明函数完成数组声明,这样就处加入文件输出的相关语句外,可以完全保留block函数和enter函数;
通过改写factor函数使数组因子包括了后缀的索引号,这样就可以调用通用的表达式函数赋值数组了。
为了方便完成数组相关功能,扩充了虚拟机处理代码。
数组的越界及非法调用错误处理没有完善,仅给出了错误代码。
在头文件pl0.h中:
/*定义两个全局变量,用来保存数组定义的下界和容量*/
staticintg_arrBase=0;
staticintg_arrSize=0;
/*虚拟机代码*///增加lda,sta专门由于数组的处理
//增加两个虚拟机指令lda,sta,分别用来从数组中取数和存到数组中
//数组元素的访问和存储,是将()后的当成表达式,先处理,得到元素的索引,放在栈顶
//最后根据数组的首地址,得到某个元素的地址
enumfct{...lda,sta}
structtablestruct{...intdata;
/*名字表中的类型*/
enumobject{...arrays//添加数组类型}
//数组声明处理,下界和上界允许已经定义过的常量标识符
intarraydeclaration(int*ptx,intlev,int*pdx);
//数组元素索引计算与“虚拟机”生成
intarraycoef(bool*fsys,int*ptx,intlev);
在源程序文件pl0.c中:
编写相关的arraydeclaration,arraycoef两个功能函数:
/*数组声明处理,下界和上界允许已经定义过的常量标识符*/
intarraydeclaration(int*ptx,intlev,int*pdx){
chararrId[al];
/*暂存数组标识名,避免被覆盖*/
intcstId;
/*常量标识符的位置*/
intarrBase=-1,arrTop=-1;
/*数组下界、上界的数值*/
getsymdo;
if(sym==lbrack){/*标识符之后是'
['
则识别为数组*/
strcpy(arrId,id);
/*检查下界*/
if(sym==ident){
if((cstId=position(id,(*ptx)))!
=0)
arrBase=(constant==table[cstId].kind)?
table[cstId].val:
-1;
elsearrBase=(sym==number)?
num:
if(-1==arrBase){
error(50);
return-1;
/*检查冒号*/
if(sym!
=colon){
error(50);
/*检查上界*/
arrTop=(constant==table[cstId].kind)?
elsearrTop=(number==sym)?
if(arrTop==-1){
//随意指定,因为原程序对错误号的规划极差!
/*检查'
]'
*/
if(sym!
=rbrack){
/*上下界是否符合条件检查*/
g_arrSize=arrTop-arrBase+1;
g_arrBase=arrBase;
if(g_arrSize<
=0){
/*恢复数组的标识符*/
strcpy(id,arrId);
return1;
return0;
/*数组元素索引计算与“虚拟机”生成*/
intarraycoef(bool*fsys,int*ptx,intlev){
boolnxtlev[symnum];
inti=position(id,*ptx);
if(sym==lbrack){/*索引是括号内的表达式*/
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[rbrack]=true;
expressiondo(nxtlev,ptx,lev);
if(sym==rbrack){
gendo(lit,0,table[i].data);
gendo(opr,0,3);
/*系数修正,减去下界的值*/
elseerror(22);
/*缺少右括号*/
elseerror(51);
/*数组访问错误*/
return-1;
修改函数enter,block,vardeclaration,factor及statement,使其具备处理数组的功能:
//将数组变量登陆名字表
voidenter(enumobjectk,int*ptx,intlev,int*pdx){
...
casearrays:
/*数组名,进行记录下界等*/
table[(*ptx)].level=lev;
table[(*ptx)].adr=(*pdx);
table[(*ptx)].data=g_arrBase;
table[(*ptx)].size=g_arrSize;
*pdx=(*pdx)+g_arrSize;
break;
...}
//输出数组名字表到控制台和文件fas.tmp
intblock(intlev,inttx,bool*fsys){
printf("
%darray%s"
i,table[i].name);
lev=%daddr=%dsize=%d\n"
table[i].level,table[i].adr,table[i].size);
fprintf(fas,"
//加入数组声明
intvardeclaration(int*ptx,intlev,int*pdx){
intarrayRet=-1;
if(sym==ident){
arrayRet=arraydeclaration(ptx,lev,pdx);
/*先判断数组*/
switch(arrayRet){
case1:
enter(arrays,ptx,lev,pdx);
//填写数组名
case0:
enter(variable,ptx,lev,pdx);
//填写名字表
//getsymdo;
default:
/*数组定义解析出错*/}
elseerror(4);
/*var后应是标识*/
/*当因子是数组型变量时,调用arraycodefdo将数组的索引入栈顶,之后按vatiabler变量操作*/
intfactor(bool*fsys,int*ptx,intlev){
switch(table[i].kind){
...
casearrays:
/*名字为数组名*/
arraycoefdo(fsys,ptx,lev);
gendo(lda,lev-table[i].level,table[i].adr);
/*找到变量地址并将其值入栈*/
...}...}
intstatement(bool*fsys,int*ptx,intlev){
if(sym==ident){
if((table[i].kind!
=variable)&
&
(table[i].kind!
=arrays)){
error(12);
i=0;
else{
enumfctfct1=sto;
switch(table[i].kind){
casearrays:
arraycoefdo(fsys,ptx,lev);
fct1=sta;
/*数组保存,要多读一个栈*/
casevariable:
{...}
}}}
//增加的两个虚拟机代码的处理:
lda,sta
voidinterpret(){
caselda:
/*数组元素访问,当前栈顶为元素索引,执行后,栈顶变成元素的值*/
s[t-1]=s[base(i.l,s,b)+i.a+s[t-1]];
break;
casesta:
/*栈顶的值存到数组中,索引为次栈顶*/
t-=2;
s[base(i.l,s,b)+i.a+s[t]]=s[t+1];
...}
五、调试及运行结果
1.测试repeat...until...语句功能测试文件:
4.txt测试结果:
vara,b,n;
begin
b:
=4;
a:
=1;
read(n);
repeat
a:
=a+1;
=b+1;
untila>
n;
write(a);
write(b);
end.
当输入的n为3时,repeat...until...语句中的循环体执行3次,所以a=4,b=72.测试增加的++,--功能
测试文件:
2.txt测试结果:
vara,b;
begin
=3;
b--;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 报告 最终版