编译原理
实验名称:词法分析器
班 级:计科0705
姓 名:
学 号:
20##年4月29日
词法分析器
一. 实验目的要求
用C语言编写一个词法分析器,使之能识别输入串,并把分析结果(单词符号,标识符,关键字等等)输出。输入源程序,输出单词符号,本词法分析器可以辨别关键字,标识符,常数,运算符号,逻辑符号和某些界符,运用了文件读入来获取源程序代码,再对该源程序代码进行词法分析,逐个识别出其中的单词,并将其转换为内部编码形式的单词符号串作确为输出。通常,可采用二元式 (value,class) 来表示一个单词符号的内部编码,其中:class为一类型码,用于表示该单词的类别;value则是该单词之值。
二. 单词分类表
将单词分为五类:
1.:保留字 2:标识符 3:数字符 4:运算符 5:界符
1.对给定的程序通过词法分析器弄够识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示。而本程序则是通过对给定路径的文件的分析后以单词符号和文字提示显示。
2.本程序我们自行规定(即单词分类表):
(1)关键字:
"auto","double","union","int","struct","break","else","long","switch","case","enum",
"register","typedef","char","extern", "return","const","float","short","unsigned","continue","for","signed","void","default","goto","sizeof", "volatile","do","while","static","if"};
运算符: "+","-","*","/","="
界符: ",",";","{","}","(",")","[","]",".","#"
(4)其他标记 如字符串,表示以字母开头的标识符。
(5)空格、回车、换行符过滤。
在屏幕上显示如下:
=>1 保留字
=>2 标识符
=>3 数字符
=>4 运算符
=>5 界符
三.单词状态图
四.算法描述
由主程序main()先调入index()函数进入主界面,用户根据提示输入要进行词法分析的文件,然后进入analysis()函数调入用户输入的文件进行分析。当所读入的文件不为空时开始分析,1:进行注释判断,将注释消除 2:过滤空格及判断出的注释符 3:判断标识符和保留字 4:判断数字 5:判断运算符和界符(同时进行括号匹配)6:在各部分中增加相对的错误提示 7:将结果输出到界面以及相应的out.txt。
五.程序结构
#define Baoliuzi 1
#define Biaoshifu 2
#define Shuzifu 3
#define Yunsuanfu 4
#define Jiefu 5
int main()
int analysis() /*用来实现:读写文件,判断注释,对空格进行过滤 ,判断注释符,判断标识符和保留字,判断是数字,判断是运算符或者是界符,判断括号匹配。*/
int letterjudge(char ch) //判断一个字符是否是字母
int numberjudge(char ch) //判断一个字符是否是数字
六.运行调试结果
通过运行调试,初步实现所需功能,报错功能仍有较大空间提高
七.个人在词法分析器中的任务
我在里面负责判断标识符,保留字,数字。
int letterjudge(char ch);
int numberjudge(char ch);
并且参与程序整体的维护和构架,以及几大模块之间的衔接。在标识符和保留字中,充分利用文件的一些操作和程序。在数字判断方面考虑到数字的类型,分类进行处理,最后的判断输出到文件out.txt中。
八.设计技巧及体会
进行词法分析器之前,现在网上参考了一些分析器的设计思路,从而确定了自己的设计方向,开始设计完成后仅仅是不到二百行的一个简易程序,通过观察老师检查别的设计小组时提出的问题,发现自己的程序仍存在很大的缺陷,例如:没有报错,无法消除注释和注释符,相同的标识符在输出文件中重复出现。通过全组人员不断的修改调试以及运行结果检测,程序的应用性有了很大的提高。
通过这次程序设计,加强了我与人配合共同完成一个程序的合作经验,并且更加清楚明白了许多程序设计时需要注意到的细节问题,熟悉了程序语言及构造词法分析器的原理,总之,这次试验让我受益匪浅。
(注:源程序清单请见电子版,稍后附上)
(组员:(1)组长:赵楠(2)郑磊(3)孙龙飞)
总体代码如下:
#include
#include
#include
#define Baoliuzi 1
#define Biaoshifu 2
#define Shuzifu 3
#define Yunsuanfu 4
#define Jiefu 5
char *baoliuzi[32]={"auto","double","union","int","struct","break","else","long","switch","case","enum","register","typedef","char","extern", "return","const","float","short","unsigned","continue","for","signed","void","default","goto","sizeof", "volatile","do","while","static","if"};
char *yunsuanfu[5]={"+","-","*","/","="};
char *jiefu[10]={",",";","{","}","(",")","[","]",".","#"};
//函数声明
int analysis();
int letterjudge(char ch);
int numberjudge(char ch);
void index()
{
printf("\n\t\t=========***********欢迎使用词法分析器************==========\n");
printf("\n\t\t\t");
printf("\n\t\t\t\t");
printf("\n\t\t\t");
printf(" \t ##本词法分析器可为您分析出## \n");
printf("\n");
printf("\n");
printf("\n");
printf(" \t\t =>1 保留字\n");
printf(" \t\t =>2 标识符\n");
printf(" \t\t =>3 数字符\n");
printf(" \t\t =>4 运算符\n");
printf(" \t\t =>5 界符\n");
printf("\n\t");
printf("\n");
printf("\n");
}
//*************************************************************
int analysis()//词法分析程序算法
{
int i=0,k=0; //k用来表示标识符存储下标
int sBracketL=0,sBracketR=0,mBracketL=0,mBracketR=0,bBracketL=0,bBracketR=0; //括号匹配
char ch;
char name[20];
char save[20][20]={'\0'}; //用来存储标识符
FILE *fpin;
FILE *fpout;
//文件操作
printf("\n\t\t======================词法分析器======================\n");
printf("\n\n\t\t请输入需要分析的文件的文件名:");
scanf("%s",&name);
if((fpin=fopen(name,"r"))==NULL)
{
printf ("\t无法打开文件,请重新查看!\n");
return(1);
}
if((fpout=fopen("out.txt","w+"))==NULL)
{
printf ("\t无法打开文件,请重新查看!\n");
return(1);
}
printf("\n\t\t=========================词法分析开始======================\n");
ch=fgetc(fpin); //获取文件的第一个字符
//对读取进来的字符进行判断
while(ch!=EOF)
{
int a,b,c;
char buffer[20]={'\0'}; //暂时存储从文件读来的字符并且对buffer进行清空
if(ch==EOF) //判断文件是否为空
{
fclose(fpin);
fclose(fpout);
}
//*************************************判断注释
if(ch=='/')
{
ch=fgetc(fpin);
if(ch=='/') //消除注释符//后的注释
{
while(ch!='\n')
{
ch=fgetc(fpin);
}
ch=fgetc(fpin);
continue;
}
else if(ch=='*')
{
int flag=0;
ch=fgetc(fpin);
while(flag!=2)
{ //当扫描到‘*’且紧接着下一个字符为‘/’才是注释的结束
flag=0;
while(ch!='*')
ch=fgetc(fpin);
flag++;
ch=fgetc(fpin);
if(ch=='/')
flag++;
else
ch=fgetc(fpin);
}
}
else //若为除号写入输出文件
{
buffer[0]=ch;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
ch=fgetc(fpin);
continue;
}
//*****************************对空格进行过滤
if(ch=='09'||ch=='10'||ch=='12'||ch=='13'||ch==' ')
ch=fgetc(fpin); //获取文件的下一个字符
//******************************判断注释符
if(ch=='\\')
{
ch=fgetc(fpin);
switch(ch)
{
case 'n': ; // \n 回车换行 10
case 't': ; // \t 横向跳到下一制表位置 9
case 'r': ; // \r 回车 13
case 'f': ; // \f 走纸换页 12
default: ;
}
ch=fgetc(fpin);
continue;
}
a=letterjudge(ch); // a表示字母函数的返回值
b=numberjudge(ch); // b表示数字函数的返回值
//*********************************判断标识符和保留字
if(a==1) //下一个字符为字母
{
int r1,r2;
int j=0;
while(a)
{
int m,n;
m=letterjudge(ch); // a表示字母函数的返回值
n=numberjudge(ch); // b表示数字函数的返回值
if(m==1||n==1)
{
buffer[j]=ch;
ch=fgetc(fpin);
j++;
}
else break;
}
for(i=0;i<32;i++)
{
r1=strcmp(baoliuzi[i],buffer); //将字符串同保留字串相对比
if(r1==0)
{
printf("\n\t%s是保留字\n",buffer); //输出到界面上
fprintf(fpout,"(%i,\"%s\")\n",Baoliuzi,buffer); //输出到文件
break;
}
}
if(r1!=0)
{
for(i=0;i<20;i++) //判断标识符是否已经出现过
{
r2=strcmp(save[i],buffer);
if(r2==0)
break;
}
if(r2!=0)
{
strcpy(save[k],buffer);
printf("\n\t%s是标识符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Biaoshifu,buffer);
k++;
}
}
continue; //接受下一个字符串
}
//*************************判断是数字 b表示数字函数的返回值
else if(b==1)
{
int j=0;
int flag=0; //小数点个数判断
while(b)
{
int m,n;
m=letterjudge(ch);
n=numberjudge(ch);
if(n==1)
{
buffer[j]=ch;
ch=fgetc(fpin);
j++;
}
else break;
if(letterjudge(ch)==1) //判断数字后面时候存在标识符
{
printf("\n\t数字串后出现标识符,出错!按任意键退出修改源文件!"); //出现标识符则报错
getchar();
getchar();
exit (1);
}
if(ch==*jiefu[6]) //判断数字后面是否存在小数点
{
flag++; //小数点个数加一
if(flag>1) //出现一次以上的小数点则报错
{
printf("\n\t数字串中存在一个以上小数点,出错!按任意键退出修改源文件!\n");
getchar();
getchar();
exit (1);
}
else
{
buffer[j]=ch;
j++;
ch=fgetc(fpin); //如果是一个小数点则继续读下一个数字
}
}
}
printf("\n\t%s是数字\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Shuzifu,buffer); //输出到文件
continue;
}
//***********************************判断是运算符或者是界符
else
{
int r1,r2;
char ch1;
buffer[0]=ch;
//判断是运算符
for(i=0;i<5;i++)
{
r1=strcmp(yunsuanfu[i],buffer);
if(r1==0)
{
if(ch=='+')
{
ch1=fgetc(fpin);
if(ch1=='+') //判断++符号
{
buffer[1]=ch1;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
else if(ch1=='=') //判断+=符号
{
buffer[1]=ch1;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
else //否则输出运算符+
{
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
}
else if(ch=='-')
{
ch1=fgetc(fpin);
if(ch1=='-') //判断--符号
{
buffer[1]=ch1;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
else if(ch1=='=') //判断-=符号
{
buffer[1]=ch1;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
else //否则输出运算符-
{
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
}
else
{
ch1=fgetc(fpin); //判断*=,/=,==
if(ch1=='=')
{
buffer[1]=ch1;
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
else
{
printf("\n\t%s是运算符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Yunsuanfu,buffer); //输出到文件
break;
}
}
}
}
//判断是界符
for(i=0;i<10;i++)
{
r2=strcmp(jiefu[i],buffer);
if(r2==0)
{
/*switch(ch) //计算括号数
{
case '(': sBracketL++;
case ')': sBracketR++;
case '[': mBracketL++;
case ']': mBracketR++;
case '{': bBracketL++;
case '}': bBracketR++;
defaule: break;
}*/
if(ch=='(') //计算括号数
sBracketL++;
else if(ch==')')
sBracketR++;
else if(ch=='[')
mBracketL++;
else if(ch==']')
mBracketR++;
else if(ch=='{')
bBracketL++;
else if(ch=='}')
bBracketR++;
else continue;
printf("\n\t%s是界符\n",buffer);
fprintf(fpout,"(%i,\"%s\")\n",Jiefu,buffer); //输出到文件
break;
}
}
ch=fgetc(fpin);
continue;
}
break;
}
printf("%d!!!",sBracketL);
printf("%d!!!",sBracketR);
printf("%d!!!",mBracketL);
printf("%d!!!",mBracketR);
if(sBracketL!=sBracketR) //判断括号匹配
{
printf("\n\t小括号匹配出现问题!按任意键退出修改源文件!\n");
getchar();
getchar();
exit (1);
}
if(mBracketL!=mBracketR)
{
printf("\n\t中括号匹配出现问题!按任意键退出修改源文件!\n");
getchar();
getchar();
exit (1);
}
if(bBracketL!=bBracketR)
{
printf("\n\t大括号匹配出现问题!按任意键退出修改源文件!\n");
getchar();
getchar();
exit (1);
}
return 0;
}
//************************判断一个字符是否是字母
int letterjudge(char ch)
{
int flag=0;
if((ch >= 'a' && ch<='z')||(ch>='A' && ch<='Z'))
flag=1;
return flag;
}
//************************判断一个字符是否是数字
int numberjudge(char ch)
{
int flag=0;
if(ch>='0' && ch<='9')
flag=1;
return flag;
}
int main() //主函数
{
index();
analysis();
printf("\n");
printf("\n");
printf("\n\t\t========================词法分析完毕=========================\n");
getchar();
getchar();
return(0);
}