史天永221300220词法分析实验.docx

上传人:b****8 文档编号:28981199 上传时间:2023-07-20 格式:DOCX 页数:24 大小:113.60KB
下载 相关 举报
史天永221300220词法分析实验.docx_第1页
第1页 / 共24页
史天永221300220词法分析实验.docx_第2页
第2页 / 共24页
史天永221300220词法分析实验.docx_第3页
第3页 / 共24页
史天永221300220词法分析实验.docx_第4页
第4页 / 共24页
史天永221300220词法分析实验.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

史天永221300220词法分析实验.docx

《史天永221300220词法分析实验.docx》由会员分享,可在线阅读,更多相关《史天永221300220词法分析实验.docx(24页珍藏版)》请在冰豆网上搜索。

史天永221300220词法分析实验.docx

史天永221300220词法分析实验

《编译系统设计实践》

实验项目一:

词法分析实验

学号:

221300220

姓名:

史天永

年级:

2014级

学院:

软件学院

专业:

软件工程

 

实验时间:

2016-2017学年第二学期

任课教师:

陈晖

 

1、程序源代码

#include

#include//isdigit/isalpha/isspace

#include//exit

#include//strcmp

#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

for(inti=0;i

a+=i;

/*annotation*/

doubleb=1.;

doublec=45.5E;

floatd=0.9999;

}

 

3、功能描述

本程序使用C语言编写,用于处理C语言源代码的词法分析,程序读取input.txt中的C语言源代码,然后以[token编号,token]的格式输出各个词法单元到output.txt文件中。

 

4、程序结构描述

本程序里只有main和compare两个函数,main函数是c语言的主函数,里面有一个大的while循环,循环里众多的if和elseif语句用于判断读取到的字符的类型。

compare函数是我自己编写的用于比较两个字符串是否相等的函数,boolcompare(char*str1,char*str2);该函数接收两个char*类型的字符数组地址变量,如果两字符串相同,则返回true,否则返回false

5、符号表的设计和结构

符号表包括:

1保留字2标识符3常数4运算符5分隔符

char*reservedWords[length1]={"if","else","for","while","do","break","continue","int","return"};//保留字表

char*identifiers[length2]={"include","stdio","define","main","printf","scanf"};//标识符表[还包括自定义的变量]

char*operators[length3]={"+","-","*","%",">","<","=","!

","+=","-=","*=","/=","%=",">=","<=","==","!

="};//运算符表

char*splitors[length4]={",",";","{","}","(",")"};//分隔符表

取单词流程图:

6、实验总结

在开始时

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 哲学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1