编译原理课程设计项目.docx
《编译原理课程设计项目.docx》由会员分享,可在线阅读,更多相关《编译原理课程设计项目.docx(21页珍藏版)》请在冰豆网上搜索。
![编译原理课程设计项目.docx](https://file1.bdocx.com/fileroot1/2023-1/8/32784400-bd2c-4606-b835-1c3ecf5d47eb/32784400-bd2c-4606-b835-1c3ecf5d47eb1.gif)
编译原理课程设计项目
计算机科学系课程设计任务书
题目:
简单编译器的设计与实现
姓名:
学号:
年级:
专业:
计算机科学与技术
指导教师:
职称:
讲师
枣庄学院计算机科学系
2010年12月2日
课程设计的具体要求:
在学习《程序设计语言编译原理》课程过程中,结合各章节构造编译程序的基本理论分别完成词法分析器、语法分析器和语义分析器实验,在基本实验完成的基础上,逐步完成课程设计。
针对自己的理解和学习,实现一个小编译器包括符号表的构造,词法分析,语法分析,目标代码生成等重要子程序(其中词法分析、语法分析及语义分析功能必须完成),并对其进行分析解释和总结,同时将理论与实际应用结合起来,接受软件设计等开发过程的全面训练,从而提高软件开发的能力。
样本语言为C-语言,实现简单的编译器,其中基本的语句要求必须实现,其余部分可根据自己的实际情况选择实现。
对主要代码给予解释和理解注释,各函数和过程应有简要描述,有功能说明,有入口和出口参数说明。
指导教师:
__________时间:
___________
指导教师评语:
成绩:
___________指导教师:
__________时间:
____________
所需实验环境、设备:
WindowsXP操作系统、WIN-TC操作平台
课程设计的具体安排:
2010年11月20日——2010年11月22日,整理资料,准备材料
2010年11月23日——2010年11月25日,编写代码,实现功能
2010年11月26日——2010年11月30日,调试,修改,完善
2010年11月31日,上交作业老师验收。
参考文献:
[1]《程序设计语言编译原理》,陈火旺编著,国防工业出版社
[2]《编译原理》,吕映芝、张素琴、蒋维杜编著,清华大学出版社
[3]《编译原理》,AlfredV.Aho等,李建中译,机械工业出版社
简单编译器的设计与实现
一、课程设计的目的
在学习《程序设计语言编译原理》课程过程中,结合各章节构造编译程序的基本理论分别完成词法分析器、语法分析器和语义分析器实验,在基本实验完成的基础上,逐步完成课程设计。
针对自己的理解和学习,实现一个小编译器括符号表的构造,词法分析,语法分析,目标代码生成等重要子程序,其中词法分析、语法分析及语义分析功能必须完成),并对其进行分析解释和总结,同时将理论与实际应用结合起来,接受软件设计等开发过程的全面训练,从而提高软件开发的能力。
二、课程设计的任务
(1)设计符号表
确定符号表的组织方式,一般应包括名字栏和信息栏,其中名字栏作为关键字。
要考虑能够存储有关名字的信息,并可以高效地完成如下操作:
a.查找:
根据给定的名字,在符号表中查找其信息。
如果该名字在符号表中不存在,则将其加入到符号表中,否则返回指向该名字的指针;
b.删除:
从符号表中删除给定名字的表项。
(2)设计词法分析器
设计各单词的状态转换图,并为不同的单词设计种别码。
将词法分析器设计成供语法分析器调用的子程序。
功能包括:
a.具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
b.能够拼出语言中的各个单词;
c.将拼出的标识符填入符号表;
d.返回(种别码,属性值)。
(3)语法分析器
要求用预测分析法、递归下降分析法、算符优先分析法、SLR分析法(几种方法任选),实现对表达式、各种说明语句、控制语句进行语法分析。
(4)目标代码生成器
能完成指定寄存器个数的情况下将一中间代码程序段翻译成汇编语言目标代码(汇编指令应包括加、减、乘、除),要求指令条数最少的情况下,尽量使用寄存器,尽量少访问内存,这样才能做到运行效率高。
三、课程设计要求
样本语言为C-语言,实现简单的编译器,其中基本的语句要求必须实现,其余部分可根据自己的实际情况选择实现。
对主要代码给予解释和理解注释,各函数和过程应有简要描述,有功能说明,有入口和出口参数说明。
四、简单编译器的实现流程图
源程序
单词符号
语法单位
中间代码
中间代码
目标代码
五、实现环境
WindowsXP操作系统、win-TC运行环境
六、课程设计的详细过程
(1)设计词法分析器
设计思想:
要求:
1.对单词的构词规则有明确的定义;
2.编写的分析程序能够正确识别源程序中的单词符号;
3.识别出的单词以<种别码,值>的形式保存在符号表中;
4.词法分析中源程序的输入以.c格式,分析后的符号表保存在.txt文件中。
5.对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;
6.输入:
由符合规定单词类别结构的各类单词组成的源程序。
实现方法:
根据加入语义过程的状态转换图直接编写词法分析程序。
根据每一组状态转换关系(标识符)组织程序结构,并将所有公共处理过程分别实现即可。
在扫描源程序字符串时,一旦识别出关键字、运算符、标识符、无符号常数中之一,即以二元式形式(类别编码,值)输出单词。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词。
实现过程及主要代码:
定义主要函数:
charprog[80]={'\0'},token[8];
charch;intsyn,n,sum,m,p;
char*rwtab[6]={"begin","if","then","while","do","end"};
实现函数代码:
扫描功能:
voidscaner(){m=0;sum=0;
for(n=0;n<8;n++)
token[n]='\0';ch=prog[p++];
while(ch=='')
ch=prog[p++];
if(isalpha(ch))
{
while(isalpha(ch)||isdigit(ch))]
{
token[m++]=ch;
ch=prog[p++];}
token[m++]='\0';
ch=prog[p--];
syn=10;
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==0)
{syn=n+1;break;}}
Elseif(isdigit(ch))
{
while(isdigit(ch))
{
sum=sum*10+ch-'0';
ch=prog[p++];}
ch=prog[p--];
syn=11;}
else
switch(ch){
case'<':
m=0;token[m++]=ch;ch=prog[p++];
if(ch==‘)’){syn=21;token[m++]=ch;}
elseif(ch=='='){syn=22;
token[m++]=ch;}
else{
syn=20;
ch=prog[p--];}
break;
case'>':
m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=24;
token[m++]=ch;}
else{
syn=23;
ch=prog[p--];}
break;
case':
':
m=0;token[m++]=ch;ch=prog[p++];
if(ch=='='){
syn=18;
token[m++]=ch;}
else{
syn=17;
ch=prog[p--];}
break;
case'+':
syn=13;token[0]=ch;break;
case'-':
syn=14;token[0]=ch;break;
case'*':
syn=15;token[0]=ch;break;
case'/':
syn=16;token[0]=ch;break;
case'=':
syn=25;token[0]=ch;break;
case';':
syn=26;token[0]=ch;break;
case'(':
syn=27;token[0]=ch;break;
case')':
syn=28;token[0]=ch;break;
case'#':
syn=0;token[0]=ch;break;
default:
syn=-1;}}
主函数:
main()
{
printf("\n\nThesignificanceofthefigures:
\n"
"1.figures1to6saidKeyword\n"
"2.figures10and11saidOtherindicators\n"
"3.figures13to28saidOperators\n");
p=0;
printf("\npleaseinputstring:
\n");
do{
ch=getchar();
prog[p++]=ch;
}while(ch!
='#');
p=0;
do{
scaner();
switch(syn){
case11:
printf("(%d,%d)\n",syn,sum);break;
case-1:
printf("\nERROR;\n");break;
default:
printf("(%d,%s)\n",syn,token);
}}
while(syn!
=0);
getch();}
(2)设计语法、语义分析器
设计思想:
要求:
1.对语法规则有明确的定义;
2.编写的分析程序能够对实验一的结果进行正确的语法分析;
3.编写的分析程序能够对实验二的结果进行正确的语义分析;
4.对于遇到的语法、语义错误,能够做出简单的错误处理,给出简单的错误提示,保证语义分析过程;
实现方法:
在词法分析识别出单词符号的基础上分析并规定程序的语法结构是否符合语法规则。
其工作本质就是按文法的产生式,识别输入符号串是否为一个句子。
首先定义语法规则,然后按照规则实现语法分析。
实现过程及主要代码:
插入符号表动作@name-def↓n,t的程序如下:
intname_def(char*name)
{inti,es=0;
if(fhbp>=maxfhbp)return(-1);
for(i=fhbp-1;i==0;i--)//查符号表
{if(strcmp(fhb[i].name,name)==0)
{es=21;//21表示变量重复声明
break;}}
if(es==21)return(es);
strcpy(fhb[fhbp].name,name);
fhb[fhbp].address=datap;
datap++;//分配一个单元,数据区指针加1
fhbp++;
return(es);}
查询符号表返回地址:
intlookup(char*name,int*paddress)
{inti,es=0;for(i=0;i{if(strcmp(fhb[i].name,name)==0)
{*paddress=fhb[i].address;
return(es);}}
es=23;//变量没有声明
return(es);}
语法、语义分析及代码生成程序:
intTESTparse()
{intes=0;
if((fp=fopen("bbb.t","r"))==NULL)
{printf("\n打开%s错误!
\n",Scanout);
es=10;return(es);}
//printf("请输入目标文件名(包括路径):
");
//scanf("%s",Codeout);
if((fout=fopen("ccc.t","w"))==NULL)
{printf("\n创建%s错误!
\n",Codeout);
es=10;return(es);}
if(es==0)es=program();
printf("==语法、语义分析及代码生成程序结果==\n");
switch(es)
{case0:
printf("语法、语义分析成功并抽象机汇编生成代码!
\n");break;
case10:
printf("打开文件%s失败!
\n",Scanout);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;}
fclose(fp);fclose(fout);return(es);}
定义语义规则并实现:
<程序>:
:
={<声明序列><语句序列>}
program:
:
={}
intprogram()
{intes=0,i;fscanf(fp,"%s%s\n",token,token1);
printf("%s%s\n",token,token1);
if(strcmp(token,"{"))//判断是否'{'
{es=1;return(es);}
fscanf(fp,"%s%s\n",&token,&token1);
printf("%s%s\n",token,token1);
es=declaration_list();
if(es>0)return(es);
printf("符号表\n");
printf("名字地址\n");
for(i=0;iprintf("%s%d\n",fhb[i].name,fhb[i].address);
es=statement_list();if(es>0)return(es);
if(strcmp(token,"}"))//判断是否'}'
{es=2;return(es);}
fprintf(fout,"STOP\n");//产生停止指令
return(es);
}
<声明序列>:
:
=<声明序列><声明语句>|<声明语句>
//:
:
=
//|
//改成:
:
={}
intdeclaration_list()
{intes=0;
while(strcmp(token,"int")==0)
{es=declaration_stat();
if(es>0)return(es);}
return(es);}
<声明语句>:
:
=int<变量>;
//↓fhbp,datap,codep->intID↑n@name-def↓n,t;
intdeclaration_stat()
{intes=0;
fscanf(fp,"%s%s\n",&token,&token1);printf("%s%s\n",token,token1);
if(strcmp(token,"ID"))return(es=3);//不是标识符
es=name_def(token1);//插入符号表
if(es>0)return(es);
fscanf(fp,"%s%s\n",&token,&token1);printf("%s%s\n",token,token1);
if(strcmp(token,";"))return(es=4);
fscanf(fp,"%s%s\n",&token,&token1);printf("%s%s\n",token,token1);return(es);}
<语句序列>:
:
=<语句序列><语句>|<语句>
//:
:
=|
//改成:
:
={}
intstatement_list()
{intes=0;
while(strcmp(token,"}"))
{es=statement();
if(es>0)return(es);}
return(es);}
<语句>:
:
=|||
//||<复合语句>|<表达式语句>
//:
:
=||
//||
intstatement()
{intes=0;
if(es==0&&strcmp(token,"if")==0)es=if_stat();//
if(es==0&&strcmp(token,"while")==0)es=while_stat();//
if(es==0&&strcmp(token,"for")==0)es=for_stat();//
//可在此处添加do语句调用
if(es==0&&strcmp(token,"read")==0)es=read_stat();//
if(es==0&&strcmp(token,"write")==0)es=write_stat();//
if(es==0&&strcmp(token,"{")==0)es=compound_stat();//<复合语句>
if(es==0&&(strcmp(token,"ID")==0||strcmp(token,"NUM")==0))es=expression_stat();//<表达式语句>
return(es);}
:
:
=if(<表达式>)<语句>[else<语句>]
//:
:
=if()[else]
if(<表达式>)@BRF↑label1<语句>@BR↑label2@SETlabel↓label1
[else<语句>]@SETlabel↓label2
if()@BRF↑label1@BR↑label2@SETlabel↓label1[else]@SETlabel↓label2
其中动作符号的含义如下
@BRF↑label1:
输出BRFlabel1,
@BR↑label2:
输出BRlabel2,
@SETlabel↓label1:
设置标号label1
@SETlabel↓label2:
设置标号label2
intif_stat(){
intes=0,label1,label2;//if
fscanf(fp,"%s%s\n",&token,&token1);
printf("%s%s\n",token,token1);
if(strcmp(token,"("))return(es=5);//少左括号
fscanf(fp,"%s%s\n",&token,&token1);
printf("%s%s\n",token,token1);
es=expression();
if(es>0)return(es);
if(strcmp(token,")"))return(es=6);//少右括号
label1=labelp++;//用label1记住条件为假时要转向的标号
fprintf(fout,"BRFLABEL%d\n",label1);//输出假转移指令
fscanf(fp,"%s%s\n",&token,&token1);
printf("%s%s\n",token,token1);
es=statement();
if(es>0)return(es);
label2=labelp++;//用label2记住要转向的标号
fprintf(fout,"BRLABEL%d\n",label2);//输出无条件转移指令
fprintf(fout,"LABEL%d:
\n",label1);//设置label1记住的标号
if(strcmp(token,"else")==0)//else部分处理
{fscanf(fp,"%s%s\n",&token,&token1);
printf("%s%s\n",token,token1);
es=statement();
if(es>0)return(es);}
fprintf(fout,"LABEL%d:
\n",label2);//设置label2记住的标号
return(es);}
:
:
=while(<表达式>)<语句>
//:
:
=while()
/*:
:
=while@SETlabel↑label1(<表达式>)@BRF↑label2
<语句>@BR↓label1@SETlabel↓label2
:
:
=while@SET↑labellabel1()@BRF↑label2
@BR↓label1@SETlabel↓label2
动作解释如下:
@SETlabel↑label1:
设置标号label1
@BRF↑label2:
输出B