编译原理:PL0词法分析

来源:互联网 发布:佛山软件行业协会 编辑:程序博客网 时间:2024/05/17 21:06

     这学期开了《编译原理》这门课,任课老师很好,认真负责,我很喜欢,突然认识到自己的编程能力很差,难道女生真的不适合搞计算机吗?(很多人都这么说)我就是要挑战一下自己,不再从网上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);//最终将错误数目报出
}