词法分析器C语言版.docx
《词法分析器C语言版.docx》由会员分享,可在线阅读,更多相关《词法分析器C语言版.docx(16页珍藏版)》请在冰豆网上搜索。
词法分析器C语言版
/**********************************************
*名称:
词法分析器
*版本:
1.0
*作者:
**
*2015/4/2
************************************************/
#include
#include
#include
#include
#include
#defineLENGTH110//typereservedwordsize
FILE*fp=NULL;//outstreamPointer
FILE*fw=NULL;//instreampointer
charcharacter;
chartoken[32];//Thecharacterarraytostorethesequenceofcharacters,hasbeenread.
//Codetable
char*CODE[]={"identifier","constant","keyword","+","-","*","/",">","<",">=","<=","!
=","=","==",
"(",")","[","]","{","}","&","||","!
",",",";",".",":
","\"","%","#","\'"};
//keywordtable
char*k[]={"for","while","do","go","to","switch","if","else","int","float","char","static","break",
"exit","continu","error"};
//标识符结构体
typedefstruct
{
char*I[256];//标识符数组
intlen;//标识符数量
}identifier;
//常量结构体
typedefstruct{
intcont[300];//存放常量的数组
intlen;//常量的数目
}constnumber;
//读入一个字符,从输入流中读入一个字符到变量character中。
voidgetNextChar(FILE*ifp)
{
if((character=getc(ifp))==EOF)
exit
(1);
}
//读入非空白字符,检查变量character中的字符是否为空白字符或回车或换行符。
若是,
//则调用getNextChar()读入下一个字符,直到character中的字符满足条件.
voidgetnbc(FILE*ifp)
{
while(character==''||character=='\n'||character==9)
{
getNextChar(ifp);
}
}
//连接字符串,把character中的字符连接到token数组的结尾。
voidconcat()
{
char*ct=&character;
strcat(token,ct);
}
//判断是否为字母。
intletter()
{
returnisalpha(character);
}
//判断是否为数字
intdigit()
{
returnisdigit(character);
}
//回退字符,将刚读入的character中的字符回退到输入流中。
并把character中的值置为空。
voidretract(FILE*ifp)
{
(ifp->_cnt)++;
(ifp->_ptr)--;
character='';
}
//处理保留字,对存放在token中的字符串查保留字,若查到,则返回该保留字的类别编码,否则返回0.
intreserve(char**k)
{
inti;
for(i=0;iif(strcmp(token,k[i])==0)
returni+1;
return0;
}
//处理标识符,对存放在token中的字符串查找符号表,若查到,则返回它在符号表的位置,
//存入常数表中,并返回它在常数表中的位置编号。
intsymbol(identifier*id)
{
inti;
for(i=0;ilen;i++)
if(strcmp(token,id->I[i])==0)
returni+1;
if(id->len>256)
assert(0);
id->I[id->len]=token;
id->len++;
returnid->len;
}
//将数字字符串转化为整数。
intstrtonumber()
{
inti;
intsum=0;
for(i=0;i{
sum=10*sum+(token[i]-'0');
}
returnsum;
}
//常数存入常数表的函数,将token中的数字串(实际上是字符串),转化成标准的二进制值(整数值)
//存入常数表中,并返回它在常数表中的位置编号。
intconstant(constnumber*con)
{
con->cont[con->len]=strtonumber();
con->len++;
returncon->len;
}
//将整数值转化为字符串
char*numbertoString(intnum)
{
chars[3];
inti=num/10;
while(i>0)
{
charc=i+'0';
strcat(s,&c);
}
returns;
}
//将结果写入到文件并且输出到屏幕。
voidreturntofile(intnum,intval,identifier*id,constnumber*con)
{
inti;
int_num=num;
charc;
c='(';
putc(c,fw);
printf("%c",c);
i=_num/10;
while(i>0)
{
_num=_num-10*i;
c=(i+'0');
printf("%c",c);
putc(c,fw);
i=_num/10;
}
c=_num+'0';
printf("%c",c);
putc(c,fw);
printf(",");
putc(',',fw);
//如果是标识符或常数则放入括号内。
if(num==1)//处理标识符
{
printf("%s",id->I[val-1]);
printf(")");
printf("\n");
fputs(id->I[val-1],fw);
putc(')',fw);
putc('\n',fw);
}
if(num==2)//处理常数
{
_num=con->cont[val-1];
i=_num/10;
while(i>0)
{
_num=_num-10*i;
c=(i+'0');
printf("%c",c);
putc(c,fw);
i=_num/10;
}
c=_num+'0';
printf("%c",c);
printf(")");
printf("\n");
putc(c,fw);
putc(')',fw);
putc('\n',fw);
}
if(num==3)//保留字
{
printf("-");
printf(")");
printf("");
printf("|");
printf("%s",k[val-1]);
printf("|");
printf("\n");
putc('-',fw);
putc(')',fw);
fputs("",fw);
putc('#',fw);
fputs(k[val-1],fw);
putc('#',fw);
putc('\n',fw);
}
if(num>3)//处理界符
{
printf("-");
printf(")");
printf("");
printf("|");
printf("%s",CODE[num-1]);
printf("|");
printf("\n");
putc('-',fw);
putc(')',fw);
fputs("",fw);
putc('#',fw);
fputs(CODE[num-1],fw);
putc('#',fw);
putc('\n',fw);
}
}
//将错误写入到文件或输出到屏幕
voiderror()
{
printf("(ERROR,");
printf("%c",character);
printf(")");
printf("\n");
fputs("(ERROR,",fw);
putc(character,fw);
putc(')',fw);
putc('\n',fw);
}
//词法分析函数
voidLexAnalyze(char**k,char**CODE,identifier*id,constnumber*con,FILE*fp,FILE*fw)
{
intnum,val;
strcpy(token,"");
getNextChar(fp);
getnbc(fp);
switch(character)
{
case'a':
case'b':
case'c':
case'd':
case'e':
case'f':
case'g':
case'h':
case'i':
case'j':
case'k':
case'l':
case'm':
case'n':
case'o':
case'p':
case'q':
case'r':
case's':
case't':
case'u':
case'v':
case'w':
case'x':
case'y':
case'z':
case'A':
case'B':
case'C':
case'D':
case'E':
case'F':
case'G':
case'H':
case'I':
case'J':
case'K':
case'L':
case'M':
case'N':
case'O':
case'P':
case'Q':
case'R':
case'S':
case'T':
case'U':
case'V':
case'W':
case'X':
case'Y':
case'Z':
while(letter()||digit())
{
concat();
getNextChar(fp);
}
retract(fp);
num=reserve(k);//保留字
if(num!
=0)
returntofile(3,num,id,con);
else
{
val=symbol(id);
returntofile(1,val,id,con);
}
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
while(digit())
{
concat();
getNextChar(fp);
}
retract(fp);
val=constant(con);
returntofile(2,val,id,con);
break;
case'<':
getNextChar(fp);
if(character=='=')
returntofile(9,0,id,con);
else
{
retract(fp);
returntofile(8,0,id,con);
}
break;
case'>':
getNextChar(fp);
if(character=='=')
returntofile(11,0,id,con);
else
{
retract(fp);
returntofile(10,0,id,con);
}
break;
case'=':
getNextChar(fp);
if(character=='=')
returntofile(13,0,id,con);
else
{
retract(fp);
returntofile(14,0,id,con);
}
break;
case'!
':
getNextChar(fp);
if(character=='=')
returntofile(12,0,id,con);
else
error();
break;
case'+':
returntofile(4,0,id,con);
break;
case'-':
returntofile(5,0,id,con);
break;
case'*':
returntofile(6,0,id,con);
break;
case'/':
returntofile(7,0,id,con);
break;
case'(':
returntofile(15,0,id,con);
break;
case')':
returntofile(16,0,id,con);
break;
case',':
returntofile(17,0,id,con);
break;
case':
':
returntofile(18,0,id,con);
break;
case';':
returntofile(19,0,id,con);
break;
case'{':
returntofile(20,0,id,con);
break;
case'}':
returntofile(21,0,id,con);
break;
case'\"':
returntofile(22,0,id,con);
break;
case'\\':
returntofile(23,0,id,con);
break;
case'\'':
returntofile(23,0,id,con);
break;
case'#':
returntofile(25,0,id,con);
break;
case'%':
returntofile(26,0,id,con);
break;
case'|':
returntofile(27,0,id,con);
break;
case'&':
returntofile(28,0,id,con);
break;
case'.':
returntofile(29,0,id,con);
break;
case'==':
returntofile(32,0,id,con);
break;
case'!
=':
returntofile(33,0,id,con);
break;
case'[':
returntofile(34,0,id,con);
break;
case']':
returntofile(35,0,id,con);
break;
default:
error();
}
}
main(intargc,char*argv[])
{
//初始化标识符和常数结构体
identifier*id=(identifier*)malloc(sizeof(identifier));
constnumber*con=(constnumber*)malloc(sizeof(constnumber));
con->len=0;
id->len=0;
argc=3;
argv[1]="E:
\\file1.txt";//待分析的文件
argv[2]="E:
\\file2.txt";//保存分析结果的文件
//从打开目标文件流
if((fp=fopen(argv[1],"r"))==NULL)
{
printf("cat:
can'topen%s\n",*argv);
return1;
}
//打开要写二元式的文件流
if((fw=fopen(argv[2],"w"))==NULL)
{
printf("cat:
can'topen%s\n",argv[2]);
return1;
}
while(!
feof(fp))
{
LexAnalyze(k,CODE,id,con,fp,fw);//执行词法分析
}
//关闭流
fclose(fp);
fclose(fw);
return0;
}