一、目的

深入了解编译技术中的词法分析,能够用c语言编写一个简单的c语言词法分析器。

二、题目

使用自己熟悉的语言,实现简化版的C语言代码的单词识别。

创新功能:显示标识符和常数数组中已添加的内容。

三、要求

tiger语言词法分析器 简单语言的词法分析器_数组

在设计的状态转换图中,首先对输入串做预处理,即剔除多余的空白符(在实际的词法分析中,预处理还包括剔除注释和制表换行符等编辑性字符的工作),使词法分析工作既简单又清晰。其次,将保留字作为一类特殊的标识符来处理,也即对保留字不专设对应的状态转换图,当转换图识别出一个标识符时就去查对表的前五项,确定它是否为一个保留字。当然,也可以专设一个保留字表来进行处理。

四、实验环境

Windows系统、visual C++ 6.0

五、系统实现

1.思路分析:

    1)主函数中写入一个c语言单词,判断其范围,通过函数指针确定需要做哪一种识别。

    2)按照要求中不同种类将识别分为五种:保留字、标识符、常数、符号、其他。

    3)主函数中对输入的单词识别其首位,从而进入不同种类识别。



    2.实现过程

   1)保留字、标识符、常数、符号、其他五类的定义我将其作为全局变量定义在程序开头。包括函数指针的定义。

    2)五个识别函数我都放在主函数之前,可以偷懒省去,声明的步骤。

    3)保留字识别,判断单词与保留字数组中指向的内容是否相同,相同即输出,若都不相同,转标识符识别。

    4)标识符识别和常数识别类似,一开始数组内为空,先判断单词是否存在,不存在即录入,若已录满,报错。

    5)符号识别,与保留字识别类似。

    6)主函数,通过j=1;while(j)进行循环,直到选择退出(j=0),通过面板选择,实现不同功能。

2.状态转换图


tiger语言词法分析器 简单语言的词法分析器_c语言_02

六、程序运行结果

1.基本单词识别  保留字

tiger语言词法分析器 简单语言的词法分析器_tiger语言词法分析器_03

标识符

tiger语言词法分析器 简单语言的词法分析器_标识符_04

常数

tiger语言词法分析器 简单语言的词法分析器_c语言_05

符号

tiger语言词法分析器 简单语言的词法分析器_标识符_06

其他

tiger语言词法分析器 简单语言的词法分析器_tiger语言词法分析器_07

输入相同的常数或标识符

tiger语言词法分析器 简单语言的词法分析器_c语言_08

显示数组中已添加的内容

tiger语言词法分析器 简单语言的词法分析器_tiger语言词法分析器_09

/* 针对题目及完成的任务要求来设计测试用例 */

七、总结

拿到题目时感觉很容易,以为只要针对输入的单词逐位识别,将其分类即可。而实现过程中却遇到不少问题:

1. 一开始想要输入一条语句,识别出每个单词的种类和种类编码,但怎样将语句分解为单词并保存让我很头疼,查阅资料也没能找到解决办法;

2.数组指针保存数据和重复时报错两者不兼容也没能解决。思考了很久,主函数中入口单词只有一个,所以其地址也唯一,若想保存到数组指针中,必须另外定义变量,赋值后才能保存,而检测重复性时,因为输入单词必与某一变量相同,所以会一直报错,我也没能想到解决方法,只能在调试时,手动更改数组属性,从而完成实验。

3.总结来说,问题主要出现在对字符串的输入、分解、保存不够熟练,对数组知识理解不够深入上,还有就是数据结构学的不好,建立线性表老是不成功,其实数组保存的问题用线性表都能够解决的。

源代码:

#include<stdio.h>//保留字while if else switch case
#include<stdlib.h>
#include<string.h>
#define  in 1
#define  out 0
char *baoliuzi[5]={"while","if","else","switch","case"};
char *biaoshifu[10];           //标识符指针数组,初始状态为空
char *changshu[50];           //常数指针数组,初始状态为空
char *fuhao[8]={"+","-","*","<=","<","==","=",";"};
char *qita[]={"error"};

