简单编译器的设计与实现1Word下载.docx
《简单编译器的设计与实现1Word下载.docx》由会员分享,可在线阅读,更多相关《简单编译器的设计与实现1Word下载.docx(24页珍藏版)》请在冰点文库上搜索。
![简单编译器的设计与实现1Word下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/10/692234b9-7357-40d3-b71a-5c25046ef705/692234b9-7357-40d3-b71a-5c25046ef7051.gif)
种别码,值>
的形式保存在符号表中;
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("
Scanout);
6.if((fin=fopen(Scanin,"
r"
))==NULL)//判断输入文件名是否正确{printf("
\n打开词法分析输入文件出错!
\n"
return
(1);
//输入文件出错返回错误代码1}if((fout=fopen(Scanout,"
w"
))==NULL)//判断输出文件名是否正确{printf("
\n创建词法分析输出文件出错!
(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"
double"
float"
long"
short"
};
char*limit[]={"
("
)"
."
!
"
*"
/"
%"
+"
-"
="
{"
}"
#"
'
FILE*fp;
inti;
charc;
fp=fopen("
key.txt"
for(i=1;
i<
=12;
i++)
fprintf(fp,"
%s\n"
key[i]);
fclose(fp);
/*初始化关键字*/
limit.txt"
=17;
limit[i]);
c='
%c\n"
c);
/*初始化运算、限界符表*/
id.txt"
/*初始化标识符表*/
constant.txt"
/*初始化常数表*/
output.txt"
/*初始化输出文件*/}根据不同命令查表或造表函数:
{intnumber=0;
charc;
chartemp[30];
inti=0;
switch(type){case1:
fp=fopen("
break;
case2:
case3:
case4:
}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);
(0);
/*找不到,当只需查表,返回0,否则还需造表*/}
switch(type)
{case1:
a"
}fprintf(fp,"
buf);
return(number+1);
/*造表时,将字符串添加到表尾并返回序号值*/}
串处理函数:
voidcs_manage(char*buffer)
{FILE*fp;
char*pointer;
intresult;
result=find(buffer,3,2);
/*先查常数表,若找不到则造入常数表并返回序号值*/fp=fopen("
%s\t\t\t3\t\t\t%d\n"
buffer,result);
/*写入输出文件*/}
voidch_manage(char*buffer)
result=find(buffer,1,1);
/*先查关键字表*/
if(result!
=0)
%s\t\t\t1\t\t\t%d\n"
/*若找到,写入输出文件*/else
{result=find(buffer,2,2);
/*若找不到,则非关键字,查标识符表,还找不到则造入标识符表*/
%s\t\t\t2\t\t\t%d\n"
}/*写入输出文件*/
}扫描功能:
intscanner()
{FILE*fpin,*fpout;
charfilename[20];
charch;
inti=0,line=1;
intcount,result;
chararray[30];
char*word;
/*输入要编译文件的名字和路径*/
if((fpin=fopen("
c:
\\source.txt"
))==NULL)
{printf("
thefileyouinputisnotexist!
getch();
return0;
}ch=fgetc(fpin);
while(ch!
=EOF)/*按字符依次扫描源程序,直至结束*/
{i=0;
if(((ch>
A'
)&
&
(ch<
Z'
))||((ch>
a'
z'
))||(ch=='
_'
))/*以字母开头*/
{while(((ch>
)||((ch>
0'
9'
)))
{array[i++]=ch;
ch=fgetc(fpin);
}word=(char*)malloc((i+1)*sizeof(char));
memcpy(word,array,i);
word[i]='
ch_manage(word);
if(ch!
fseek(fpin,-1L,SEEK_CUR);
}elseif(ch>
ch<
)/*以数字开头*/
{while(ch>
{array[i++]=ch;
cs_manage(word);
}elseif((ch=='
'
)||(ch=='
\t'
))
/*消除空格符和水平制表符*/
elseif(ch=='
line++;
/*消除回车并记录行数*/
/'
{/*消除注释*/
if(ch=='
{/*判断是否为‘/=’符号*/
fpout=fopen("
fprintf(fpout,"
/=\t\t\t4\t\t\t32\n"
fclose(fpout);
}elseif(ch!
*'
{/*若为除号,写入输出文件*/
/\t\t\t4\t\t\t13\n"
}}
)/*消除包含在双引号中的字符串常量*/
{fpout=fopen("
%c\t\t\t4\t\t\t37\n"
ch);
}else/*首字符为其它字符,即运算限界符或非法字符*/
{array[0]=ch;
/*再读入下一个字符,判断是否为双字符运算、限界符*/if(ch!
=EOF)/*若该字符非文件结束符*/
{array[1]=ch;
word=(char*)malloc(3*sizeof(char));
memcpy(word,array,2);
word[2]='
result=find(word,4,1);
/*先检索是否为双字符运算、限界符*/if(result==0)/*若不是*/
{word=(char*)malloc(2*sizeof(char));
memcpy(word,array,1);
word[1]='
result=find(word,4,1);
/*检索是否为单字符运算、限界符*/
/*若为单字符运算、限界符,写入输出文件并将扫描文件指针回退一个字符*/fpout=fopen("
%s\t\t\t4\t\t\t%d\t\n"
word,result);
}else/*若为双字符运算、限界符,写输出文件*/
%s\t\t\t4\t\t\t%d\n"
{/*若读入的下一个字符为文件结束符*/word=(char*)malloc(2*sizeof(char));
/*只考虑是否为单字符运算、限界符*/
/*若是,写输出文件*/
}fclose(fpin);
return1;
}主函数:
main()
{inti;
init();
/*初始化*/
i=scanner();
/*扫描源程序*/
if(i==1)
Theanswerisin'
output.txt'
:
}
(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表示变量重复声明
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)
for(i=0;
vartablep;
{*paddress=vartable[i].address;
es=23;
//变量没有声明
}(3)语法、语义分析及代码生成程序
intTESTparse()
{intes=0;
if((fp=fopen(Scanout,"
{printf("
\n打开%s错误!
es=10;
}if(es==0)es=program();
switch(es)
{case0:
printf("
语法分析成功!
case10:
打开文件%s失败!
case1:
缺少{!
缺少}!
缺少标识符!
少分号!
case5:
缺少(!
case6:
缺少)!
case7:
缺少操作数!
case21:
符号表溢出!
case22:
变量重复定义!
case23:
变量未声明!
}
fclose(fout);
//program:
={<
declaration_list>
statement_list>
intprogram()
{intes=0,i;
fscanf(fp,"
%s%s\n"
token,token1);
if(strcmp(token,"
))//判断是否'
{'
{es=1;
&
token,&
token1);
es=declaration_list();
es=statement_list();
}'
{es=2;
}//<
=
//<
declaration_stat>
|<
//改成<
intdeclaration_list()
while(strcmp(token,"
)==0)
{es=declaration_stat();
}return(es);
↓vartablep,datap,codep->
intID↑n@name-def↓n,t;
intdeclaration_stat()
%s%s\n"
if(strcmp(token,"
))return(es=3);
//不是标识符
es=name_def(token1);
//插入符号表
%%s\n"
))return(es=4);
=<
statement>
intstatement_list()
{es=statement();
=<
if_stat>
while_stat>
for_stat>