Pascal语言子集词法分析器

 

编译原理实验实战
作者: falcon   发表日期: 2006-04-07 17:47  


编译原理课程设计实现



一,概述

1、词法分析
2、语法分析
3、语义分析

相关资料:
1)实验教材信息学院ftp>incoming>教师专用>编译原理>编译原理实验题目
2)其他资料
《程序实现C语言词法分析器的设计》:http://pro.jxyd.net/A921/zhuye/analy1.cpp
3)Lex$yacc使用
http://li2.itpub.net/post/72/64211

二,正文

1,词法分析器

4月21日,花了几个小时的时间,把以前有过一定准备的词法分析器基本完成。
首先介绍词法分析器的流程(由于我太懒,没有重新划,直接copy自老师的课件):

[注:我还不知道这个blog怎么把图片弄上来哦,真是郁闷]

下面简单介绍一下设计过程算拉:

由于编译原理课程中对词法分析的基本原理讲得非常清楚(当然,还是有好多值得思考和探讨的地方哦),甚至都给出了基本的算法,所以我们要做的只是用某一个语言把它实现拉。

我的做法是:

1)理清词法分析的功能

词法分析器又称扫描器,输入源程序,进行词法分析,输出单词符号。
这样我们就弄清楚了词法分析器的基本功能,该过程的输入与输出,接着就是要“如何实现词法分析”,从相应的输入获得相应的输出。

2)词法分析器的设计

这个过程基本上是进一步弄清词法分析器的工作过程,从输入(预处理)——>单词符号的识别(超前搜索)——>画出状态转化图(实现过程流程化)——>实现状态转换图(算法实现,子过程划分等)

3)用某一门具体语言编写代码,算法程序化

我用的是c语言哦,实现的时候还是蛮方便的。不过由于有好长一段时间没有用c,好多语法都有些陌生拉。

总结:

