编译原理课程设计PL0语言的扩充.docx
- 文档编号:11536145
- 上传时间:2023-03-19
- 格式:DOCX
- 页数:42
- 大小:140.79KB
编译原理课程设计PL0语言的扩充.docx
《编译原理课程设计PL0语言的扩充.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计PL0语言的扩充.docx(42页珍藏版)》请在冰豆网上搜索。
编译原理课程设计PL0语言的扩充
一.课程设计目的0
二.课程设计要求0
基本内容:
0
选做内容:
0
已实现的功能:
0
三.编译环境与工具0
四.结构设计说明0
1.PL/0编译程序的结构图0
2.PL/0编译程序的过程或函数的功能表1
3.PL/0编译程序的总体流程图1
4.PL/0编译程序的中间代码2
5.PL\0的编译程序的过程和函数的功能3
五.课程设计的设计与步骤3
1.扩充赋值运算:
+=-=*=/=++和--5
2.增加Pascal的FOR语句15
3.一维数组17
六.调试测试19
1.+=-=*=/=++--的测试19
2.FOR语句的测试21
3.数组的调试22
4.综合调试23
七.课程设计总结25
【参考文献】26
1.课程设计目的
在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。
达到进一步了解程序编译过程的基本原理和基本实现方法的目的。
2.课程设计要求
基本内容:
(1)扩充赋值运算:
*=和/=
(2)扩充语句(Pascal的FOR语句):
①FOR<变量>:
=<表达式>TO<表达式>DO<语句>
②FOR<变量>:
=<表达式>DOWNTO<表达式>DO<语句>
其中,语句①的循环变量的步长为2,语句②的循环变量的步长为-2。
(3)增加运算:
++和--。
选做内容:
(1)增加类型:
①字符类型;②实数类型。
(2)扩充函数:
①有返回值和返回语句;②有参数函数。
(3)增加一维数组类型(可增加指令)。
(4)其他典型语言设施。
已实现的功能:
(1)扩充赋值运算:
*=和/=(另外也扩充了+=和-=)
(2)扩充语句(Pascal的FOR语句):
①FOR<变量>:
=<表达式>TO<表达式>DO<语句>
②FOR<变量>:
=<表达式>DOWNTO<表达式>DO<语句>
(3)增加运算:
++和--。
(4)增加一维数组类型(可增加指令)。
3.编译环境与工具
编译环境:
MicrosoftWindows7(64bit)
编译工具:
MicrosoftVisualC++6.0
4.结构设计说明
1.PL/0编译程序的结构图
2.PL/0编译程序的过程或函数的功能表
过程或函数名
简要功能说明
pl0
主程序
error
出错处理,打印出错位置和错误编码
getsym
词法分析,读取一个单词
getch
漏掉空格,读取一个字符
gen
生成目标代码,并送入目标程序区
test
测试当前单词符号是否合法
block
分程序分析处理过程
enter
登录名字表
position(函数)
查找标识符在名字表中的位置
constdeclaration
常量定义处理
vardeclaration
变量说明处理
listode
列出目标代码清单
statement
语句处理
expression
表达式处理
term
项处理
factor
因子处理
condition
条件处理
interpret
对目标代码的解释执行程序
base(函数)
通过静态链求出数据区的基地址
表4-1PL/0编译程序的过程或函数的功能表
3.PL/0编译程序的总体流程图
图4-2PL/0编译程序的总体流程图
4.PL/0编译程序的中间代码
对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-2PL/0编译程序的目标指令
5.PL\0的编译程序的过程和函数的功能
Pl0:
主程序
Error:
出错处理,打印出错位置和错误编码
Getsym:
词法分析,读取一个单词
Getch:
漏掉空格,读取一个字符
Gen:
生成目标代码,并送入目标程序区
Test:
测试当前单词符号是否合法
Block:
分程序分析处理过程
Enter:
登陆名字表
Position:
查找标识符在名字表中的位置
Constdeclaration:
常量定义处理
Vardeclaration:
变量说明处理
Listcode:
列出目标代码清单
Statement:
语句部分处理
Expression:
表达式处理
Term:
项处理
Factor:
因子处理
Condition:
条件处理
Interpret:
对目标代码的解释执行程序
Base:
通过静态链求出数据区的基地址
5.课程设计的设计与步骤
本次课程设计是在实验的基础上,在实验中,已经实现对PL/0作以下修改扩充:
(1)增加单词:
保留字ELSE,FOR,STEP,UNTIL,RETURN
运算符+=,-=,++,--,∧,∨,┓
(2)修改单词:
不等号#改为<>
(3)增加条件语句的ELSE子句
在课程设计中,因为关键字增加到了18个,所以令#definenorw18。
SYMBOL扩展为48个值。
在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,stepsym,untilsym,returnsym,
plusbecomes,dplus,minusbecomes,dminus,and,or,not,lepa,ripa,
slashbecomes,timesbecomes,
};
#definesymnum48
符号和关键字扩展(粗体部分为课程设计更改部分):
ssym['+']=plus;
ssym['-']=minus;
ssym['*']=times;
ssym['/']=slash;
ssym['(']=lparen;
ssym[')']=rparen;
ssym['=']=eql;
ssym[',']=comma;
ssym['.']=period;
//ssym['#']=neq;去掉#,改为<>
ssym[';']=semicolon;
ssym['!
']=not;//非
ssym['[']=lepa;//一维数组的左括号[
ssym[']']=ripa;//一维数组的右括号]
/*设置保留字名字,按照字母顺序,便于折半查找*/
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");
strcpy(&(word[5][0]),"end");
strcpy(&(word[6][0]),"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");
strcpy(&(word[12][0]),"step");
strcpy(&(word[13][0]),"then");
strcpy(&(word[14][0]),"until");
strcpy(&(word[15][0]),"var");
strcpy(&(word[16][0]),"while");
strcpy(&(word[17][0]),"write");
/*设置保留字符号*/
wsym[0]=beginsym;
wsym[1]=callsym;
wsym[2]=constsym;
wsym[3]=dosym;
wsym[4]=elsesym;
wsym[5]=endsym;
wsym[6]=forsym;
wsym[7]=ifsym;
wsym[8]=oddsym;
wsym[9]=procsym;
wsym[10]=readsym;
wsym[11]=returnsym;
wsym[12]=stepsym;
wsym[13]=thensym;
wsym[14]=untilsym;
wsym[15]=varsym;
wsym[16]=whilesym;
wsym[17]=writesym;
设置指令名称(粗体部分为课程设计更改部分):
strcpy(&(mnemonic[lit][0]),"lit");
strcpy(&(mnemonic[opr][0]),"opr");
strcpy(&(mnemonic[lod][0]),"lod");
strcpy(&(mnemonic[sto][0]),"sto");
strcpy(&(mnemonic[cal][0]),"cal");
strcpy(&(mnemonic[inte][0]),"int");
strcpy(&(mnemonic[jmp][0]),"jmp");
strcpy(&(mnemonic[jpc][0]),"jpc");
strcpy(&(mnemonic[gar][0]),"gar");
strcpy(&(mnemonic[sar][0]),"sar");
strcpy(&(mnemonic[shd][0]),"shd");
strcpy(&(mnemonic[del][0]),"del");
strcpy(&(mnemonic[jud][0]),"jud");
strcpy(&(mnemonic[tra][0]),"tra");
1.扩充赋值运算:
+=-=*=/=++和--
1)在symbol增加字符:
Plusbecomes:
+=
Minusbecomes:
-=
Slashbecomes:
*=
Timesbecomes:
/=
2)对取字符getsym()函数进行扩充,具体如下(粗体部分为更改部分):
intgetsym()
{
...//此处省略部分未修改过的代码
elseif(ch=='+')//读到加号
{
getchdo;//再读一个字符
if(ch=='=')//读到等号,则与+号构成加等
{
sym=plusbecomes;
getchdo;
}
elseif(ch=='+')//读到加号,则与加号构成++
{
sym=dplus;
getchdo;
}
else
{
sym=plus;//那就是一个单独的加号
}
}
elseif(ch=='-')//读到减号
{
getchdo;
if(ch=='=')//读到等号,则与减号构成减等
{
sym=minusbecomes;
getchdo;
}
elseif(ch=='-')//读到减号,则与减号构成--
{
sym=dminus;
getchdo;
}
else
{
sym=minus;//那就是一个单独的减号
}
}
elseif(ch=='*')
{
getchdo;
if(ch=='=')//读到乘号,则与减号构成乘等
{
sym=timesbecomes;
getchdo;
}
else
{
sym=times;//那就是一个单独的乘
}
}
elseif(ch=='/')
{
getchdo;
if(ch=='=')//读到乘号,则与减号构成除等
{
sym=slashbecomes;
getchdo;
}
else
{
sym=slash;//那就是一个单独的除
}
}
...//此处省略部分未修改过的代码
}
3)对statemen函数进行扩展
intstatement(bool*fsys,int*ptx,intlev)
{
...//此处省略部分未修改过的代码
if(sym==ident)
{
i=position(id,*ptx);
if(i==0)
{
error(11);
}
else
{
if(table[i].kind!
=variable&&table[i].kind!
=array)
{
error(12);
i=0;
}
else
{
getsymdo;
if(sym==lepa)//如果是数组
{
getsymdo;//处理[]里的表达式
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
nxtlev[ripa]=true;
expressiondo(nxtlev,ptx,lev);
gendo(tra,0,table[i].size);//生成将数组下标范围入栈指令
gendo(jud,0,0);//判断下标合法性
if(sym!
=ripa)
{
error(26);
}
getsymdo;
}
if(sym==becomes)//赋值:
=
{
getsymdo;
flag=1;
}
elseif(sym==plusbecomes)//加赋值+=
{
getsymdo;
flag=2;
}
elseif(sym==minusbecomes)//减赋值-=
{
getsymdo;
flag=3;
}
elseif(sym==dplus)//++
{
getsymdo;
flag=4;
}
elseif(sym==dminus)//--
{
getsymdo;
flag=5;
}
elseif(sym==timesbecomes)//*=
{
getsymdo;
flag=6;
}
elseif(sym==slashbecomes)///=
{
getsymdo;
flag=7;
}
else
{
error(13);
}
if(i!
=0)
{
if(flag==1)//:
=
{
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);
}
elseif(flag==2)//+=
{
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
gendo(opr,lev-table[i].level,2);//执行加法
}
elseif(i!
=0&&flag==3)//-=
{
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
gendo(opr,lev-table[i].level,3);//执行减法
gendo(opr,lev-table[i].level,1);//取反
}
elseif(i!
=0&&flag==4)//++
{
if(table[i].kind==variable)
{
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
gendo(lit,lev-table[i].level,1);//将值为1入栈
gendo(opr,lev-table[i].level,2);//加法,即加1
}
if(table[i].kind==array)
{
gendo(gar,lev-table[i].level,table[i].adr);
gendo(lit,lev-table[i].level,1);
gendo(opr,lev-table[i].level,2);
}
}
elseif(i!
=0&&flag==5)//--
{
if(table[i].kind==variable)
{
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
gendo(lit,lev-table[i].level,1);//将值为1入栈
gendo(opr,lev-table[i].level,3);//减法,即-1
}
if(table[i].kind==array)
{
gendo(gar,lev-table[i].level,table[i].adr);
gendo(lit,lev-table[i].level,1);
gendo(opr,lev-table[i].level,3);
}
}
elseif(i!
=0&&flag==6)//*=
{
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
gendo(opr,lev-table[i].level,4);//乘法
}
elseif(i!
=0&&flag==7)///=;
{
gendo(lod,lev-table[i].level,table[i].adr);//先取值到栈顶
memcpy(nxtlev,fsys,sizeof(bool)*symnum);
expressiondo(nxtlev,ptx,lev);
gendo(opr,lev-table[i].level,5);//除法
}
if(table[i].kind==array)//数组,根据偏移地址存入数组
{
gendo(sar,lev-table[i].level,table[i].adr);
gendo(del,0,0);//赋值语句需将存入数组后栈顶为偏移地址出栈
}
else//变量
{
gendo(sto,lev-table[i].level,table[i].adr);//根据变量地址存入变量
}
}
}
}
}
elseif(s
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 课程设计 PL0 语言 扩充