编译原理词法分析器.docx
《编译原理词法分析器.docx》由会员分享,可在线阅读,更多相关《编译原理词法分析器.docx(15页珍藏版)》请在冰豆网上搜索。
编译原理词法分析器
实验一词法分析
一、实验目的(实验日期:
2011.3.21)
通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
二、实验要求
编制一个读单词过程,源程序为一个文件,读取该文件,识别出各个具有独立意义的单词,并依次输出各个单词的内部编码及单词符号自身值。
单词的内部编码如下:
1、保留字:
main、if、int、for、while、do、return、break、continue,单词种别码分别为1~9,输出的二元组形式为(单词种别码,0)
2、标识符:
除保留字外的以字母开头,后跟字母、数字的字符序列,单词种别码为20,输出的二元组形式为(单词种别码,标识符的名字);
3、常数为无符号整型数;单词种别码为30,输出的二元组形式为(单词种别码,常数值);
4、运算符包括:
+、-、*、/、=、>、<、>=、<=、==、!
=;单词种别码为41~51,输出的二元组形式为(单词种别码,0);
5、分隔符包括:
、;、{、}、(、);单词种别码为61~66,输出的二元组形式为(单词种别码,0)。
单词符号
种别码
单词符号
种别码
main
1
/
44
int
2
=
45
if
3
>
46
for
4
<
47
while
5
>=
48
do
6
<=
49
return
7
==
50
break
8
!
=
51
continue
9
61
ID
20
;
62
NUM
30
{
63
+
41
}
64
-
42
(
65
*
43
)
66
三、预习提示
1、模块结构参照教材105页图3.22。
四、实验过程和指导
1、准备
(1)课本有关章节;
(2)编制好程序;
(3)准备多组测试数据。
2、为了能设计好程序,注意以下事情:
(1)模块设计:
将程序分成合理的多个模块(函数),每个模块做具体的同一事情。
(2)设计方案:
模块关系简图、流程图、全局变量、函数接口等。
(3)编程时注意编程风格:
空行的使用、注释的使用、缩进的使用等。
五、举例
源程序文件内容如下:
main()
{
inta,b;
a=10;
b=a+20;
}
要求输出如下:
(1,0)
(65,0)
(66,0)
(63,0)
(3,0)
(20,a)
(61,0)
(20,b)
(62,0)
(20,a)
(45,0)
(30,10)
(62,0)
(20,b)
(45,0)
(20,a)
(41,0)
(30,20)
(62,0)
(64,0)
源程序:
#include
#include
#include
structtest//保留字
{
charname[10];
intnum;
};
structoper//运算符与关系运算符
{
charname[4];
intnum;
};
structcut//分隔符
{
charname[2];
intnum;
};
//定义全局变量
structtesttest[9]={
{"main",1},{"if",2},{"int",3},{"for",4},{"while",5},{"do",6},{"retuen",7},{"break",8},{"continue",9}
};
structoperoper[11]={
{"+",41},{"-",42},{"*",43},{"/",44},{"=",45},{">",46},{"<",47},{">=",48},{">=",49},{"==",50},{"!
=",51}
};
structcutcut[6]={
{",",61},{";",62},{"{",63},{"}",64},{"(",65},{")",66}
};
//包含的函数
voidmenu();//菜单
voidscansource();//查看源文件
voidrule();//查看输出规则
voidanalyse();//分析结果显示
voidexplain();
voidgetch(charch);//读取为字母
voidgetnum(charch);//读取为数字
voidgetspace(charch);//读取制表符类
voidgetelse(charch);//其他字符
charch;
charstr[10];
intk=0,i=0;
charsourcefile[20];//源文件名
charobjectfile[20];//目标文件名
FILE*fp;
FILE*hp;
intmain(intargc,char*argv[])
{
intchoice;
//显示菜单
menu();
printf("请输入要进行词法分析的源文件名:
");
scanf("%s",sourcefile);
printf("\n输入要将分析结果存入的文件名:
");
scanf("%s",objectfile);
printf("\n输入选择项:
");
scanf("%d",&choice);
for(;;)
{
switch(choice)
{
case1:
scansource();
break;
case2:
rule();
break;
case3:
analyse();
break;
case4:
explain();
break;
case5:
exit
(1);
break;
}
printf("\n\n");
menu();
printf("输入选择项:
");
scanf("%d",&choice);
}
return0;
}
voidmenu()
{
printf("/************************************************/\n");
printf("词法分析器\n");
printf("1.查看源文件\n");
printf("2.符号种别码\n");
printf("3.分析结果\n");
printf("4.程序说明\n");
printf("5.退出程序\n");
printf("/************************************************/\n");
}
voidscansource()
{
FILE*fp;
charch;
if((fp=fopen(sourcefile,"r"))==NULL)
{
printf("文件打开错误或源文件不存在!
\n");
exit
(1);
}
ch=fgetc(fp);
while(ch!
=EOF)
{
putchar(ch);
ch=fgetc(fp);
}
fclose(fp);
printf("\n");
}
voidrule()
{
inti;
printf("保留字及其对应种别码:
\n");
for(i=0;i<9;i++)
{
printf("(%s,%d)\t",test[i].name,test[i].num);
}
printf("\n");
printf("运算符及其对应种别码:
\n");
for(i=0;i<11;i++)
{
printf("(%s,%d)\t",oper[i].name,oper[i].num);
}
printf("\n");
printf("分隔符及其对应种别码:
\n");
for(i=0;i<6;i++)
{
printf("(%s,%d)\t",cut[i].name,cut[i].num);
}
printf("\n");
}
voidanalyse()
{
if((fp=fopen(sourcefile,"r"))==NULL)
{
printf("文件打开错误!
\n");
exit
(1);
}
if((hp=fopen(objectfile,"w"))==NULL)
{
printf("文件打开错误!
\n");
exit
(1);
}
do
{
ch=fgetc(fp);
if(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z')))
{
getch(ch);
}
elseif((ch>='0')&&(ch<='9'))
{//如果读取的是数字
getnum(ch);
}
Elseif((ch=='')||(ch=='\r')||(ch=='\n')||(ch=='\t'))
{
getspace(ch);
}
else//其他情况
{
getelse(ch);
}
k=0;
str[k]='\0';
}while(ch!
=EOF);
fclose(fp);//关闭文件
fclose(hp);
printf("\n");
}
voidexplain()
{
printf("\n提示:
\n");
printf("本程序是一个进行标准C语言词法分析的程序,在本程序执行的开始,你会看到一个菜单\n");
printf("为了是程序正确的运行,请按照提示进行正确的输入,比如:
输入错误的源文件名会导致\n");
printf("程序因找不到源文件而出错,所以请输入正确的文件名并将源文件与本程序放在同一目录\n");
printf("下,结果将会存入输入的目标文件中,如果目标文件不存在,程序将会自动建立同名文件\n")
printf("可以再程序中或者查看目标文件浏览词法分析结果,谢谢使用!
~(~o~)~zZ\n");
printf("\n");
}
voidgetch(charch)
{
for(;;)
{
str[k]=ch;
str[++k]='\0';
ch=fgetc(fp);
if(!
(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))||((ch>='0')&&(ch<='9'))))
{
fseek(fp,-1L,1);
for(i=0;i<9;i++)
{if(strcmp(str,test[i].name)==0)//测试是否为保留字{printf("(%d,0)\n",test[i].num);fprintf(hp,"(%d,0)\n",test[i].num);
k=0;
break;
}
}
if(k!
=0)//否则为变量
{printf("(20,%s)\n",str);fprintf(hp,"(20,%s)\n",str);
break;
}
break;
}
}
}
voidgetnum(charch)
{
for(;;)
{
str[k]=ch;
str[++k]='\0';
ch=fgetc(fp);
if(!
((ch>='0')&&(ch<='9')))
{
fseek(fp,-1L,1);
printf("(30,%s)\n",str);fprintf(hp,"(30,%s)\n",str);
break;
}
}
}
voidgetspace(charch)
{
for(;;)
{
ch=fgetc(fp);
if(!
((ch=='')||(ch=='\n')||(ch=='\t')||(ch=='\r')))
{
fseek(fp,-1L,1);
break;
}
}
}
voidgetelse(charch)
{
switch(ch)
{
case',':
printf("(61,0)\n");
fprintf(hp,"(61,0)\n");
break;
case';':
printf("(62,0)\n");
fprintf(hp,"(62,0)\n");
break;
case'{':
printf("(63,0)\n");
fprintf(hp,"(63,0)\n");
break;
case'}':
printf("(64,0)\n");
fprintf(hp,"(64,0)\n");
break;
case'(':
printf("(65,0)\n");
fprintf(hp,"(65,0)\n");
break;
case')':
printf("(66,0)\n");
fprintf(hp,"(66,0)\n");
break;
case'+':
printf("(41,0)\n");
fprintf(hp,"(41,0)\n");
break;
case'-':
printf("(42,0)\n");
fprintf(hp,"(42,0)\n");
break;
case'*':
printf("(43,0)\n");
fprintf(hp,"(43,0)\n");
break;
case'/':
printf("(44,0)\n");
fprintf(hp,"(44,0)\n");
break;
case'=':
str[k]=ch;
str[++k]='\0';
ch=fgetc(fp);
if(ch!
='=')
{
fseek(fp,-1L,1);
printf("(45,0)\n");
fprintf(hp,"(45,0)\n");
}
elseif(ch=='=')
{
printf("(50,0)\n");
fprintf(hp,"(50,0)\n");
}
break;
case'>':
str[k]=ch;
str[++k]='\0';
if(ch!
='=')
{
fseek(fp,-1L,1);
printf("(46,0)\n");
fprintf(hp,"(46,0)\n");
}
elseif(ch=='=')
{
printf("(48,0)\n");
fprintf(hp,"(48,0)\n");
}
break;
case'<':
str[k]=ch;
str[++k]='\0';
if(ch!
='=')
{
fseek(fp,-1L,1);
printf("(47,0)\n");
fprintf(hp,"(47,0)\n");
}
elseif(ch=='=')
{
printf("(49,0)\n");
fprintf(hp,"(49,0)\n");
}
break;
case'!
':
str[k]=ch;
str[++k]='\0';
if(ch!
='=')
{
fseek(fp,-1L,1);
}
elseif(ch=='=')
{
printf("(51,0)\n");
fprintf(hp,"(51,0)\n");
}
break;
}
}
程序运行效果:
主界面
查看源文件
符号及其种别码
分析结果
程序说明