用python做一个类c编译器——词法分析器

小鸡
阅读850 喜欢6 python 更新2019-5-20

程序创建一个词法类——classword_list,在使用类构造一个示例对象时需传入一个文件名参数。
而后,对象的初始化函数对该源代码进行切割,并返回一个字典,存放单词和单词所在的行号。
接着,初始化函数调用单词分类函数(creat_table)对每个单词进行分类,并且进行括号匹配
最后将分类的单词放进对象的四个成员变量中,也就是四个表。

我的词法分析思维导图

单词类别序号和表序号

输出单词结点有类别,序号等信息

运算符表
y_list = ["+","-","*","/","<","<=",">",">=","=","==","!=","^",",","&","&&","|","||","%","~","<<",">>","!"]
分隔符表
f_list = [";","(",")","[","]","{","}", ".",":",""","#","","","?"]
关键字表
k_list = [
"auto", "break", "case", "char", "const", "continue","default", "do", "double", "else", "enum", "extern",
"float", "for", "goto", "if", "int", "long","register", "return", "short", "signed", "sizeof", "static",
"struct", "switch", "typedef", "union", "unsigned", "void","volatile", "while", "printf"
]
括号配对判断
kuo_cp = {{:}, [:], (:)}

说明:每个关键字的id定义为它在该关键字表中的索引位置,运算符表与分隔符表也是如此

代码注释部分

//开始的行注释,和/*开始*/结束的段注释,对程序没有影响,也忽略.

词法分析程序的功能

输入:所给文法的源程序字符串。
输出:一个自定义的词法类

该词法类定义如下

# 词法分析器输出对象
# 成员变量:输出的单词表,源代码中的分隔符表,运算符表,变量表,关键字表
# 一个方法,将源代码字符切割并存入对应表中
# 对象创建实例需要传入filename参数,默认为test.c
class word_list():
def __init__(self, filename=test.c):
self.word_list = [] # 输出单词列表
self.separator_list = [] # 分隔符
self.operator_list = [] # 运算符
self.name_list = [] # 变量
self.key_word_table = [] # 关键字
self.flag = True # 源代码是否无报错标识
# get_word函数将源代码切割
self.creat_table(get_word(filename))
# 创建各个表
def creat_table(self, in_words):
  1. 成员变量:输出的单词表,源代码中的分隔符表,运算符表,变量表,关键字表
  2. 成员方法:将源代码字符切割并存入对应表中

其中,word_list(输出单词列表)中包含所有答源代码单词,其他表中存放着细分的单词(考虑到后面的程序会用到)

词法分析器由两个python文件组成

  1. Cmp.py 为分析器主函数
  2. Function.py 存放我写的一些单词处理函数,并在cmp.py中导入调用
import re
# 一些判断函数和字符分割函数放在function文件中
from function import if_num, if_name, have_name, printf, get_word

词法分析程序的主要算法思想

程序创建一个词法类——classword_list,在使用类构造一个示例对象时需传入一个文件名参数。
而后,对象的初始化函数对该源代码进行切割,并返回一个字典,存放单词和单词所在的行号。
接着,初始化函数调用单词分类函数(creat_table)对每个单词进行分类,并且进行括号匹配
最后将分类的单词放进对象的四个成员变量中,也就是四个表。

测试用例

  1. 测试一(正确用例):
#include <stdio.h>
int main()
{
// 兰州小红鸡的注释测试
// 这是一条独立行的注释测试
int a,b;
a=0;
b=1; /*
这样的注释测试
*/a=a+b;
printf("%d",a); // 这是一条同行的注释测试
return 0;
/*
多行注释测试
*/
}

输出单词表如下

Line:行号,type:类型,word:单词

{line: 1, type: separator, word: #}
{line: 1, type: name, word: include, id: 0}
{line: 1, type: operator, word: <}
{line: 1, type: name, word: stdio, id: 1}
{line: 1, type: separator, word: .}
{line: 1, type: name, word: h, id: 2}
{line: 1, type: operator, word: >}
{line: 2, type: keyword, word: int}
{line: 2, type: name, word: main, id: 3}
{line: 2, type: separator, word: (}
{line: 2, type: separator, word: )}
{line: 3, type: separator, word: {}
{line: 6, type: keyword, word: int}
{line: 6, type: name, word: a, id: 4}
{line: 6, type: operator, word: ,}
{line: 6, type: name, word: b, id: 5}
{line: 6, type: separator, word: ;}
{line: 7, type: operator, word: =}
{line: 7, type: number, value: 0}
{line: 7, type: separator, word: ;}
{line: 8, type: operator, word: =}
{line: 8, type: number, value: 1}
{line: 8, type: separator, word: ;}
{line: 11, type: keyword, word: printf}
{line: 11, type: separator, word: (}
{line: 11, type: separator, word: "}
{line: 11, type: operator, word: %}
{line: 11, type: name, word: d, id: 6}
{line: 11, type: separator, word: "}
{line: 11, type: operator, word: ,}
{line: 11, type: separator, word: )}
{line: 11, type: separator, word: ;}
{line: 12, type: keyword, word: return}
{line: 12, type: number, value: 0}
{line: 12, type: separator, word: ;}
{line: 16, type: separator, word: }}

输出变量表如下

{line: 1, id: 0, value: 0.0, name: include}
{line: 1, id: 1, value: 0.0, name: stdio}
{line: 1, id: 2, value: 0.0, name: h}
{line: 2, id: 3, value: 0.0, name: main}
{line: 6, id: 4, value: 0.0, name: a}
{line: 6, id: 5, value: 0.0, name: b}
{line: 11, id: 6, value: 0.0, name: d}

其他两个表不再累赘输出

报错处理

括号匹配处理
测试2(错误代码)

#include <stdio.h>
int main()
{
/*
括号匹配错误检测
printf后面多了个括号
*/
printf("hello world"));
return 0;
}

非法变量名处理

测试3(错误代码)

#include <stdio.h>
int main()
{
/*
变量名错误检测
*/
int 7a,8b;
return 0;
}

词法分析器程序

源代码见源文件
源文件结构:

  1. cmp.py 为分析器主函数
  2. function.py 存放我写的一些单词处理函数,并在cmp.py中导入调用

实验环境

  • 编译环境: python3.6
  • 使用库: re

源码见我的GitHub兰州小红鸡