void (*p)(char a[]);   //函数指针,对输入单词判断类型,从而进行不同类型识别
int m=0,n=0;
void shibie1(char a[])   //保留字
{ void shibie2(char);  //申明标识符函数
int i;
for(i=0;i<=4;i++)
{
 if(strcmp(a,baoliuzi[i])==0)
 {
  printf("%s:\t< %s,_ >\n\n",baoliuzi[i],baoliuzi[i]);
  break;
 }
 
}
if(i==5)
{
 shibie2(a);    //若不为保留字,转识别2
}
}

void shibie2(char a[])  //标识符
{
 int i;
 for(i=0;i<=9;i++)  //避免重复
 {
  if(biaoshifu[i]==a)
  {
   printf("标识符数组中已存在该标识符。内码值为:%d\n\n",&biaoshifu[i]);
   goto lo;
  }
 }
 for(i=0;i<=9;i++)   //数组未满时,录入数据
 {
  if(biaoshifu[i]==0)
  {
   biaoshifu[i]=a;
   printf("为标识符。");
   printf("录入的标识符内码值为:%d,标识符为:%s\n\n",&biaoshifu[i],a);   //地址作为内码值输出
   break;
  }
 }
lo: if(biaoshifu[9]!=0)  //数组已满,禁止输入
 {
  printf("标识符数组已满,禁止输入!\n\n ");
 }
}


void shibie3(char a[])   //常数
{
 int i,j;
 
 for(i=0;i<=49;i++)  //避免重复
 {
  if(changshu[i]==a)
  {
   printf("常数数组中已存在该标识符。内码值为:%d\n\n",&changshu[i]);
   goto lb;
  }
 }
 for(i=0;i<=49;i++)  //常数数组未满,输入数据
 {
  if(changshu[i]==0)
  {
   changshu[i]=a;
   printf("为常数,已录入。\n%s:\t< %s,%d >\n\n",a,a,&changshu[i]);
   break;
  }
 }
lb: if(changshu[9]!=0)  //数组已满,禁止输入
 {
  printf("常数数组已满,禁止输入!\n\n ");
 }
}

oid shibie4(char a[])   //符号
{
 int i;
 for(i=0;i<=7;i++)
 {
  if(strcmp(a,fuhao[i])==0)
  {
   if(i<=2)
   {
    printf("%s:\t< %s,_ >\n\n",a,a);
    break;
   }
   if(i==3)
   {
    printf("%s:\t< relop,LE >\n\n",a);
    break;
   }
   if(i==4)
   {
    printf("%s:\t< relop,LT >\n\n",a);
    break;
   }
   if(i==5)
   {
    printf("%s:\t< relop,EQ >\n\n",a);
    break;
   }
   if(i>=6)
   {
    printf("%s:\t< %s,_ >\n\n",a,a);
    break;
   }
  }
  
 }
}
void shibie5(char a[])   //其他
{
 printf("非法字符,错!\n\n");
}
void main()
{
 int i,j,t;
 char danci[10];
 while(j)
 {
  printf("请输入您想进行的操作(输入其他字符默认为1,进行查询):\n1.查询(输入标识符和常数时自动录入)\n2.显示标识符数组内容(初始为空)\n3.显示常数数组内容(初始为空)\n0.退出\n");
  scanf("%d",&j);
  if(j==1)
  {
   printf("请输入一个单词:\n");
   scanf("%s",&danci);
   if(danci[0]>='a'&& danci[0]<='z') //首位为字母,转标识符(保留字)识别
   {
    p=shibie1;
   }
   else if( danci[0]>='A'&&danci[0]<='Z')  //大写字母,转标识符识别
   {
    p=shibie1;
   }
   else if(danci[0]>='0'&&danci[0]<='9')  //首位为数字,转常数识别
   {
    p=shibie3;
   }
   
   else if(strcmp(danci,fuhao[0])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[1])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[2])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[3])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[4])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[5])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[6])==0)
   {
    p=shibie4;
   }
   else if(strcmp(danci,fuhao[7])==0)    //笨比方法,但为什么写成if(danci=='+')一直不运行?
   {
    p=shibie4;
   }
   else
    p=shibie5;
   p(danci);
  }
  if(j==2)
  {
   for(i=0;i<=9;i++)
   {
    printf("%s",biaoshifu[i]);
   }
  }
  if(j==3)
  {
   for(i=0;i<=49;i++)
   {
    printf("%s",changshu[i]);
   }
  }
 }
}