用C语言写的Pascal语言词法分析器

虽然只是个词法分析器,但是重拾C语言好难!好久没用过C了。放在这儿勉励自己做事一定要有始有终

/*Trans.c -main,Trans */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//char *name[]={"begin","1","end","2","integer","3","if","4","then","5","else","6","function","7","read","8","write","9"};
//char *sign[]={"=","<>","<=","<",">=",">","-","*",":=","(",")",";"};
int match_code=0;
char buffer1[256];
char buffer2[256];
char *infile;
char* outfile;
char* errfile;
char token[15];
int token_index=0;
char ch;
int buffer1Empty=1;
int buffer2Empty=1;
int EndofFile=0;


//int reserve_(int* code)  //本来自己写了一个比较保留字段的函数,但是不知道什么原因工作不是很良好,鉴于时间很紧就没有用
//{
//     int match=-1;
//     int i=0;
//     while(i!=18)
//     {
//                match=strcmp(name[i],token);
//    i++;
//                if(match==0)
//                {
//                            *code=i;
//                            break;
//                }
//     }
//     return match;            
//}

//void write_dyd(int code,FILE* fp)  //这个是针对上一个函数的写入文件流的函数,同样也放弃了
//{
//    int blank=16-strlen(name[code]);
//    while(blank!=0)
//    {
//       fputc(' ',fp);
//    blank=blank-1;
//    }
// fputs(name[code],fp);
// fputc(' ',fp);
// fputs(name[code+1],fp);
// fputc('/n',fp);
//}
void ReadIntoBuffer(char buffer[256],FILE* fp)
{
     int i;
     char c;
     char tmp;
     for(i=0;i<255;i++)
     {
       c=fgetc(fp);
       switch(c)
       {
        case ' ':
             tmp=c;
             while(c==' ')
                c=fgetc(fp);
             if(c!=EOF)
             {
                if(c!='/t'&&c!=' ')
                   fseek(fp,-1L,1);
                if(buffer[i-1]!=' ')
                   buffer[i]=tmp;
                else
                   i=i-1;
             }
             else
                buffer[i]=EOF;
             break;
        case '/t':
              while(c=='/t')
                 c=fgetc(fp);
              if(c!=EOF)
              {
                 if(c!='/t'&&c!=' ')    //如果非这些字符,就要把文件当前读取位置往前移
                    fseek(fp,-1L,1);                 
                 if(buffer[i-1]!=' ')                 //如果缓冲区的前一个字符不为空格,就要输入一个空格来分开token
                    buffer[i]=' ';
                 else
                    i=i-1;            //因为这轮for循环缓冲区什么也没有修改,而缓冲区的游标又要被加1,所以这里要把i减1
              }
              else
                 buffer[i]=EOF;        //其他情况就把文件结束符写到缓冲区里面去
              break;
  case EOF:
   buffer[i]=EOF;
            break;
        default:
              buffer[i]=c;
     break;
    }
     }
}
int read_buffer(FILE* fp,int* index) //这个函数从两个缓冲区中的一个读出一个字符赋给全局变量ch,缓冲区空则调用ReadInotBuffer函数写入缓冲区
{
  char* readfrom;                    //readfrom是我设的缓冲区数组的指针
  if(buffer1Empty&&!buffer2Empty)       //缓冲区空与否由两个变量buffer1Empty和buffer2Empty来测定
      readfrom=buffer2;
  else
  {
      if(buffer2Empty&&!buffer1Empty)
           readfrom=buffer1;
      else
   {
          if(buffer1Empty&&buffer2Empty)
          {
              readfrom=buffer1;
              ReadIntoBuffer(readfrom,fp);     //第一次读文件时默认填充缓冲区1
          }
   }
  }
  if(readfrom==buffer1)
       buffer1Empty=0;
  else
  {
      if(readfrom==buffer2)
          buffer2Empty=0;
  }
  if(readfrom[*index]!=EOF&&*index<256)
  {
       ch=readfrom[*index];                  //将ch赋值
       *index=*index+1;
  }
  else
  {
      if(readfrom[*index]==EOF)
      {
          return 1;                      //若读到文件尾,则返回1,1在函数translate中被赋给了全局变量EndofFile,这个全局变量控制了整个translate的while循环
      }
      else
          if(*index>255)
          {
              *index=0;
              readfrom=buffer1Empty?buffer1:buffer2;
              ReadIntoBuffer(readfrom,fp);
              if(readfrom==buffer1)
              {
                 buffer1Empty=0;
                 buffer2Empty=1;
              }                                                  
              else
              {
                  if(readfrom==buffer2)
                  {
                     buffer1Empty=1;
                     buffer2Empty=0;
                  }
              }
              ch=readfrom[*index];
              *index=*index+1;
          }
  }
  return 0;
}
void translate(const char *infile,const char *outfile,const char *errfile)         //词法分析器主要功能函数
{
     FILE *ifp = fopen(infile,"r");
     FILE *ofp = fopen(outfile,"a");
     FILE *efp = fopen(errfile,"a");
     int index=0;                            //index为读缓冲区的下标变量
     int line_number=1;
     while(ifp!=NULL&&!EndofFile)
     {
          printf("token now is %s|/n",token);
          EndofFile=read_buffer(ifp,&index);
          if(isdigit((int)ch)&&!EndofFile)
          {
            while(isdigit((int)ch)&&!EndofFile)
            {
               token[token_index]=ch;
               token_index=token_index+1;
               EndofFile=read_buffer(ifp,&index);
            }
            token[token_index]='/0';
            token_index=0;
            index=((index-1)==-1)?255:index-1;     //每个缓冲区为256个字符,若回退下标的时候处在缓冲区头,则切换到上一次读的缓冲区尾
            int blank=16-strlen(token);
            while(blank!=0)
            {
                fputc(' ',ofp);
                blank=blank-1;
            }
            fputs(token,ofp);
            fputc(' ',ofp);
            fputs("11/n",ofp);
            continue;
          }
          if(isalpha((int)ch)&&!EndofFile)
          {
              while((isalpha((int)ch)||isdigit((int)ch))&&!EndofFile)
              {
                  token[token_index]=ch;
                  token_index=token_index+1;
                  EndofFile=read_buffer(ifp,&index);
              }
              token[token_index]='/0';
              token_index=0;
              index=((index-1)==-1)?255:index-1;
              if(!strcmp(token,"begin"))
              {
                 fputs("           begin 1/n",ofp);
                 continue;
              }
              if(!strcmp(token,"end"))
              {
                 fputs("             end 2/n",ofp);
                 continue;
              }
              if(!strcmp(token,"integer"))
              {
                 fputs("         integer 3/n",ofp);
                 continue;
              }
              if(!strcmp(token,"if"))
              {
                 fputs("              if 4/n",ofp);
                 continue;
              }
              if(!strcmp(token,"then"))
              {
                               fputs("            then 5/n",ofp);
                               continue;
              }
              if(!strcmp(token,"else"))
              {
                               fputs("            else 6/n",ofp);
                               continue;
              }
              if(!strcmp(token,"function"))
              {
                                   fputs("        function 7/n",ofp);
                                   continue;
              }
              if(!strcmp(token,"read"))
              {
                         fputs("            read 8/n",ofp);
                         continue;
              }
              if(!strcmp(token,"write"))
              {
                                fputs("           write 9/n",ofp);
                                continue;
              }                                                                   
              else
              {
                  int blank=16-strlen(token);
                  while(blank!=0)
                  {
                      fputc(' ',ofp);
                      blank=blank-1;
                  }
                  fputs(token,ofp);
                  fputc(' ',ofp);
                  fputs("10/n",ofp);
              }
   continue;
          }
          if((ch=='=')&&!EndofFile)
          {
                     fputs("               = 12/n",ofp);
                     continue;
          }
          if((ch=='<')&&!EndofFile)
          {
               EndofFile=read_buffer(ifp,&index);
               if((ch=='=')&&!EndofFile)
               {
                    fputs("              <= 14/n",ofp);
                    continue;
               }
               else
               {
                   if((ch=='>')&&!EndofFile)
                   {
                       fputs("              <> 13/n",ofp);
                       continue;
                   }
                   else
                   {
                       if(!EndofFile)
                       {
                        fputs("               < 15/n",ofp);
                        index=((index-1)==-1)?255:index-1;
                        continue;
                       }
                       else
                       {
                           fputs("             EOF 25/n",ofp);
                           break;
                       }
                   }
               }
          }
          if((ch=='>')&&!EndofFile)
          {
              EndofFile=read_buffer(ifp,&index);
              if((ch=='=')&&!EndofFile)
              {
                 fputs("              >= 16/n",ofp);
                 continue;
              }
              else
              {
                  if(!EndofFile)
                  {
                       index=((index-1)==-1)?255:index-1;
                       fputs("               > 17/n",ofp);
                       continue;
                  }
                  else
                  {
                      fputs("             EOF 25/n",ofp);
                      break;
                  }
              }
          }
          if((ch=='-')&&!EndofFile)
          {
              fputs("               - 18/n",ofp);
              continue;
          }
          if((ch=='*')&&!EndofFile)
          {
              fputs("               * 19/n",ofp);
              continue;
          }
          if((ch==':')&&!EndofFile)
          {
              EndofFile=read_buffer(ifp,&index);
              if((ch=='=')&&!EndofFile)
              {
                  fputs("              := 20/n",ofp);
                  continue;
              }
              else
              {
                  if(!EndofFile)
                  {
                      index=((index-1)==-1)?255:index-1;
                      fprintf(efp,"%d ':' is not defined",line_number);
                      continue;
                  }
                  else
                  {
                      fputs("             EOF 25/n",ofp);
                      break;
                  }
              }
          }
          if((ch=='(')&&!EndofFile)
          {
              fputs("               ( 21/n",ofp);
              continue;
          }
          if((ch==')')&&!EndofFile)
          {
              fputs("               ) 22/n",ofp);
              continue;
          }
          if((ch==';')&&!EndofFile)
          {
              fputs("               ; 23/n",ofp);
              continue;
          }                 
                 
          if((ch=='/n')&&!EndofFile)
          {
              fputs("            EOLN 24/n",ofp);
              line_number=line_number+1;
              continue;
          }
     }
     fputs("             EOF 25/n",ofp);
     fclose(ifp);
     fclose(ofp);
     fclose(efp);
}           
             
     
     
