这学期开了《编译原理》这门课,任课老师很好,认真负责,我很喜欢,突然认识到自己的编程能力很差,难道女生真的不适合搞计算机吗?(很多人都这么说)我就是要挑战一下自己,不再从网上copy,自己编词法分析。不知熬了多少夜,下了多少工夫,终于调试成功,那种胜利的喜悦,已经好久没有体会到了!
以下就是我的成果,有不足的地方就请高人指点啊!
#include<stdio.h>
#include<string.h>
#include "pl0.h"
void init()
{
/*将保留字存入保留字表*/
strcpy(word[0],"BEGIN");
strcpy(word[1],"CALL");
strcpy(word[2],"CONST");
strcpy(word[3],"DO");
strcpy(word[4],"END");
strcpy(word[5],"IF");
strcpy(word[6],"ODD");
strcpy(word[7],"PROGRAM");
strcpy(word[8],"PROCEDURE");
strcpy(word[9],"READ");
strcpy(word[10],"THEN");
strcpy(word[11],"VAR");
strcpy(word[12],"WHILE");
strcpy(word[13],"WRITE");
strcpy(word[14],"ELSE");
strcpy(word[15],"REPEAT");
strcpy(word[16],"UNTIL");
/*存入保留字的单词类别值,顺序与保留字表中的顺序一致*/
wsym[0]="BEGINSYM";
wsym[1]="CALLSYM";
wsym[2]="CONSTSYM";
wsym[3]="DOSYM";
wsym[4]="ENDSYM";
wsym[5]="IFSYM";
wsym[6]="ODDSYM";
wsym[7]="PROGSYM";
wsym[8]="PROCSYM";
wsym[9]="READSYM";
wsym[10]="THENSYM";
wsym[11]="VARSYM";
wsym[12]="WHILESYM";
wsym[13]="WRITESYM";
wsym[14]="ELSESYM";
wsym[15]="REPEATSYM";
wsym[16]="UNTILSYM";
/*将界符存入表中*/
symbol[0]='+';
symbol[1]='-';
symbol[2]='*';
symbol[3]='/';
symbol[4]='(';
symbol[5]=')';
symbol[6]='=';
symbol[7]=';';
symbol[8]=',';
symbol[9]='.';
symbol[10]='#';
/*将界符类别值存入表中*/
ssym[0]="PLUS";// +
ssym[1]="MINUS";// -
ssym[2]="MULTIPLY";// *
ssym[3]="DIVISION";// /
ssym[4]="LPARENT";// ;
ssym[5]="RPARENT";// )
ssym[6]="EQL";// =
ssym[7]="SEMICOLON";// ;
ssym[8]="COMMA";// ,
ssym[9]="PERIOD"; // .
ssym[10]="NEQ";// #
}
void error(int n)
{
switch(n)
{
case 1: printf("/"%s/" is a illegal ident!/n",errid);
fprintf(fout,"(%-10s 非法)/n",errid);
break;
case 2: printf("/"%s/" is a illegal number!/n",errid);
fprintf(fout,"(%-10s 非法)/n",errid);
break;
case 3: if(A>0&&A<254)
{
printf("/"%c/" is a illegal symbol!/n",ch);
fprintf(fout,"(%-10c 非法)/n",ch);
break;
}else
{
fprintf(fout,"(%-10x 非法)/n",&ch);
printf("%x unknown character!/n",&ch);
break;
}
default :printf("error!/n");
}
}
void getachar() //检查ch是否为空白符,若是,继续取下一个字符,直至不为空
{
while(ch==' ')
{
ch=fgetc(fin);
}
}
int lower() //判断ch是否为小写字母
{
if(ch>='a'&&ch<='z')
return 1;
else
return 0;
}
int upper()//判断ch是否为大写字母
{
if(ch>='A'&&ch<='Z')
return 1;
else
return 0;
}
int digit() //判断ch是否为数字
{
if((ch>='0')&&(ch<='9'))
return 1;
else
return 0;
}
void findident()//判断是保留字还是标识符,并对应各自类别值存入名字表
{
int i;
strcpy(id,a);
for(i=0;i<keynum;i++)
{
if(strcmp(id,word[i])==0)
{
strcpy(sym,wsym[i]);
fprintf(fout,"( %10s)/n", sym);
break;
}
}
if(i>=keynum)
{
strcpy(sym,"IDENT");
fprintf(fout,"(%-10s%10s)/n",id,sym);
}
}
void othersym()//判断单字符是否为单界符
{
int i,k=0;
a[k]=ch;
k++;
if(ch!=' '&&ch!=10&&ch!=9&&!feof(fin))
{
for(i=0;i<signum;i++)
{
if(ch==symbol[i])
{
a[k]='/0';
strcpy(id,a);
strcpy(sym,ssym[i]);
fprintf(fout,"(%-10s%10s)/n",id,sym);
break;
}
}
if(i>=signum)
{
errnum++;
A=a[k-1];
error(3);
}
}
}
void getid()//获取单词
{
int k=0,i;
A=' ';
number=0;
for(i=0;i<sizeof(errid);i++)
{
errid[i]=' ';
}
ch=fgetc(fin);
getachar();//获取单词首个非空字符
if(upper()||lower())//首字符为字母,则可能为保留字或标识符
{
while(digit()||upper()||lower())
{
if(k<alphalen)
{
a[k]=ch;
errid[k]=ch;
ch=fgetc(fin);
k++;
}else
break;
}
if(k<alphalen)
{
a[k]='/0';
fseek(fin,-1L,1);
findident();
}
else
{
while(digit()||lower()||upper())
{
errid[k]=ch;
ch=fgetc(fin);
k++;
}
errid[k]='/0';
fseek(fin,-1L,1);
errnum++;
error(1);
}
}
else//首字符不为字母
if(digit())//若首字符为数字,则可能为数值
{
while(digit())
{
a[k]=ch;
errid[k]=ch;
ch=fgetc(fin);
k++;
}
if(k<nummax)
{
if(lower()||upper())
{
while((digit()||lower()||upper())&&ch!=' '&&ch!=10&&ch!=9&&!feof(fin))
{
errid[k]=ch;
ch=fgetc(fin);
k++;
}
errid[k+1]='/0';
fseek(fin,-1L,1);
errnum++;
error(2);
}else{
a[k]='/0';
strcpy(id,a);
fseek(fin,-1L,1);
strcpy(sym,"NUMBER");
fprintf(fout,"(%-10s%10s)/n",id,sym);
}
}else{
while((digit()||lower()||upper())&&ch!=' '&&ch!=10&&ch!=9&&!feof(fin))
{
errid[k]=ch;
ch=fgetc(fin);
k++;
}
errid[k]='/0';
fseek(fin,-1L,1);
errnum++;
error(2);
}
}else//首字符不是字母也不是数字,则只可能为界符,否则为非法字符
{
switch(ch)
{
case '<': a[k]=ch;
ch=fgetc(fin);
k++;
if(ch=='=')
{
a[k]=ch; k++; a[k]='/0';
strcpy(id,a);
strcpy(sym,"lsseql");
fprintf(fout,"(%-10s%10s)/n",id,sym);
break;
}else
{
a[k]=ch; k++; a[k]='/0';
strcpy(id,a);
strcpy(sym,"deql");
fprintf(fout,"(%-10s%10s)/n",id,sym);
break;
}
case '>': a[k]=ch;
ch=fgetc(fin);
k++;
if(ch=='=')
{
a[k]=ch; k++; a[k]='/0';
strcpy(id,a);
strcpy(sym,"greql");
fprintf(fout,"(%-10s%10s)/n",id,sym);
break;
}else{
fseek(fin,-1L,1);
a[k]='/0';
strcpy(id,a);
strcpy(sym,"grthan");
fprintf(fout,"(%-10s%10s)/n",id,sym);
break;
}
default : othersym();break;
}
}
}
void main()
{
A=' ';
ch=' ';//ch初值为空
init();//初始化
printf("please input the name of the source file: ");
scanf("%s",fname);
fin=fopen(fname,"r");//以只读方式打开文件fname
fout=fopen("fout.txt","w");//以只写方式打开文件fout.txt,若没有则新建,若存在,则先将其删除,重新建立
if(!fout)
{
printf("can't open the file /"%s/" !/n","fout.txt");
}
if(fin)
{
while(ch!=EOF)//文件结束前重复循环,识别单词
{
getid();
}
}else{
printf("can't open the file /"%s/" ,or it is not exists !/n",fname);
}
printf("there are %d errors !/n/n",errnum);//最终将错误数目报出
}