史天永221300220词法分析实验.docx
- 文档编号:16652858
- 上传时间:2023-07-16
- 格式:DOCX
- 页数:24
- 大小:113.60KB
史天永221300220词法分析实验.docx
《史天永221300220词法分析实验.docx》由会员分享,可在线阅读,更多相关《史天永221300220词法分析实验.docx(24页珍藏版)》请在冰点文库上搜索。
史天永221300220词法分析实验
《编译系统设计实践》
实验项目一:
词法分析实验
学号:
221300220
姓名:
史天永
年级:
2014级
学院:
软件学院
专业:
软件工程
实验时间:
2016-2017学年第二学期
任课教师:
陈晖
1、程序源代码
#include
#include
#include
#include
#include
#definelength120
#definelength26
#definelength317
#definelength46
boolcompare(char*str1,char*str2);
voidmain()
{
FILE*fp1=NULL;
FILE*fp2=NULL;
fp1=fopen("input.txt","r");//打开文件
fp2=fopen("output.txt","w");
if(fp1==NULL)
{
printf("找不到文件:
input.txt");
system("pause");
exit
(1);//process.h中的函数
}
//单词类型的编号:
1保留字2标识符3常数4运算符5分隔符
char*reservedWords[length1]={"if","else","goto","for","switch","case","while","do","break","continue","return","int","long","short","const","struct","void","float","double","char"};//保留字表
char*identifiers[length2]={"include","define","main","printf","scanf"};//标识符表[还包括自定义的变量]
char*operators[length3]={"+","-","*","%",">","<","=","!
","+=","-=","*=","/=","%=",">=","<=","==","!
="};//运算符表
char*splitors[length4]={",",";","{","}","(",")"};//分隔符表
charch;//用于存放读取到的字符
charstr[30];//用于存放读取到的单词
for(inti=0;i<30;i++)//清空str[30]
str[i]='\0';
ch=getc(fp1);//getc函数读取文件中的字符
while(ch!
=EOF)
{
//开始判断是否为空白字符,如果是空白字符,则掠过,什么都不做。
isspace用于判断是否为空白字符
if(isspace(ch));
//开始判断是否为注解,如果是注解,则掠过,什么都不做。
elseif(ch=='/')
{
ch=getc(fp1);//再往前读一位才能继续判断
if(ch=='/')//说明该行中发现了一个注解”//“,那么该行之后的字符串就可以省略了
{
char*temp=(char*)malloc(1024);
fgets(temp,1023,fp1);//把该行读取掉,每读一次,读取指针跳到下一行的开头,如果是最后一行,则读取指针指向EOF
free(temp);
}
elseif(ch=='=')//说明读到了运算符/=
{
printf("[4,/=]\n");
}
elseif(ch=='*')//说明读到了/*型的注释开始利用栈来寻找/**/对,情形可能有/*/**//*///**dds*/
{
char*temp=(char*)malloc(1024);//创建一个数组当作栈
intindex=0;
temp[0]='/';//将第一个读到的/*放入栈中
temp[1]='*';
index=2;
while((ch=getc(fp1))!
=EOF)
{
if(ch=='*')//每读到一个*,则判断它上一个字符是否是/,如果是,则读到了一个/*,否则判断它下一个字符是否是/,如果是,则读到了一个*/
{
fseek(fp1,-2L,SEEK_CUR);
ch=getc(fp1);
if(ch=='/')//本次字符*的上一个字符是/,说明读到了一个/*
{
temp[index]='/';index++;//将/*入栈
temp[index]='*';index++;
fseek(fp1,1L,SEEK_CUR);//将读取指针还原回来
}
else
{
fseek(fp1,1L,SEEK_CUR);//将读取指针还原回来
ch=getc(fp1);
if(ch=='/')//本次字符*的下一个字符是/,说明读到了一个*/
{
//这里不用判断栈是否为空,能运行到这里,栈里面必定至少有一个/*
//对于一开始就读到*/这种情况,会被翻译为一个乘号,一个除号,至于是否语法错误,这要在语法分析里再考虑
index-=2;//将栈中栈顶的/*出栈
if(index==0)//每当有/*出栈都要检查栈是否变空,如果为空,说明此次注解扫描告一段落,可以退出while循环了。
break;
}
}
}
}
free(temp);
}
else//如果字符/后面的字符不是/或=或*,说明/是除号
{
printf("[4,/]\n");
if(ch!
=EOF)
fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节
}
}
//开始判断是否为保留字或标识符
elseif(isalpha(ch))//以字母开头,要么是保留字,要么是标识符。
C语言变量组成:
数字、字母、下划线。
做为变量名的开头不能为数字
{
intindex=0;//str字符数组的下标
str[index]=ch;
index++;
ch=getc(fp1);
while(isalpha(ch)||isdigit(ch)||ch=='_')//如果是字母,下划线,则一直往下读,直到读到的字符不是数字、字母或下划线
{
str[index]=ch;
index++;
ch=getc(fp1);
if(index>29)//如果读的变量长度大于30,报错
{
printf("Error!
\n");
exit(0);
}
}
//如果能从while中跳出来,说明单词读完了
str[index]='\0';
if(ch!
=EOF)//如果此时ch为EOF,则当前指针仍然指向EOF,即EOF是终极文件尾,读取指针的最后终点,如果此时再用fseek回退的话,就会出现无限重复的情况
fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节
//开始判断以字母开头字符串是否是保留字
intinfo=0;
for(inti=0;i { if(compare(reservedWords[i],str))//strcmp比较的两字符数组的长度要一致,不然会出现内存溢出的错误 { //fputs("[1,str",fp2); fprintf(fp2,"[1,%s]\n",str);//判断出是保留字,保存到文件 for(inti=0;i<30;i++)//清空str[30] str[i]='\0'; info=1; break; } } if(info==0)//如果不是保留字,那么它肯定就是标识符了,要么是预定义标识符,要么是自定义标识符,反正都是标识符 { fprintf(fp2,"[2,%s]\n",str);//判断出是预定义标识符 for(inti=0;i<30;i++)str[i]=0;//清空str[30] } } //开始判断是否为常量,根据龙书84页的无符号数字的状态转换图,无符号数字有以下6种情况 //digit //digitE±digit //digitEdigit //digit.digit //digit.digitE±digit //digit.digitEdigit elseif(isdigit(ch))//以数字开头,肯定是常量 { intindex=0;//str字符数组的下标 str[index]=ch; index++; ch=getc(fp1); while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } if(ch=='.')//说明是第4、5、6种情况 { str[index]='.'; index++; ch=getc(fp1); if(isdigit(ch))//判断字符.后面是不是数字 { while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } if(ch=='E')//说明是第5、6种情况 { str[index]=ch; index++; ch=getc(fp1); if(ch=='+'||ch=='-')//说明是第5种情况 { str[index]=ch; index++; ch=getc(fp1); while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } //能从while中跳出来,说明第5种情况的字符串已经读完 str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } elseif(isdigit(ch))//说明是第6种情况 { str[index]=ch; index++; ch=getc(fp1); while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } //能从while中跳出来,说明第5种情况的字符串已经读完 str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } else//即E后面既不是±,也不是数字,则报错 { str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"字符串%s有错误! \n",str); } } else//说明是第4种情况 { str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } } else//字符.后面不是数字,所以错误 { str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"字符串%s有错误\n",str); } } elseif(ch=='E')//说明是第2、3种情况 { str[index]=ch; index++; ch=getc(fp1); if(ch=='+'||ch=='-')//说明是第2种情况 { str[index]=ch; index++; ch=getc(fp1); while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } //能从while中跳出来,说明第5种情况的字符串已经读完 str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } elseif(isdigit(ch))//说明是第3种情况 { str[index]=ch; index++; ch=getc(fp1); while(isdigit(ch))//如果是数字,则一直往下读,直到遇到一个非数字的字符 { str[index]=ch; index++; ch=getc(fp1); } //能从while中跳出来,说明第5种情况的字符串已经读完 str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } else//即E后面既不是±,也不是数字,则报错 { str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"字符串%s有错误! \n",str); } } else//说明是第1种情况 { str[index]='\0'; if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[3,%s]\n",str); } } //开始判断是否为运算符[除号/的判断放在注解判断那一块了] elseif(ch=='+'||ch=='-'||ch=='*'||ch=='%'||ch=='>'||ch=='<'||ch=='='||ch=='! ') { str[0]=ch; ch=getc(fp1); if(ch=='=')//如果在+-*%><=后面的是=号,则说明运算符已经读取完毕,而且是双字符的运算符 { str[1]=ch; fprintf(fp2,"[4,%s]\n",str); } else//如果在+-*%><=! 后面的不是=号,则说明运算符已经读取完毕,而且是单字符的运算符 { if(ch! =EOF) fseek(fp1,-1L,SEEK_CUR);//把读取指针从当前位置退回1个字节 fprintf(fp2,"[4,%s]\n",str); } } //开始判断是否为分隔符 elseif(ch==','||ch==';'||ch=='{'||ch=='}'||ch=='('||ch==')') fprintf(fp2,"[5,%c]\n",ch); else { fprintf(fp2,"当前字符%c错误! \n",ch); } ch=getc(fp1); } fclose(fp1); fclose(fp2); } boolcompare(char*str1,char*str2)//垃圾strcmp只能比较长度相同的两个字符串,我只好自己写字符串比较函数 { intlen1=strlen(str1);//strlen()用来计算指定的字符串s的长度,不包括最后一个非空字符后的空白字符""和结束字符"\0" intlen2=strlen(str2);//例如: charstr[30]="hello5555";strlen(str)值为9 if(len1! =len2) returnfalse; else { for(inti=0;i { if(str1[i]! =str2[i]) returnfalse; } returntrue; } } 2、已经通过的测试数据以及截图 测试数据1: main(){ inta;//thisisatest a=10;/*thisisatest*/ } 测试数据2: voidmain(){ inta=10;//thisisatest for(inti=0;i a+=i; /*annotation*/ doubleb=1.5; doublec=45.5E+10; floatd=0.9999; } 测试数据3: voidmain(){ inta=10;//thisisatest
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 史天永 221300220 词法 分析 实验
![提示](https://static.bingdoc.com/images/bang_tan.gif)