编译器----词法分析

本文通过学习王博俊、张宇的《DIY Compiler and Linker》 ,实现词法分析器,一方面作为自己的学习笔记,一方面也作与大家分享与交流

代码下载地址

词法分析的任务

源程序由字符序列构成,词法分析器扫描源程序字符串,根据语言的词法规则分析并识别具有独立意义的最小语法单位:单词(包括关键字、运算符、标识符等),并以某种编码形式输出。

词法分析流程图

这次实现的词法分析器完全按照下图所编写:
这里写图片描述

从图中可以看到
1. 先打开源文件,如果无法打开则异常退出
2. 打开源文件后进行初始化,标致行号为第一行,再初始化动态数组,并把运算符、关键字、常量直接放入单词表(单词表是由动态数组和哈希表一起组成的复合结构)
3. 开始读取一个字符,并从第一个字符开始进行“取单词”的工作,如果遇到空白字符或者注释则忽略,如果是有效字符则判断这一单词并给出编号或者标识符索引码
4. 为了能显示出来我们的词法分析,对不同类别的单词进行着色输出到我们屏幕上
5. 循环往复第3、4步直到文件末尾,关闭文件,正常结束

实现词法分析器

1. 自定义动态字符串和动态数组

自定义动态字符串和动态数组是词法分析需要用到的数据结构

  • 首先,常量字符串的长度没办法预知,可能是空串,也可能很长,则需要动态字符串来存储
  • 其次,单词的个数也无法预知,可能只有一个单词,也可能有许多,对于单词的存储,也需要一个按需分配的动态数组

词法分析器是用C语言写的,需要自定义动态字符串和动态数组

1.1 动态字符串

dynstring.h(实际上放在头文件lexical_analysis.h):

/*动态字符串定义*/
typedef struct DynString
{
    int count; //字符串长度
    int capacity; //包含该字符串的缓冲区长度
    char *data; //指向字符串的指针
}DynString;
void dynstring_init(DynString *pstr, int initsize);//初始化动态字符串存储容量,用于dynstring_reset()
void dynstring_free(DynString *pstr);//释放动态字符串使用的内存空间,用于dynstring_reset()
void dynstring_realloc(DynString *cstr, int new_size);//重新分配字符串容量
void dynstring_chcat(DynString *cstr, int ch);//字符串中添加字符
void dynstring_reset(DynString *cstr);//重置动态字符串

dynstring.c:

#include "lexical_analysis.h"


/***********************************************************
*  功能:      初始化动态字符串储存容量
*  pstr:        动态字符串指针
*  initsize:    字符串初始化分配空间
**********************************************************/
void dynstring_init(DynString *pstr, int initsize)
{
    if (pstr != NULL)
    {
   
   
        pstr->data = (char *)malloc(sizeof(char) * initsize);
        pstr->count = 0;
        pstr->capacity = initsize;
    }
}

/***********************************************************
*  功能:  释放动态字符串使用的内存空间
*  pstr:    动态字符串指针
**********************************************************/
void dynstring_free(DynString *pstr)
{
    if (pstr != NULL)
    {
   
   
        if (pstr->data) free(pstr->data);
        pstr->count = 0;
        pstr->capacity = 0;
    }
}

/***********************************************************
*  功能:  重置动态字符串,先释放,重新初始化
*  pstr:    动态字符串指针
**********************************************************/
void dynstring_reset(DynString *pstr)
{
    dynstring_free(pstr);
    dynstring_init(pstr, 10);//初始化字符串分配10个字节空间
}

/***********************************************************
*  功能:      重新分配字符串容量
*  pstr:        动态字符串指针
*  new_size:    字符串新长度
**********************************************************/
void dynstring_realloc(DynString *pstr, int new_size)
{
    int capacity;
    char *data;
    capacity = pstr->capacity;
    while (capacity < new_size)
    {
   
   
        capacity *= 2;//本来分配空间扩大一倍
    }
    data = (char *)realloc(pstr->data, capacity);
    if (!data)//realloc 返回NULL 即分配失败
        error("内存分配失败");
    pstr->capacity = capacity;
    pstr->data = data;
}

/***********************************************************
*  功能:  追加单个字符到动态字符串对象
*  pstr:    动态字符串指针
*  ch:      所要追加的字符
**********************************************************/
void dynstring_chcat(DynString *pstr, int ch)
{
    int count;
    count = pstr->count + 1;
    if (count > pstr->capacity)
        dynstring_realloc(pstr, count);
    pstr->data[count - 1] = ch;
    pstr->count = count;
}
1.2 动态数组

dynarray.h(实际上放在头文件lexical_analysis.h):

/*动态数组定义*/
typedef struct DynArray
{
    int count;//动态数组元素个数
    int capacity;//动态数组缓冲区长度
    void **data;//指向数据指针的数组
}DynArray;

void dynarray_realloc(DynArray *parr, int new_size);//重新分配动态数组容量,用于dynarray_add()函数
void dynarray_add(DynArray *parr, void *data);//追加动态数组元素
void dynarray_init(DynArray *parr, int initsize);//初始化动态数组存储容量
void dynarray_free(DynArray *parr);//释放动态数组使用的内存空间
int dynarray_search(DynArray *parr, int key);//动态数组元素查找

dynarray.c:

#include "lexical_analysis.h"

/***********************************************************
* 功能:       初始化动态数组储存容量
* parr:     动态数组指针
* initsize: 动态数组初始化分配空间
**********************************************************/
void dynarray_init(DynArray *parr, int initsize)
{
    if (parr != NULL)
    {
   
   
        parr->data = (void **)malloc(sizeof(void*) * initsize);
        parr->count = 0;
        parr->capacity = initsize;
    }
}

/***********************************************************
*  功能:  释放动态数组使用的内存空间
*  parr:    动态数组指针
**********************************************************/
void dynarray_free(DynArray *parr)
{
    void **p;
    for (p = parr->data; parr->count; ++p, --parr->count)
    {
   
   
        if (*p)
            free(*p);
    }
    free(parr->data);
    parr->data = NULL;
}
/***********************************************************
*  功能:      重新分配动态数组容量
*  parr:        动态数组指针
*  new_size:    动态数组最新元素个数
**********************************************************/
void dynarray_realloc(DynArray *parr, int new_size)
{
    int capacity;
    void *data;

    capacity = parr->capacity;
    while (capacity < new_size)
        capacity *= 2;
    data = realloc(parr->data, capacity);
    if (!data)
        error("内存分配失败");
    parr->capacity = capacity;
    parr->data = (void **)data;
}

/***********************************************************
*  功能:  追加动态数组元素
*  parr:    动态数组指针
*  data:    所要追加的新元素
*********************************************<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值