简化的C语言编译程序.docx
- 文档编号:10850786
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:48
- 大小:266.25KB
简化的C语言编译程序.docx
《简化的C语言编译程序.docx》由会员分享,可在线阅读,更多相关《简化的C语言编译程序.docx(48页珍藏版)》请在冰豆网上搜索。
简化的C语言编译程序
课程设计
(2010-2011学年度第二学期)
课程名称编译原理
设计题目简化的C语言编译程序
专业:
计算机科学与技术
******
学号:
***********
班级:
本科计算机0801班
*****
地点:
八栋实验室
一、设计目的及优势
目的:
对编译的完整过程有一个感性认识,对各个环节的任务,处理方法有一定的熟悉。
特点:
我写的C语言编译程序,分为五个阶段:
词法分析、语法分析、语义分析与中间代码产生、表格管理、出错处理。
每一个阶段在功能上是相对独立的,它一方面从上一个阶段获取分析的结果来进行分析,另一方面由将结果传递给下一个阶段。
其中词法分析器利用超前搜索、状态转换等方法,将源程序转化成为一个一个的单词符号二元式。
一般程序语言的单词符号包括关键字、运算符、常数、标识符和界符。
语法分析器将这些单词符号作为输入,对它进行语法分析。
语法分析分为两种方法:
自上而下分析法和自下而上分析法。
我采用的是自上而下的分析法。
语法分析器把语法单元作为输入供语义分析器使用。
语义分析器主要采用的是语法制导方法,即在语法分析的同时进行语法分析,并产生一定的语义动作,来生成中间代码(中间代码采用是四元式)。
同时,在上面的几个过程中,涉及到表格管理和出错处理。
在这个编译程序中,可以对C语言的所有结构:
顺序结构,选择结构(if---else),循环结构(while)进行编译,有了这三种结构理论上可以现实任何程序。
在数据类型上采用整型,常数,当然也可以加入其他C语言类型。
同时,有C语言必要的赋值语句,声明语句,转移语句(我采用的是goto语句)。
在其中比较复杂的控制语句中运用回填技术,超前搜索,状态转换,以及标记状态等方法。
我建立起了一个C语言编译器的架构,如果要全部实现其功能的话理论上只需把要各种语法语义加入其中即可。
二、设计内容及步骤
设计内容:
自选一种常见高级语言为背景,对其进行简化.例如只包括整型常数和其四则运算以及相应的赋值语句,转移语句,条件语句和最简单的输入输出语句等.编制一个包括必要处理阶段(词法分析、语法分析、语义分析、代码生成)简化又完整的编译程序。
词法单元的种别码
单词符号
种别码
if
1
else
2
while
3
read
4
write
5
int
6
goto
7
{
8
}
9
单词符号
种别码
Identity
10
NUM
11
LABEL
30
+
13
-
14
*
15
/
16
=
17
==
18
>=
24
;
26
(
27
)
28
<
20
!
=
21
<=
22
>
23
#
0
程序的文法
<程序>:
:
={<声明序列><语句序列>}
<声明语句>:
:
=int<变量>
<语句序列>:
:
=<语句序列><语句>|<语句>
<语句>:
:
=
:
=if(<表达式>)<语句>|[else<语句>]
:
=while(<表达式>)<语句>
<赋值语句>:
:
=ID=<表达式>
:
=goto<标号>
<表达式>:
:
=<项>{+<项>|-<项>}
<项>:
:
=<因子>{*<因子>|/<因子>}
<因子>:
:
=ID|NUM|(<表达式>)
编译程序的工作过程一般可以分为五个阶段:
词法分析、语法分析、语义分析与中间代码产生、优化、目标代码生成。
每一个阶段在功能上是相对独立的,它一方面从上一个阶段获取分析的结果来进行分析,另一方面由将结果传递给下一个阶段。
由编译程序的五个阶段就对应了编译系统的结构。
其中词法分析器利用超前搜索、状态转换等方法,将源程序转化成为一个一个的单词符号二元式。
一般程序语言的单词符号包括关键字、运算符、常数、标识符和界符。
语法分析器将这些单词符号作为输入,对它进行语法分析。
语法分析分为两种方法:
自上而下分析法和自下而上分析法。
针对不同程序语言的语法规则可以采取不同的分析方法,当然两种方法也可以同时使用。
语法分析器把语法单元作为输入供语义分析器使用。
一般的语义分析器主要采用的是语法制导方法,即在语法分析的同时进行语法分析,并产生一定的语义动作,来生成中间代码。
上面三个过程可以与硬件无关,而接下来的优化器和目标代码生成器是针对某一种处理器而言的。
代码优化是将语义分析生成的中间代码进行优化,产生执行效率更高的代码。
目标代码生成器最终生成可以在某种机器上运行的机器语言或者汇编语言。
在整个编译过程中还包括对表格的操作和对错误的处理,这些也都是非常重要的环节。
编译系统的结构框图
(1)设计符号表
确定符号表的组织方式,一般应包括名字栏和信息栏,其中名字栏作为关键字。
要考虑能够存储有关名字的信息,并可以高效地完成如下操作:
a.查找:
根据给定的名字,在符号表中查找其信息。
如果该名字在符号表中不存在,则将其加入到符号表中,否则返回指向该名字的指针;
b.删除:
从符号表中删除给定名字的表项。
(2)设计词法分析器
设计各单词的状态转换图,并为不同的单词设计种别码。
将词法分析器设计成供语法分析器调用的子程序。
功能包括:
a.具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
b.能够拼出语言中的各个单词;
c.将拼出的标识符填入符号表;
d.返回(种别码,属性值)。
(3)语法分析器
要求用预测分析法、递归下降分析法、算符优先分析法、SLR分析法(几种方法任选),实现对表达式、各种说明语句、控制语句进行语法分析。
(4)语义分析器及目标代码生成器
主要是生成四元式。
三、详细的算法描述(流程图或伪代码)
1、总的程序架构
图1语义分析主程序流程图
图3语句串分析程序流程图
图2递归下降分析程序流程图
图5statement_list语句序列程序流程图
图4declaration_stat声明语句程序流程图
图6statement语句函数流程图图7expression语句程序流程图
图7term函数程序流程图图8factor函数程序流程图
2、使用的数据结构和关键变量
//标识符结构体
structIdentity
{
charname[8];//名字
intaddress;//值在常数表中的位置
}iden[50];
intlabelp=0;//全局标号用于goto语句记录标签时使用。
charch;//用户输入的字符
intdatap=0;//常数表中的常数的位置值
intidenp=0;//标识符中的在常数中的位置值
intsyn;//单词的种别码
intcurreny=0;//四元式的全局标号
charprog[200];//保存用户输入的程序段
token[8];//保存单个词法单元
char*rwtab[7]={"if","else","while","read","write","int","goto"};//关键字
structNUM//常数表
{
intvalue;//常数值
intpoint;//常数在表中的位置
}num[50];
intlabelp=0;//全局标号
structLABEL//标号结构体,用于保存goto时的转移地址
{
charlabelname[8];
intlabeladdr;
}label[50];
//四元式
structsiyuanshi{
intlabel;
charresult[8];
charag1[8];
charag2[8];
charop[8];
}quad[100];
3、主要功能函数简述
在1目中我已画出了总的程序架构。
在这里说明语句中的if语句、while语句、赋值语句、goto语句。
intif_stat();
功能:
对if语句进行分析,产生四元式。
同时能对else进行处理。
采用了回填技术,超前搜索。
返回分析状态值。
intwhile_stat()
功能:
对while语句进行分析,产生四元式。
采用了回填技术。
返回分析状态值。
intassign_stat()
功能:
对赋值语句进行分析,产生四元式返回分析状态值。
voidscaner()
功能:
属于词法分析阶段,识别出一个个单词符号传给token,将种别码传给syn。
intgoto_stat()
功能:
对goto语句进行分析,产生四元式。
采用了回填技术。
返回分析状态值。
intlabel_stat()
功能:
将标号放入标号结构体数组中,返回分析状态值。
char*newtemp()
功能:
新建一个临时变量,并返回此变量
intputIntolabel(char*name)
功能:
将标号插入符号表中,返回分析状态值。
intputIntoIdentity(char*name)
功能:
将标识符及相关信息插入符号表中,返回分析状态值。
intlookup(char*name,int*address)
功能:
在符号表中查找变量名,返回分析状态值。
四、设计结果(测试案例)
1.声明语句及赋值语句测试
输入:
{inta;intb;a=8;b=4;}#
输出:
2.if语句测试
输入:
{inta;intb;a=9;b=4;if(a>b){a=4;}else{b=3;}}#
输出:
3.while语句测试
输入:
{inta;
intb;
a=4;
b=3;
while(a>b)
{a=5;
}}#
输出:
4.goto语句测试
输入:
{inta;
intb;
a=4;
b=3;
Label1:
if(a>b)
{
a=4;
}
b=5;
gotoLabel1;
a=a+b;
}#
输出:
5.综合测试
输入:
{inta;
intb;
a=5;b=4;
if(a>=b)
{a=a+b;
}else{
a=a-b;
}
while(a>b)
{
a=a+b;
a=a-1;
}
Label1:
a=a+2;
b=b-1;
gotoLabel1;
}#
输出:
当然还可设计嵌套的程序,在这里只是演示,不可能穷举出所有测试用例。
四、设计总结与心得
在做这个课程设计之前,由于对编译原理有一种恐惧感,因此我不敢掉以轻心。
我在11周就开始准备了。
首先,是将老师给三个实验指导,了解其中的原理,明白其方法,掌握其思想。
然后,根据程序框架在12的时候将三个实验全部用C语言实现。
后来我理清了思路后,打算在原来的基础编写更复杂的编译程序。
在13周的周六下午我开始编码,开始我是想将其生成汇编代码的,我将程序写到晚上11点钟的样子,发现写不下去了。
因为一是汇编代码大部分忘记了,二是不知道怎么组织起来,汇编代码是基于特定的机器的。
我在设计的时候进入了低谷。
第二天7点多起来,我决定不生成汇编代码,改用生成四元式,原因是相对来说比较容易实现,书上有,另外一方面是那三个实验的最后语义分析生成的是四元式,我是有一定基础的。
虽然前一天在生成汇编代码的问题失败了,但是那些工作没有白费,在周日的整个上午,我将在生成汇编代码的地方改成生成四元式。
中午休息了一下,下午进行最让人头痛的工作来了——调试。
我首先修改了程序中的一些语法错误,这个很容易就解决了。
最难的是逻辑错误,我碰的最主要的问题是,scaner()函数的调用次序,我是读出一个单词接着进行处理的,scaner()分布在整个编译程序中,这给我的调试带来了难度,这个scaner()函数的次序就显得很重要了。
我花了三分之二的调试时间去把这个问题解决了。
最后,我砬到一个很具有戏剧性的问题,我输入了一段代码,进行分析,发现每一次执行到相同的地方就出现了错误,是执行到相同的地方,我强调一下。
我百思不得其解,我进行了调试,调试几次都一无所获。
接着,我决定加强调试的细度,在调试到scaner()函数时,跟踪ch的值,发现当prog[80]以后,ch的值和我预期的值不一样,这时我才恍然大悟,原来我将prog的值长度设为80而我输入的程序超过80个字符,于是我将prog的长度设为了200。
再次输入原来的程序段,一点错误也没有。
经过一个下午,调试完成。
当然我也不可能找到所有的Bug,但总算做完了。
我花了一天半的时间,将这个C语言分析程序写完了,用了近1000行代码。
回顾这段时间,心态是呈波浪线式的,有低谷也有兴奋的时候,这段时间很痛苦。
在这个程序中我觉得最有技术含量的地方是回填技术,它的思想比较简单,但是用程序实现起来是有一定难度的,它的逻辑性很强。
最后,我总结出一个编程经验:
只要想得到,就做得到。
我认为自己写这个程序的时间是比较短的,原因在于我前期做了很多工作,我加强了理论的基础,和巩固C语言的编程技巧,做到心中有思路才开始编码的。
我最后的心得就是:
要做一个有思想的人,有准备地做事!
六、附:
程序完整代码
#include
#include
charch;intsyn,p,m,n,sum,kk,k=0;
char*rwtab[7]={"if","else","while","read","write","int","goto"};
intcurreny=0;//四元式的全局标号
charprog[200],token[8];
charplace[12];
intmaxNum=50;
structNUM//常数
{
intvalue;//常数值
intpoint;//常数在表中的位置
}num[50];
FILE*out=NULL;
intlabelp=0;//全局标号
structLABEL//标号结构体,用于保存goto时的转移地址
{
charlabelname[8];
intlabeladdr;
}label[50];
//标识符结构体
structIdentity
{
charname[8];//名字
intaddress;//值在常数表中的位置
}iden[50];
intdatap=0;
intidenp=0;
//四元式
structsiyuanshi{
intlabel;
charresult[8];
charag1[8];
charag2[8];
charop[8];
}quad[100];
main()
{
voidscaner();
intlrparser();
intes,i;
kk=0;
p=0;
printf("Pleaseinputstring:
\n");
do{
ch=getchar();
prog[p++]=ch;
}while(ch!
='#');
printf("======词法分析及代码生成程序结果=====\n");
p=0;
scaner();
printf("%s%d\n",token,syn);
es=lrparser();
switch(es)
{
case0:
printf("语法、语义分析成功并生成四元式代码!
\n");
break;
case10:
printf("标号重复使用!
\n");
break;
case11:
printf("无效的标号!
");
break;
case1:
printf("缺少{!
\n");
break;
case2:
printf("缺少}!
\n");
break;
case3:
printf("缺少标识符!
\n");
break;
case4:
printf("缺少分号!
\n");
break;
case5:
printf("缺少(\n");
break;
case6:
printf("缺少)\n");
break;
case7:
printf("缺少操作数!
\n");
break;
case21:
printf("符号表溢出!
\n");
break;
case22:
printf("变量重复定义!
\n");
break;
case23:
printf("变量未声明!
\n");
break;
case24:
printf("赋值号错误!
\n");
break;
case25:
printf("变量未赋值就使用!
\n");
break;
}
for(p=0;p { printf("%d\t%s\t%s\t%s\t%s\n",quad[p].label,quad[p].result,quad[p].ag1,quad[p].op,quad[p].ag2); } } intlrparser() { voidscaner(); intyucu(); intes=0; kk=0; if(syn==8) { es=yucu(); if(syn==9)//结束 { scaner(); if(syn==0&&(kk==0)) { printf("success! \n"); } elseif(kk! =1) { printf("lost'}'error! \n"); es=2; } } } else { printf("{error! \n"); es=1; } returnes; } //程序: : ={<声明序列><语句序列>}program: : ={ intyucu() { inti; intstatement(); voidscaner(); intdeclar_list(); intdeclaration_stat(); intes=0; es=declar_list();//声明语句 if(es>0) returnes; for(i=0;i printf("%s%d\n",iden[i].name,iden[i].address); es=statement_list(); returnes; } intdeclar_list()//声明语句 { voidscaner(); intdeclaration_stat(); intes=0; scaner(); printf("%s%d\n",token,syn); while(strcmp(token,"int")==0) { es=declaration_stat(); if(es>0) returnes; } returnes; } //<声明语句>: : =int<变量> // intdeclaration_stat() { intputIntoIdentity(chartoken[8]); intes=0; voidscaner(); scaner(); printf("%s%d\n",token,syn); if(syn! =10) returnes=3; es=putIntoIdentity(token); if(es>0) returnes; scaner(); printf("%s%d\n",token,syn); if(strcmp(token,";")) return(es=4); scaner(); printf("%s%d\n",token,syn); returnes; } //<语句序列>: : =<语句序列><语句>|<语句> // : = intstatement_list() { intstatement(); intes=0; voidscaner(); while(strcmp(token,"}")) { es=statement(); if(es>0) returnes; scaner(); printf("%s%d\n",token,syn); } returnes; } //<语句>: : = // : = intstatement() { voidscaner(); chartt[8],eplace[8]; voidemit(char*result,char*ag1,char*op,char*ag2); intassign_stat(); intlabel_stat(); intif_stat(); intwhile_stat(); intes=0; switch(syn)//是标识符 { case10: //赋值语句 es=assign_stat(); break; case1: es=if_stat(); break; case3: es=while_stat(); break; case30: es=label_stat();//标号 break; case7: es=goto_stat(); break; } returnes; } intlabel_stat() { intes=0; es=putIntolabel(token); returnes; } intgoto_stat() { voidscaner(); intes=0,i; char*tt=malloc(12); scaner(); printf("%s%d\n",token,syn); for(i=labelp-1;i>=0;i--) if(strcmp(
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 简化 语言 编译程序