简单编译器的设计与实现1.docx
《简单编译器的设计与实现1.docx》由会员分享,可在线阅读,更多相关《简单编译器的设计与实现1.docx(24页珍藏版)》请在冰豆网上搜索。
简单编译器的设计与实现1
一、课程设计的目的
在学习《程序设计语言编译原理》课程过程中,结合各章节构造编译程序的基本理论分别完成词法分析器、语法分析器和语义分析器实验,在基本实验完成的基础上,逐步完成课程设计。
针对自己的理解和学习,实现一个译器括符号表的构造,词法分析,语法分析,目标代码生成等重要子程序,其中词法分析、语法分析及语义分析功能必须完成),并对其进行分析解释和总结,同时将理论与实际应用结合起来,接受软件设计等开发过程的全面训练,从而提高软件开发的能力。
二、课程设计的任务
(1)设计符号表
确定符号表的组织方式,一般应包括名字栏和信息栏,其中名字栏作为关键字。
要考虑能够存储有关名字的信息,并可以高效地完成如下操作:
a.查找:
根据给定的名字,在符号表中查找其信息。
如果该名字在符号表中不存在,则将其加入到符号表中,否则返回指向该名字的指针;
b.删除:
从符号表中删除给定名字的表项。
(2)设计词法分析器
设计各单词的状态转换图,并为不同的单词设计种别码。
将词法分析器设计成供语法分析器调用的子程序。
功能包括:
a.具备预处理功能。
将不翻译的注释等符号先滤掉,只保留要翻译的符号串,即要求设计一个供词法分析调用的预处理子程序;
b.能够拼出语言中的各个单词;
c.将拼出的标识符填入符号表;
d.返回(种别码,属性值)。
(3)语法分析器
要求用预测分析法、递归下降分析法、算符优先分析法、SLR分析法(几种方法任选),实现对表达式、各种说明语句、控制语句进行语法分析。
(4)目标代码生成器
能完成指定寄存器个数的情况下将一中间代码程序段翻译成汇编语言目标代码(汇编指令应包括加、减、乘、除),要求指令条数最少的情况下,尽量使
用寄存器,尽量少访问内存,这样才能做到运行效率高。
三、课程设计要求
样本语言为C-语言,实现简单的编译器,其中基本的语句要求必须实现,其余部分可根据自己的实际情况选择实现。
对主要代码给予解释和理解注释,各函数和过程应有简要描述,有功能说明,有入口和出口参数说明。
四、简单编译器的实现流程图表格管理词法分析器源程序出错处理
语法分析器单词符号
语法单位
语义分析与中间代码产生器
中间代码
优化器
中间代码
目标代码生成器
目标代码
五、实现环境
WindowsXP操作系统、win-TC运行环境
六、课程设计的详细过程
(1)设计词法分析器
设计思想:
要求:
1.对单词的构词规则有明确的定义;
2.编写的分析程序能够正确识别源程序中的单词符号;
3.识别出的单词以<种别码,值>的形式保存在符号表中;
4.词法分析中源程序的输入以.c格式,分析后的符号表保存在.txt文件中。
5.对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;
6.输入:
由符合规定单词类别结构的各类单词组成的源程序。
实现方法:
根据加入语义过程的状态转换图直接编写词法分析程序。
根据每一组状态转换关系(标识符)组织程序结构,并将所有公共处理过程分别实现即可。
在扫描源程序字符串时,一旦识别出关键字、运算符、标识符、无符号常数中之一,即以二元式形式(类别编码,值)输出单词。
每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词。
实现过程及主要代码:
定义主要函数:
1.charScanin[100],Scanout[100];//用于接收输入输出文件名
FILE*fin,*fout;//用于指向输入输出文件的指针
2.//下面定义保留,为简化程序,使用字符指针数组保存所有保留字。
//如果想增加保留字,可继续添加,并修改保留字数目
#definekeywordSum8
char
*keyword[keywordSum]={"if","else","for","while","do","int","read","write"};
3.//下面定义纯单分界符,如需要可添加
charsingleword[50]="+-*(){};,:
";
4.//下面定义双分界符的首字符
chardoubleword[10]="><=!
";
5.scanf("%s",Scanin);
printf("请输入词法分析输出文件名(包括路径):
");
scanf("%s",Scanout);
6.if((fin=fopen(Scanin,"r"))==NULL)//判断输入文件名是否正确{printf("\n打开词法分析输入文件出错!
\n");
return
(1);//输入文件出错返回错误代码1}if((fout=fopen(Scanout,"w"))==NULL)//判断输出文件名是否正确{printf("\n创建词法分析输出文件出错!
\n");
return
(2);//输出文件出错返回错误代码2}
7.ch=getc(fin);//读取文件里的一个字符
8.isalpha(ch)//字母判断函数
isalnum(ch))//数字判断函数
strcmp(token,keyword[n])//串比较
fprintf(fout,"%s\t%s\n","ID",token);//输出标识符符号到fout指定的文件strchr(singleword,ch)//声明:
char*strchr(constchar*string,intc);实现函数代码:
初始化函数:
init()
{char*key[]={"","case","char","const","do","double",
"else","float","for","if","int","long","short"};char*limit[]={"","(",")",".","!
","*","/","%","+","-",
"=",",",";","{","}","#","'"};
FILE*fp;inti;charc;fp=fopen("key.txt","w");
for(i=1;i<=12;i++)
fprintf(fp,"%s\n",key[i]);
fclose(fp);/*初始化关键字*/
fp=fopen("limit.txt","w");
for(i=1;i<=17;i++)
fprintf(fp,"%s\n",limit[i]);c='"';
fprintf(fp,"%c\n",c);
fclose(fp);/*初始化运算、限界符表*/
fp=fopen("id.txt","w");
fclose(fp);/*初始化标识符表*/
fp=fopen("constant.txt","w");
fclose(fp);/*初始化常数表*/
fp=fopen("output.txt","w");
fclose(fp);/*初始化输出文件*/}根据不同命令查表或造表函数:
{intnumber=0;FILE*fp;charc;chartemp[30];inti=0;switch(type){case1:
fp=fopen("key.txt","r");break;
case2:
fp=fopen("id.txt","r");break;
case3:
fp=fopen("constant.txt","r");break;
case4:
fp=fopen("limit.txt","r");}c=fgetc(fp);
while(c!
=EOF)
{while(c!
='\n')
{temp[i++]=c;c=fgetc(fp);}
temp[i]='\0';
i=0;
number++;
if(strcmp(temp,buf)==0)
{fclose(fp);
return(number);/*若找到,返回在相应表中的序号*/}
else
{fclose(fp);
return
(0);/*找不到,当只需查表,返回0,否则还需造表*/}
switch(type)
{case1:
fp=fopen("key.txt","a");break;
case2:
fp=fopen("id.txt","a");break;
case3:
fp=fopen("constant.txt","a");break;
case4:
fp=fopen("limit.txt","a");}fprintf(fp,"%s\n",buf);
fclose(fp);
return(number+1);/*造表时,将字符串添加到表尾并返回序号值*/}
串处理函数:
voidcs_manage(char*buffer)
{FILE*fp;
char*pointer;
intresult;
result=find(buffer,3,2);/*先查常数表,若找不到则造入常数表并返回序号值*/fp=fopen("output.txt","a");
fprintf(fp,"%s\t\t\t3\t\t\t%d\n",buffer,result);
fclose(fp);/*写入输出文件*/}
voidch_manage(char*buffer)
{FILE*fp;
intresult;
result=find(buffer,1,1);/*先查关键字表*/
fp=fopen("output.txt","a");
if(result!
=0)
fprintf(fp,"%s\t\t\t1\t\t\t%d\n",buffer,result);/*若找到,写入输出文件*/else
{result=find(buffer,2,2);/*若找不到,则非关键字,查标识符表,还找不到则造入标识符表*/
fprintf(fp,"%s\t\t\t2\t\t\t%d\n",buffer,result);
}/*写入输出文件*/
fclose(fp);}扫描功能:
intscanner()
{FILE*fpin,*fpout;
charfilename[20];
charch;
inti=0,line=1;
intcount,result;
chararray[30];
char*word;
/*输入要编译文件的名字和路径*/
if((fpin=fopen("c:
\\source.txt","r"))==NULL)
{printf("thefileyouinputisnotexist!
");
getch();
return0;}ch=fgetc(fpin);
while(ch!
=EOF)/*按字符依次扫描源程序,直至结束*/
{i=0;
if(((ch>='A')&&(ch<='Z'))||((ch>='a')&&(ch<='z'))||(ch=='_'))/*以字母开头*/
{while(((ch>='A')&&(ch<='Z'))||((ch>='a')&&(ch<='z'))||(ch=='_')||((ch>='0')&&(ch<='9')))
{array[i++]=ch;
ch=fgetc(fpin);}word=(char*)malloc((i+1)*sizeof(char));
memcpy(word,array,i);
word[i]='\0';
ch_manage(word);
if(ch!
=EOF)
fseek(fpin,-1L,SEEK_CUR);}elseif(ch>='0'&&ch<='9')/*以数字开头*/
{while(ch>='0'&&ch<='9')
{array[i++]=ch;
ch=fgetc(fpin);}word=(char*)malloc((i+1)*sizeof(char));
memcpy(word,array,i);
word[i]='\0';
cs_manage(word);
if(ch!
=EOF)
fseek(fpin,-1L,SEEK_CUR);}elseif((ch=='')||(ch=='\t'))
;/*消除空格符和水平制表符*/
elseif(ch=='\n')
line++;/*消除回车并记录行数*/
elseif(ch=='/')
{/*消除注释*/
ch=fgetc(fpin);
if(ch=='=')
{/*判断是否为‘/=’符号*/
fpout=fopen("output.txt","a");
fprintf(fpout,"/=\t\t\t4\t\t\t32\n");
fclose(fpout);}elseif(ch!
='*')
{/*若为除号,写入输出文件*/
fpout=fopen("output.txt","a");
fprintf(fpout,"/\t\t\t4\t\t\t13\n");
fclose(fpout);
fseek(fpin,-1L,SEEK_CUR);}}
elseif(ch=='"')/*消除包含在双引号中的字符串常量*/
{fpout=fopen("output.txt","a");
fprintf(fpout,"%c\t\t\t4\t\t\t37\n",ch);
ch=fgetc(fpin);
while(ch!
='"')
ch=fgetc(fpin);
fprintf(fpout,"%c\t\t\t4\t\t\t37\n",ch);
fclose(fpout);}else/*首字符为其它字符,即运算限界符或非法字符*/
{array[0]=ch;
ch=fgetc(fpin);/*再读入下一个字符,判断是否为双字符运算、限界符*/if(ch!
=EOF)/*若该字符非文件结束符*/
{array[1]=ch;
word=(char*)malloc(3*sizeof(char));
memcpy(word,array,2);
word[2]='\0';
result=find(word,4,1);/*先检索是否为双字符运算、限界符*/if(result==0)/*若不是*/
{word=(char*)malloc(2*sizeof(char));
memcpy(word,array,1);
word[1]='\0';
result=find(word,4,1);/*检索是否为单字符运算、限界符*/
/*若为单字符运算、限界符,写入输出文件并将扫描文件指针回退一个字符*/fpout=fopen("output.txt","a");
fprintf(fpout,"%s\t\t\t4\t\t\t%d\t\n",word,result);fclose(fpout);
fseek(fpin,-1L,SEEK_CUR);}else/*若为双字符运算、限界符,写输出文件*/
{fpout=fopen("output.txt","a");
fprintf(fpout,"%s\t\t\t4\t\t\t%d\n",word,result);fclose(fpout);}}
else
{/*若读入的下一个字符为文件结束符*/word=(char*)malloc(2*sizeof(char));
memcpy(word,array,1);
word[1]='\0';
result=find(word,4,1);/*只考虑是否为单字符运算、限界符*/
/*若是,写输出文件*/
fpout=fopen("output.txt","a");
fprintf(fpout,"%s\t\t\t4\t\t\t%d\n",word,result);fclose(fpout);}}
ch=fgetc(fpin);}fclose(fpin);return1;}主函数:
main()
{inti;
init();/*初始化*/
i=scanner();/*扫描源程序*/
if(i==1)
printf("Theanswerisin'output.txt':
");
getch();}
(2)设计语法、语义分析器
设计思想:
要求:
1.对语法规则有明确的定义;
2.编写的分析程序能够对实验一的结果进行正确的语法分析;
3.编写的分析程序能够对实验二的结果进行正确的语义分析;
4.对于遇到的语法、语义错误,能够做出简单的错误处理,给出简单的错误提示,保证语义分析过程;
实现方法:
在词法分析识别出单词符号的基础上分析并规定程序的语法结构是否符合语法规则。
其工作本质就是按文法的产生式,识别输入符号串是否为一个句子。
首先定义语法规则,然后按照规则实现语法分析。
实现过程及主要代码:
插入符号表动作@name-def↓n,t的程序如下:
(1)定义符号表结构
struct{
charname[8];
intaddress;
}vartable[maxvartablep];//改符号表最多容纳maxvartablep个记录intvartablep=0,labelp=0,datap=0;
//插入符号表动作@name-def↓n,t的程序如下:
intname_def(char*name)
{inti,es=0;
if(vartablep>=maxvartablep)return
(21);
for(i=vartablep-1;i==0;i--)//查符号表
{if(strcmp(vartable[i].name,name)==0)
{es=22;//22表示变量重复声明
break;}}
if(es>0)return(es);
strcpy(vartable[vartablep].name,name);
vartable[vartablep].address=datap;
datap++;//分配一个单元,数据区指针加1
vartablep++;
return(es);}
(2)查询符号表返回地址
intlookup(char*name,int*paddress)
{inti,es=0;
for(i=0;i{if(strcmp(vartable[i].name,name)==0)
{*paddress=vartable[i].address;
return(es);}}
es=23;//变量没有声明
return(es);}(3)语法、语义分析及代码生成程序
intTESTparse()
{intes=0;
if((fp=fopen(Scanout,"r"))==NULL)
{printf("\n打开%s错误!
\n",Scanout);
es=10;
return(es);
}if(es==0)es=program();
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);
es=statement_list();
if(es>0)return(es);
if(strcmp(token,"}"))//判断是否'}'
{es=2;return(es);}
return(es);}//:
:
=
//|
//改成:
:
={}
intdeclaration_list()
{intes=0;
while(strcmp(token,"int")==0)
{es=declaration_stat();
if(es>0)return(es);}return(es);
}//↓vartablep,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\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);}//:
:
=||