编译原理词法分析课程设计.docx
《编译原理词法分析课程设计.docx》由会员分享,可在线阅读,更多相关《编译原理词法分析课程设计.docx(28页珍藏版)》请在冰点文库上搜索。
编译原理词法分析课程设计
课程设计
报告题目:
编译原理词法分析
学习中心:
计算机信息工程学院
指导老师:
郜晓晶
学生姓名:
黄正鹏学号:
091014861
专业:
软件工程
2011年12月1日
2011—2012学年第一学期
目录
一、问题描述………………………………………………………………………………………………………2
二、词法分析………………………………………………………………………………………………………2
三、简要分析与概要设计…………………………………………………………………………………………3
四、程序流程图.……………………………………………………………………………………………………4
五、源代码.…………………………………………………………………………………………………………4
六、运行结果………………………………………………………………………………………………………16
七、设计收获与体会………………………………………………………………………………………………19
词法分析程序设计
1.问题描述
本次课程设计要求在Windows环境下使用visualC++软件,采用熟悉的语言,通过设计、编制、调试一个对于C语言词法的词法分析程序,加深对词法分析原理的理解,并实现输出单词序列的词法检查和分析。
2.词法分析
2.1五种单词的文法
<标识符>->l|l<字母数字>
<字母数字>->l|d|l<字母数字>|d<字母数字>
<无符号整数>->d|d<无符号整数>
<运算符>->+|-|*|/|=|<<等号>|><等号>……
<界符>->,|;|(|)|{|}|……
其中l表示a~z中的任何一个英文字母,d表示0~9中的任一个数字。
关键字也是一种单词,一般关键字都是由字母构成,关键字集合时标识符集合的子集。
2.2词法分析方法
从待分析文件中取出当前符号ch=fgetc(fp)
If(Isalpha(ch))
{
读出字符串,放进TOKEN代码中
If(Iskey(token))
{
对不同关键字进行种别码设置
}
else标识符种别码设置
}
elseif(Isdigit(ch))
{
统一设置为一种种别码
数字放入TOKEN代码中
}
elseif(Isoperation(ch))
{
对不同操作符设置不同种别码
将读出的操作符放入TOKEN代码
}
elseif(Isboundrary(ch))
{
设置每种界符的种别码
将读出的界符放入TOKEN代码中
}
2.3符号表设计和TOKEN代码设计
typedefstruct_token_list//记录词法分析结果
{
Tokentoken;
struct_token_list*next;
}TokenNode,*PTokenList;
typedefstruct_symtab{//符号表
charname[10];//名称
chartype[10];//类型
intlength;//长度
intoffset;//相对数
struct_symtab*next;
}sym,*PSYMLIST;
typedefstruct_token//TOKEN代码设计
{
intsym;//种别码
charstr[10];//存放单词
}*PToken,Token;
3.简要分析与概要设计:
设置一个TOKEN结构体,用来存放单词信息,其中包含sym和str[10]两个成员,sym用来存放单词种别码,str[10]数组用来存放单词符号。
设置一个Symtab结构体,用来存放符号表中个变量的信息,其中name[10]用来存放单词名称,type[10]用来存放单词类型,length用来存放单词存储位置信息。
在程序运行之前,先把要分析的程序放在一个.txt记事本中,分析过程中通过ch=fgetc(ch)从文件中读取字符,并进行分析,分析过程见2.2词法分析方法。
对分析之后的单词用二元式进行输出。
接下来进行符号表内容的输出,将已经分析过的关键字,存放在table[]数组中,当遇到分析出的符号为‘;’时,将table[]数组清空。
对分析出的标识符进行判断,如果是第一次分析出,则用symtab.type存放其类型,用symtab.name存放其名称,symtab.length存放其长度,symtab.offset存放其相对数,然后输出符号表信息,如果不是第一次分析出,则输出错误提示。
4.程序主要流程图
5.源代码
#define_CRT_SECURE_NO_WARNINGS//字符串和内存操作时关闭函数的安全警告
#include
#include
#include
intj,n;
charch;
typedefstruct_token
{
intsym;//种别码
charstr[10];//存放单词
}*PToken,Token;
typedefstruct_token_list{//记录词法分析结果
Tokentoken;
struct_token_list*next;
}TokenNode,*PTokenList;
typedefstruct_symtab{//符号表
charname[10];//名称
chartype[10];//类型
intlength;//长度
intoffset;//相对数
struct_symtab*next;
}sym,*PSYMLIST;
char_type[5][10]={"int","float","char","double","long"};//符号表类型
int_size[5]={32,32,8,64,32};//及对应的长度
PSYMLISTsymtab=NULL;//符号表的头指针
PSYMLISTsymtail=symtab;//符号表的尾指针
Tokentoken;
chartype[10]={0};//保存类型名称
PTokenListptl=NULL;//TokenList的头指针
PTokenListptltail=ptl;//TokenList的尾指针
intLineNumber=1;//记录代码行数
intoffset=0;//计算变量偏移地址
voidScan(FILE*);//词法分析
boolIsoperation(charch);//判断i当前所指的字符是否为一个运算符
boolIsboundary(charch);//判断i当前所指的字符是否为一个分界符
boolIskey(charch[]);//判断i当前所指的字符是否为关键字
boolIsalpha(charch);//判断i当前所指的字符是否为字母
boolIsdigit(charch);//判断i当前所指的字符是否为数字
boolIsType(charch[]);//判断是否为类型
intGetSizeOfType(chartype[]);//获得类型大小
intSearchSymTab(charname[]);//查找符号表
voidAddToSymTab(Tokentoken);
voidPrintSymTab();//显示符号表
voidAddToTokenList(Tokentoken);//保存到词法分析表
voidPrintTokenList();//显示词法分析表
//主函数
voidmain()
{
charinput[20];
FILE*fp;
printf("*****************************************\n"
"10~~22----------------表示关键字\n"
"2---------------------表示标识符\n"
"3---------------------表示数字\n"
"40~~57----------------表示操作符\n"
"60~~65----------------表示界符\n"
"*******************************************\n");
printf("pleaseinputthesourcefilename:
");
while(true)
{
gets(input);
if((fp=fopen(input,"r"))!
=NULL)break;//读取文件内容,并返回文件指针,该指针指向文件的第一个字符
else
printf("fileopenfiled!
Pleaseinputagain:
");
}
printf("\n********theresultisasfollows********\n");
while(!
feof(fp))Scan(fp);//扫描源程序
//符号表
PrintSymTab();
//词法分析
PrintTokenList();
getchar();//暂停
}
//判断i当前所指的字符是否为一个运算符,是的话返回真,反之假
boolIsoperation(charch)
{
intt;
chararr[8]={'+','*','/','=','<','>','!
'};
for(t=0;t<8;t++)
if(ch==arr[t])
returntrue;
returnfalse;
}
//判断i当前所指的字符是否为一个分界符,是的话返回真,反之假
boolIsboundary(charch)
{
intt;
chararr[6]={',',';','{','}','(',')'};
for(t=0;t<6;t++)
if(ch==arr[t])
returntrue;
returnfalse;
}
//判断i当前所指的字符是否为一个关键字,是的话返回真,反之假
boolIskey(charch[])
{
intt;
char*keywords[13]={"const","auto","if","else","break","int",
"char","float","long","for","do","printf","case"};
for(t=0;t<13;t++)
if(strcmp(token.str,keywords[t])==0)
returntrue;
returnfalse;
}
boolIsType(charch[])
{
intt;
char*keywords[5]={"int",
"char","float","long","double"};
for(t=0;t<5;t++)
if(strcmp(token.str,keywords[t])==0)
returntrue;
returnfalse;
}
//判断i当前所指的字符是否为字母,是的话返回真,反之假
boolIsalpha(charch)
{
if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))
returntrue;
returnfalse;
}
//判断i当前所指的字符是否为数字,是的话返回真,反之假
boolIsdigit(charch)
{
if(ch>='0'&&ch<='9')
returntrue;
returnfalse;
}
intGetSizeOfType(chartype[])
{
for(inti=0;i<5;i++)
{
if(strcmp(type,_type[i])==0)
{
return_size[i];
}
}
return0;
}
voidAddToSymTab(Tokentoken)
{
PSYMLISTs=(PSYMLIST)malloc(sizeof(sym));
if(s==NULL)return;
memset(s,0,sizeof(sym));
memcpy(s->name,token.str,10);
memcpy(s->type,type,10);
s->length=GetSizeOfType(s->type);
s->offset=offset;
offset+=s->length;
s->next=NULL;
if(symtab==NULL)//如果链表为空则初始化链表
{
symtab=s;
symtail=symtab;
}
else//链表不为空则将节点增加到链表尾部
{
symtail->next=s;
symtail=s;
}
}
intSearchSymTab(charname[])
{
intexist=0;//如果没有找到
intindex=-1;
for(PSYMLISTs=symtab;s!
=NULL;s=s->next)
{
index+=1;
if(strcmp(name,s->name)==0)
exist=1;
}
returnexist?
index:
-1;
}
voidPrintSymTab()
{
printf("符号表:
\n");
printf("名称类型长度相对数\n");
for(PSYMLISTs=symtab;s!
=NULL;s=s->next)
{
printf("%-10s%-10s%-10d%-10d\n",s->name,s->type,s->length,s->offset);
}
}
voidAddToTokenList(Tokentoken)
{
TokenNode*tn=(TokenNode*)malloc(sizeof(TokenNode));
if(tn==NULL)return;
memcpy(&(tn->token),&token,sizeof(Token));
tn->next=NULL;
if(ptl==NULL)
{
ptl=tn;
ptltail=tn;
}
else
{
ptltail->next=tn;
ptltail=tn;
}
}
voidPrintTokenList()
{
printf("词法分析表:
\n");
printf("名称类型\n");
for(PTokenLists=ptl;s!
=NULL;s=s->next)
{
printf("%-10s%-10d\n",s->token.str,s->token.sym);
}
}
voidScan(FILE*fp)
{
token.str[10]=NULL;
j=0;
ch=fgetc(fp);//获取字符,指针fp并自动指向下一个字符
if(ch=='\n')
{
LineNumber++;//记录分析的代码的行号
strcpy(type,"");
}
//分析字符串
if(Isalpha(ch))//判断该字符是否是字母
{
while((ch>='a')&&(ch<='z')||((ch>='A')&&(ch<='Z')))
{
token.str[j++]=ch;
ch=fgetc(fp);
}
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
if(Iskey(token.str))
{
switch(n)//关键字种别码设置
{
case0:
token.sym=10;break;
case1:
token.sym=11;break;
case2:
token.sym=12;break;
case3:
token.sym=13;break;
case4:
token.sym=14;break;
case5:
token.sym=15;break;
case6:
token.sym=16;break;
case7:
token.sym=17;break;
case8:
token.sym=18;break;
case9:
token.sym=19;break;
case10:
token.sym=20;break;
case11:
token.sym=21;break;
case12:
token.sym=22;break;
}
}
else
token.sym=2;//2表示标识符种别码
//printf("(%d,%s)\n",token.sym,token.str);
AddToTokenList(token);
}
elseif(Isdigit(ch))
{
token.sym=3;//3表示数字种别码
while((ch>='0')&&(ch<='9'))
{
token.str[j++]=ch;
ch=fgetc(fp);
}
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
//printf("(%d,%s)\n",token.sym,token.str);
AddToTokenList(token);
}
elseif(Isoperation(ch))//运算符
{
switch(ch)
{
case'=':
token.str[j++]=ch;
token.str[j]='\0';
ch=fgetc(fp);
if(ch=='=')
{
token.sym=40;
token.str[j++]=ch;
token.str[j]='\0';
}
else
{
token.sym=41;
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
}
break;
case'>':
token.str[j++]=ch;
token.str[j]='\0';
ch=fgetc(fp);
if(ch=='=')
{
token.sym=42;
token.str[j++]=ch;
token.str[j]='\0';
}
else
{
token.sym=43;
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
}
break;
case'<':
token.str[j++]=ch;
token.str[j]='\0';
ch=fgetc(fp);
if(ch=='=')
{
token.sym=44;
token.str[j++]=ch;
token.str[j]='\0';
}
else
{
token.sym=45;
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
}
break;
case'!
':
token.str[j++]=ch;
token.str[j]='\0';
ch=fgetc(fp);
if(ch=='=')
{
token.sym=46;
token.str[j++]=ch;
token.str[j]='\0';
}
else
{
token.sym=47;
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
}
break;
case'+':
token.str[j++]=ch;
token.str[j]='\0';
ch=fgetc(fp);
if(ch=='=')
{
token.sym=48;
token.str[j++]=ch;
token.str[j]='\0';
}
elseif(ch=='+')
{
token.sym=49;
token.str[j++]=ch;
token.str[j]='\0';
}
else
{
token.sym=50;
token.str[j++]='\0';//'\0'代表字符结束(空格)
fseek(fp,-1,1);//回退一个字符
}