编译原理实验词法分析器.docx
《编译原理实验词法分析器.docx》由会员分享,可在线阅读,更多相关《编译原理实验词法分析器.docx(15页珍藏版)》请在冰豆网上搜索。
编译原理实验词法分析器
洛阳理工学院实验报告
院部
计算机系
班级
B150402
学号
姓名
课程名称
编译原理
实验日期
2018.6.4
实验名称
词法分析器
成绩
实验目的:
加深对词法分析过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析;能够使自己编写的程序对简单的程序片段进行词法分析。
实验条件:
装有Windows操作系统,MicrosoftVisualC++6.0。
实验内容:
自定义一种程序设计语言,或选择已有的一种高级语言(C语言),编制它的词法分析程序。
实验要求:
1.对单词的构成规则有明确的定义
2.编写的程序能够正确识别源程序中的单词符号
3.识别出的单词以<种别码,值>的形式保存在符号表中
4.词法分析中源程序和分析后的符号表均保存在.txt文件中
5.有一定的检查错误的能力。
遇到错误时可显示“Error”,然后跳过错误部分继续显示。
6.实验报告包括以下内容
(1)编程思路、流程图、源代码
(2)上机调试时发现的问题,以及解决的过程
(3)所使用的测试数据及结果
(4)心得体会
实验步骤
1.给出目标语言的所有单词符号及种别编码、单词符号的状态转换图。
2.依次读入源程序,对源程序进行单词切分和识别,直到源程序结束。
3.对正确的单词,按照它的种别以<种别码,值>的形式保存在符号表中。
4.对不正确的单词,做出错误处理。
实验内容:
1.编程思路:
1.1、实现预处理功能
源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。
1.2、实现词法分析功能
输入:
所给文法的源程序字符串。
输出:
将每个单词或数字以及他对应的种别码和类型输出到文件中。
具体实现时,可以将单词的二元组用结构进行处理。
1.3、待分析的C语言子集的词法
1)关键字"char","int","if","else","var","return","break","do","while","for","double","float","short"
2)运算符和界符
+-*/<<><=>>==;()[]\|&{}\\#
3)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
1.4、各种单词符号对应的种别码
表1各种单词符号的种别码
单词符号
种别码
char
1
int
2
if
3
else
4
var
5
return
6
break
7
do
8
while
9
for
10
double
11
float
12
short
13
标识符
14
数字
15
符号
16-40
1.5、词法分析程序的主要算法思想
算法的基本任务是从文件中读出字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号,并输出到文件中。
2.流程图:
2.1主程序流程图
主函数流程图
2.2分析函数流程图
分析函数流程图
3.源代码:
#include
#include
#include
#include
#include
inti,row=0,line=0;
chara[1000];//程序
intnumber[1000][100];//常数表
charmark[100][5];//标识符表
FILE*fin,*fout;
//词法分析
intwordanalysis()
{
if((a[i]>='A'&&a[i]<='Z')||(a[i]>='a'&&a[i]<='z'))//分析标识符和关键字
{
charword[10];
charkeyWord[100][100]={"char","int","if","else","var","return","break","do","while","for","double","float","short"};//关键字表
intn=0;
word[n++]=a[i++];
//若字符为A~Z或0~9,则继续读取
while((a[i]>='A'&&a[i]<='Z')||(a[i]>='0'&&a[i]<='9')||(a[i]>='a'&&a[i]<='z'))
{
word[n++]=a[i++];
}
word[n]='\0';
i--;
//判断该标识符是否为关键字
for(n=0;n<100;n++)
{
if(strcmp(word,keyWord[n])==0)
{
fprintf(fout,"%s\t(%d)\t关键字\n",keyWord[n],n+1);
return3;
}
}
//判断该标识符是否存在标识符表中
intm=0;
if(line!
=0)
{
intq=0;
while(q{
if(strcmp(word,mark[q++])==0)
{
fprintf(fout,"%s\t(14,%d)\t标识符\n",word,q);
return3;
}
}
}
//将该标识符保存到标识符表中
strcpy(mark[line],word);
fprintf(fout,"%s\t(14,%d)\t标识符\n",word,line+1);
line++;
return3;
}
elseif(a[i]>='0'&&a[i]<='9')//分析常数
{
charx[100];
intn=0,sum;
x[n++]=a[i++];
//判断字符是否是0~9
while(a[i]>='0'&&a[i]<='9')
{
x[n++]=a[i++];
}
x[n]='\0';
i--;
intnum=atoi(x);//将字符串转换成int型
//判断该常数是否存在于常数表中
if(row!
=0)
{
inty;
for(y=0;y<1000;y++)
{
intw=number[y][0];
sum=0;
intd;
for(d=1;d<=number[y][0];d++)
{
w=w-1;
sum=sum+number[y][d]*pow(2,w);
}
if(num==sum)
{
fprintf(fout,"%d\t(15,%d)\n",num,y+1);
return3;
}
}
}
intz=num,c=num;
intm=0;
do//计算是几位二进制数
{
z=z/2;
m++;
}while(z!
=0);
for(n=m;n>0;n--)//将二进制保存于常数表中
{
number[row][n]=c%2;
c=c/2;
}
number[row][0]=m;
intline=row;
fprintf(fout,"%d\t(15,%d)\n",num,line+1);
row++;
return3;
}
else//分析符号
switch(a[i])
{
case'':
case'\n':
return-1;
case'#':
return0;
case'=':
fprintf(fout,"=\t(16)\n");return3;
case'<':
i++;
if(a[i]=='=')
{
fprintf(fout,"<=\t(17)\n");
return3;
}
elseif(a[i]=='>')
{
fprintf(fout,"<>\t(18)\n");
return3;
}
else
{
i--;
fprintf(fout,"<\t(19)\n");
return3;
}
case'>':
i++;
if(a[i]=='=')
{
fprintf(fout,">=\t(20)\n");
return3;
}
else
{
i--;
fprintf(fout,">\t(21)\n");
return3;
}
case'+':
fprintf(fout,"+\t(22)\n");return3;
case'-':
fprintf(fout,"-\t(23)\n");return3;
case'*':
fprintf(fout,"*\t(24)\n");return3;
case'/':
i++;
if(a[i]!
='/'){
i--;
fprintf(fout,"/\t(25)\n");return3;
}
else{
while
(1){
if(a[i++]=='\n')
return-1;
}
fprintf(fout,"//\t(35)\n");return3;
}
case':
':
fprintf(fout,":
\t(26)\n");return3;
case';':
fprintf(fout,";\t(27)\n");return3;
case'(':
fprintf(fout,"(\t(28)\n");return3;
case')':
fprintf(fout,")\t(29)\n");return3;
case'{':
fprintf(fout,"{\t(30)\n");return3;
case'}':
fprintf(fout,"}\t(31)\n");return3;
case'[':
fprintf(fout,"[\t(32)\n");return3;
case']':
fprintf(fout,"]\t(33)\n");return3;
case'|':
fprintf(fout,"|\t(34)\n");return3;
case'"':
fprintf(fout,"\"\t(35)\n");return3;
case',':
fprintf(fout,",\t(36)\n");return3;
case'\'':
fprintf(fout,"'\t(37)\n");return3;//单引号
case'&':
i++;
if(a[i]!
='&'){
i--;
fprintf(fout,"&\t(38)\n");return3;
}
else{
fprintf(fout,"&&\t(39)\n");return3;
}
case'\\':
fprintf(fout,"\\\t(40)\n");return3;
}
}
intmain()
{
printf("************C语言实现编译原理词法分析器************\n\n");
printf("\n");
intl=0;
intm;
i=0;
charinput[100],output[100];//输入文件和输出文件的路径和文件名
printf("请输入词法分析输入的文件名(包括路径):
");
scanf("%s",input);
printf("请输入词法分析输出的文件名(包括路径):
");
scanf("%s",output);
fin=fopen(input,"r");
fout=fopen(output,"w");
if(fin==NULL){
printf("打开词法分析输入文件有错\n");
return
(1);
}
if(fout==NULL){
printf("打开词法分析输出文件有错\n");
return
(2);//返回错误代码2
}
printf("\n--------开始进行词法分析--------\n");
while(!
feof(fin))
{
a[l++]=fgetc(fin);
}
a[l]='#';
do
{
m=wordanalysis();
switch(m)
{
case-1:
i++;break;
case0:
i++;break;
case3:
i++;break;
}
}while(m!
=0);
fclose(fin);
fclose(fout);
printf("\n--------词法分析执行完毕--------\n");
_getch();
return0;
}
4.上机调试时发现的问题,以及解决的过程:
1)文件读取错误。
运行程序后,输入文件路径后,显示“打开词法分析输入文件有错”。
解决:
我看了下程序,没发现什么明显错误,然后看了文件名111.txt,也是对的,点开文件属性,发现文件名显示的是111.txt.txt,意识到机房电脑默认没显示后缀,自己起名字的时候多加了一个.txt;
2)运行过程中强行停止。
解决:
检查了一下程序,发现关键字表数组下标溢出,后来改了循环的条件。
3)运行不能正常停止。
解决:
MS-DOS命令窗口未关闭的时候,检查输出文件是否存在,发现存在但是打开为空,然后关闭运行窗口后再打开发现输出结果已经写入了文件,只是没有执行fclose()所以打开后看不到内容。
4)某些关键字被作为标识符输出。
解决:
检查程序发现关键字表不够完整,所以不能输出不存在于关键字表中的种别码,然后完善了关键字表。
5)单词、数字、符号重复出现时,序号不一致。
解决:
增加了一个标识符表、数字表以及符号表,判断过词性时,先判断一下是否存在于其词性表中,然后在输出。
5.所使用的测试数据及结果:
5.1测试数据:
5.2运行效果
5.3输出结果
实验总结:
通过这次实验,我利用C语言做出了词性分析的程序,理解了该知识点以及学科之间的融合渗透,全面系统的理解了词性分析的具体过程。
把死板的课本知识变得生动有趣,激发了学习的积极性。
我学会了遇到问题独立思考,增强了自己整体的学习能力,把学过的计算机编译原理和C语言的知识强化,能够把课堂上学的知识通过自己设计的程序表示出来,加深了对理论知识的理解。