通过词法分析器的设计,发现了自己好多问题,比如由于好长时间没有用c语言进行编程,所以导致无法积累这方面的编程经验。另外,由于该实验两个礼拜以前就已经布置,但我到现在才麻烦完成,说明我对时间的把握还是比较欠缺的。


 

 /*
  ============前言==========================
  SUBJEST:Pascal语言子集词法分析器
  Author:falcon
  announce:版权所有,请尊重知识产权
  =========Pascal语言子集要求===============
  关键字 begin do else end if then var while
  -----------------------------------------
  分界符 , ; . := ( )
  -----------------------------------------
  算术运算符
  (code,运算符)
  10H     +
  11H     -
  20H     *
  21H     /
  ------------------------------------------
  关系运算符
  (code,运算符)
  00H     <
  01H     <=
  02H     =
  03H     >
  04H     >=
  05H     <>
  ------------------------------------------
  字符种类     code type
  关键字     指针,0
  分界符     指针,1
  算术运算符   code,2
  关系运算符   code,3
  标识符     指针,4
  常数表         指针,5
  ===========================================
  */
  /*代码正文*/
  #include <stdio.h>
  #include <string.h>
  #include<process.h>  // exit 包含的头文件

  /*涉及到的字符集*/
  char* key[6]={"begin","if","then","while","do","end"};         
  /*定义关键字*/
  char* par[6]={",",";",".",":=","(",")"};       /*定义分界符*/
  typedef struct                                   /*定义运算符结构体*/
  {
   int ISN;                                 /*内部编码*/                   
      char *Oper;                                 /*值*/
  }Ope;
  Ope
  AriOpe[4]={{10,"+"},{11,"-"},{20,"*"},{21,"/"}},RelOpe[6]={{0,"<"},{1,"="},{2,">"},{3,"<="},{4,">="},{5,"<>"}};
    char mask[200][8],cons[200][8];                 
  /*标识符和常数数组,最好是弄成动态分配*/
  int maski=-1,consi=-1;                             /*上述数组对应的指针*/

  /*词法分析用到的一些变量*/
  char strToken[8],ch,instring[500];         /*字符串、字符、文件缓冲变量*/
  int si=0,searchi=0;                             /*对应的指针*/
  int tempi;                                 /*循环过程中用到指针*/
  /*返回结果形式的结构体*/
  typedef struct
  {    
   int CODE;    
   int TYPE;
  }RetCT;


  /*各个子过程*/
  void GetChar()                                 /*取得一个字符*/
  {
   ch=instring[searchi];
   searchi=searchi+1;
  }             
  
  void GetBC()                               
  /*取得一个字符并且为非空*/
  {
      while(ch==' ') GetChar();
  }

  void Concat()                               
  /*把最近取得的字符(ch)连接到字符串(strToken)*/
  {
   strToken[si]=ch;
   si=si+1;
  }

  int IsLetter()                                 /*判断某个字符是否为字母*/
  {
  if((ch<='Z'&& ch>='A')||(ch<='z'&&ch>='a'))
  return 1;
  else return 0;
  }

  int IsDigit()                                 /*判断某个字符是否为数字*/
  {
  if(ch<='9'&&ch>='0') return 1;
  else return 0;
  }

  int Reserve()                                 /*查找保留字表,返回它的编码*/
  {
   for(tempi=0;tempi<6;tempi++)
   if (strcmp(strToken,key[tempi])==0) {return tempi;}
   return 0;
  }                     
  
  void Retract()                               
  /*回退一个字符,并且置ch为空*/
  {
   searchi=searchi-1;
   ch=' ';
  }

  int InsertId()                               
  /*把strToken插入标识符表,返回标识表指针*/
  {
   for(tempi=0;tempi<maski;tempi++)
   if(strcmp(strToken,mask[tempi])==0){return tempi;}
   maski++;
   strcpy(mask[maski],strToken);
   return maski;
  }

  int InsertConst()                           
  /*将strTken中的常数常数插入常数表,返回常数表指针*/
  {
   for(tempi=0;tempi<consi;tempi++)
   if(strcmp(strToken,cons[tempi])==0){return tempi;}
   consi++;
   strcpy(cons[consi],strToken);
   return consi;
  }

  int GetCode(int type)                           
  /*取得分界符表、算术运算和逻辑运算符表的内部编码或指针*/
  {
   if(type==1)
    {
     for(tempi=0;tempi<6;tempi++)
     if(strcmp(strToken,par[tempi])==0){return tempi;}
     return -1;
    }
   else if(type==2)
    {
     for(tempi=0;tempi<4;tempi++)
     if(ch==AriOpe[tempi].Oper[0]){return AriOpe[tempi].ISN;}
     return -1;
    }
   else if(type==3)
    {
     for(tempi=0;tempi<6;tempi++)
     if(strcmp(strToken,RelOpe[tempi].Oper)==0){return RelOpe[tempi].ISN;}
     return -1;
    }
  }

  /*一次词法分析过程*/
  RetCT CFFX()
  {
   int code,type;
   RetCT Ret;
   si=0;                   /*每次词法分析之前进行初始化*/
   for(tempi=0;tempi<8;tempi++)
   {
    strToken[tempi]=' ';
   }

   GetChar();
   GetBC();
   if(IsLetter())
   {   
    while(IsLetter()||IsDigit())
    {
     Concat();GetChar();
    }        
   Retract();   
   code=Reserve();  
   if(code==0)  
    {   
    code=InsertId(strToken);
    type=4;   
    }    
   else type=0;
   }

   else if(IsDigit())
   {    
    while(IsDigit()) 
    {
     Concat();GetChar();
    }  
    Retract();   
    code=InsertConst(strToken); 
    type=5;
   }

   else if(ch==','||ch==';'||ch=='.'||ch=='('||ch==')'||ch==':')
   {
    type=1;
    Concat();
    GetChar();
    if(ch!='=') Retract();
    else Concat();
    code=GetCode(type);
   }

   else if(ch=='+'||ch=='-'||ch=='*'||ch=='/')
   {
    type=2;
    code=GetCode(type);
   }

   else if(ch=='='||ch=='>'||ch=='<')
   {
    type=3;
    Concat();
    GetChar();
    if(ch!='='&&ch!='>') Retract();
    else Concat();
    code=GetCode(type);
   }
   else code=-1;
   Ret.CODE=code;
   Ret.TYPE=type;
   return Ret;
  }


  /*打开文件读取源代码*/
  void ReadSource()
  {
  FILE *fp;
  char cha;
  if((fp=fopen("F://compiler//program//Pascal.txt","r"))==NULL)         
  /*打开文件,文件名最好是可以输入*/
  {
  printf("cannot open file/n");
  exit(0) ;
  }

  cha=fgetc(fp);
  while(cha!=EOF)
  {    
   if(cha!='/n')   
   {    
    instring[searchi]=cha;   
    searchi=searchi+1; 
   }  
   cha=fgetc(fp);
  }
  fclose(fp);
  instring[searchi]='#';                           
  /*在源代码缓冲区的最后插入一个标记作为结束标志*/
  searchi=0;
  }
  /*主函数过程*/

  int main()
  {
   RetCT RetTmp;
   ReadSource();        /*调用ReadSource()过程获得源代码*/
         /*显示出来*/
   printf("/nThe Source is :/n/n%s/n/nAfter analysing the accidence,The Result is:/n/n",instring);                                           
      /*调用一次词法分析过程进行词法分析*/
   do
   {
    RetTmp=CFFX();
    if(RetTmp.CODE==-1)  
    {
     printf("ERROR!/n");
     break;
    }
    else           
     printf("%d,%d/n",RetTmp.CODE,RetTmp.TYPE);
   }while(instring[searchi]!='#');
   return 1;
  }

 

///

txt  文件内容:

var a:=0;
do
a:=a+1;
while(a<=5);
 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值