int main(int argc, char *argv[])
{
  switch(argc)                                //处理命令行参数
  {
             case 1:
                  infile="input.txt";         
         outfile="output.txt";
         errfile="error.txt";
         break;
             case 2:
                  infile = argv[1];
                  outfile="output.txt";
         errfile="error.txt";
         break;
             case 3:
                  infile = argv[1];
                  outfile = argv[2];
                  errfile="error.txt";
                  break;
             case 4:
                  infile = argv[1];
                  outfile = argv[2];
                  errfile = argv[3];
                  break;
             default:
                     fprintf(stderr,"usage:Trans [Infile path] [outfile path] [error log path]/n");
                     exit(-1);
  }
  translate(infile,outfile,errfile);
  system("PAUSE"); 
}

 

 

       


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
⒈ 题目 编前述PASCAL子集的词法分析程序。 1)主程序设计考虑,(参阅后面给出的程序框架) 主程序的说明部分为各种表格和变量安排空间。 数组k为关键字表,每个数组元素存放一个关键字。采用定长的方式,较短的关键字后面补空格。 P 数组存放分界符。为了简单起见,分界符、算术运算符和关系运算符都放在p表中(学生编程时,应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。 id 和ci 数组分别存放标识符和常数。 instring 数组为输入源程序的单词缓存。 outtoken 记录为输出内部表示缓存。 还有一些为造表填表设置的变量。 主程序开始后,先以人工方式输入关键字,造 k 表;再输入分界符等造 p 表。 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。 2)词法分析过程考虑 该过程取名为 lexical,它根据输入单词的第一个字符(有时还需读第二个字符),判断单词类,产生类号:以字符k表示关键字;i表示标识符;c 表示常数;p 表示分界符;s 表示运算符(学生编程时类号分别为1,2,3,4,5)。 对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组 id 中,将常数变为二进制形式存入数组中 ci 中,并记录其在表中的位置。 lexical 过程中嵌有两个小过程:一个名为 getchar,其功能为从 instring 中按顺序取出一个字符,并将其指针 pint 加 1 ;另一个名为 error,当出现错误时,调用这个过程,输出错误编号。 将词法分析程序设计成独(入口)立一遍扫描源程序的结构。其流程图见图5-1。 图5-1 词法分析程序流程图 ⒉ 要求 ⑴ 所有识别出的单词都用两个字节的等长表示,称为内部码。第一个字节为 t ,第二个字节为 i 。 t 为单词的种类。关键字的 t=1;分界符的 t=2;算术运算符的 t=3;关系运算符的 t=4;无符号数的 t=5;标识符的 t=6。i 为该单词在各自表中的指针或内部码值。表 5-1 为关键字表;表 5-2 为分界符表;表 5-3 为算术运算符的 i 值;表 5-4 为关系运算符的 i 值。 表5-1 关键字表 表5-2 分界符表 指针1 关键字 指针1 分界符 0 BEGIN 0 , 1 DO 1 ; 2 ELSE 2 . 3 END 3 := 4 IF 4 ( 5 THEN 5 ) 6 VAR 7 WHILE 表5-3 算术运算符 表5-4 关系运算符 i 值 算术运算符 i 值 关系运算符 00H < 10H + 01H 21H / 04H >= 05H 常数表和标识符表是在编译过程中建立起来的。其 i 值是根据它们在源程序中出现的顺序确定的。 ⑵ 常数分析程序、关键字和标识符分析程序、其他单词分析程序请参阅范例自行设计。 ⑶ 本实践题可通过扩充下面给出的程序框架完成。 PROGRAM plexical(input,output); LABEL l; CONST keylen=10; identlen=10; TYPE //定义的类型 tstring=ARRAY[1..identlen] OF char; outreco=RECORD//记录为输出内部表示缓存。 ty: char; point: integer; END; {outreco} VAR cip,ip,pint,i,j,l,m,errorx:integer; charl:CHAR; ci:ARRAY[1..10] OF integer; k,id:ARRAY[1..keylen] OF tstring; token:tstring; //标志符 outtoken:outreco; instring:ARRAY[1..10]OF char; p:ARRAY[1..16] OF ARRAY [1..2] OF char; PROCEDURE lexical; VAR l,m,num:integer; b: boolean; PROCEDURE
C语言一个只包含部分保留字和单词符号(见语言子集L)的PASCAL语言的扫描器(词法分析器)。 1、该词法分析器的任务: (1)滤掉源程序中的无用成分,如空格; (2)输出分类记号供语法分析器使用,并产生两个表格:常数表和标识符表,表的数据结构和包含内容可参看书中第八章符号表; (3)识别非法输入,并将其标记为“出错记号”。 2、该词法分析器的功能: 以在下面段落中定义的PASCAL语言子集的源程序作为词法分析程序的输入数据。词法分析器打开该文件后,自文件头开始扫描源程序字符,发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查填适当的信息表,一旦发现不符合“单词”定义的源程序字符串时,给出错误提示。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。 3、PASCAL语言子集L----保留字不区分大小 L={ VAR,BEGIN,ELSE,END,IF,THEN,REAL,INTEGER,=,:=,-,+,*,; ,. }∪{常数}∪{标识符} 4、实验要求: (1)词法分析器构造:正规式设计、DFA设计、代码编; (2)进行词法分析器的测试:测试例程(一小段程序)、测试结果与测试结果分析。 (3)实验报告格式自拟;实验报告中要对实验要求中正规式设计、DFA设计、代码编、测试例程(3中定义的PASCAL语言子集的源程序段)、测试结果与测试结果分析逐项给予说明。 例子: 本例中单词符号(记号)的种类: 1、保留字; 2、分隔符; 3、运算符; 4、等符 5、常数; 6、标识符 (单词符号的分类可以自己规定,只是要在实验报告中给出说明) 测试例程PASCAL程序清单如下: BEGIN IF I=1 THEN ^ A:=I+1 ELSE *& IF I=2 THEN A:=I+11; END. # 运行词法分析程序后,显示如下结果如下: BEGIN (1,1) IF (1,4) I (6,0) = (4,2) 1 (5,0) THEN (1,5) ^ error, not a word A (6,1) := (2,2) I (6,0) + (3,0) 1 (5,0) ELSE (1,2) * (3,2) & error, not a word IF (1,4) I (6,0) = (4,2) 2 (5,1) THEN (1,5) A (6,1) := (2,2) I (6,0) + (3,0) 11 (5,2) ; (2,1) END (1,3) . (2,3) # error, not a word over 常数表CT:1,2 标识符表LT:I,A

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值