手写一个词法分析器(下)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 最近大部分时间都在撸 Python,其中也会涉及到将数据库表转换为 Python 中 ORM 框架的 Model,但我们并没有找到一个合适的工具来做这个意义不大的”体力活“,所以每次新建表后大家都是根据自己的表结构手写一遍 Model。 一两张表还好,一旦 10 几张表都要写一遍时那痛苦只有自己知道;这时程序员的 slogan 再次印证:一切毫无意义的体力劳动终将被计算机取代。

DDL 解析


简单的解析完成后来看看 DDL 这样的脚本应当如何解析:


CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(20) DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) DEFAULT NULL COMMENT '密码',
  `roleId` int(11) DEFAULT NULL COMMENT '角色ID',
  PRIMARY KEY (`id`),  
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8


原理类似,首先还是要看出规律(也就是语法):


  • 表名是第一行语句,同时以 CREATE TABLE 开头。


  • 每一个字段的信息(名称、类型、长度、备注)都是以 "`" 符号开头 "," 结尾。


  • 主键是以 PRIMART 字符串开头的字段,以 ) 结尾。


根据我们需要解析的数据种类,我这里定义了这个枚举:



然后在初始化类型时进行判断赋值:



由于需要解析的数据不少,所以这里的判断条件自然也就多了。


递归解析


针对于 DDL 的语法规则,我们这里还有需要有特殊处理的地方;比如解析具体字段信息时如何关联起来?


举个例子:


`userName` varchar(20) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',


这里我们解析出来的数据得有一个映射关系:



所以我们只能一个字段的全部信息解析完成并且关联好之后才能解析下一个字段。


于是这里我采用了递归的方式进行解析(不一定是最好的,欢迎大家提出更优的方案)。


} else if (value == '`' && pStatus == Status.BASE_INIT) {
    result.tokenType = DDLTokenType.FI;
    result.text.append(value);
} 


当当前字符为 ”`“ 符号时,将状态置为 "FI"(FieldInfo),同时当解析到为 "," 符号时便进入递归处理。



可以理解为将这一段字符串单独提取出来处理:


`userName` varchar(20) DEFAULT NULL COMMENT '用户名',


接着再将这段字符递归调用当前方法再次进行解析,这时便按照字段名称、类型、长度、注释的规则解析即可。


同时既然存在递归,还需要将子递归的数据关联起来,所以我在返回结果中新增了一个 pid 的字段,这个也容易理解。


默认值为 0,一旦递归后便自增 +1,保证每次递归的数据都是唯一的。


用同样的方法在解析主键时也是先将整个字符串提取出来:


PRIMARY KEY (`id`)


只不过是 "P" 打头 ")" 结尾。


} else if (value == 'P' && pStatus == Status.BASE_INIT) {
    result.tokenType = DDLTokenType.P_K;
    result.text.append(value);
} 



也是将整段字符串递归解析,再递归的过程中进行状态切换 P_K ---> P_K_V 最终获取到主键。



所以通过对刚才那段 DDL 解析得到的结果如下:



这样每个字段也通过了 pid 进行了区分关联。


所以现在只需要对这个词法解析器进行封装,便可以提供一个简单的 API 来获取表中的数据了。



总结


到此整个词法解析器的全部内容都已经完成了。


但这还只是整个编译语言知识点的冰山一角,后续还有语法、语义、中间、目标代码等一系列内容。


本文所有源码及插件地址:


github.com/crossoverJi…


相关文章
|
2月前
|
自然语言处理 算法 前端开发
编译原理 - 词法分析
编译原理 - 词法分析
46 0
|
11月前
|
自然语言处理 前端开发 算法
编译原理 (二)词法分析、语法分析、语义分析以及中间代码生成器的基本概念
编译原理 (二)词法分析、语法分析、语义分析以及中间代码生成器的基本概念
632 0
|
1月前
|
自然语言处理 容器
S语言词法分析器设计
还有很多需要优化的地方,作为小白发出了也和大家一起交流下,这次我是分文件写的,因为考虑到以后的实验都用这一套代码,分文件写方便一点,用的是C++14标准
14 0
|
2月前
|
自然语言处理
【编译原理】词法分析
【编译原理】词法分析
36 0
|
2月前
|
索引
12 # 手写 findIndex 方法
12 # 手写 findIndex 方法
32 0
|
2月前
|
索引
09 # 手写 some 方法
09 # 手写 some 方法
23 0
|
2月前
|
索引
10 # 手写 every 方法
10 # 手写 every 方法
26 0
|
自然语言处理 C语言 C++
编译原理 实验二:词法分析器的手动实现(基于状态机的词法分析器)
编译原理 实验二:词法分析器的手动实现(基于状态机的词法分析器)
901 0
编译原理 实验二:词法分析器的手动实现(基于状态机的词法分析器)
|
存储 自然语言处理 Unix
编译原理 实验一:词法分析器的自动实现(Lex词法分析)
编译原理 实验一:词法分析器的自动实现(Lex词法分析)
874 0
编译原理 实验一:词法分析器的自动实现(Lex词法分析)
|
存储 自然语言处理
词法分析器的设计与实现
加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。
172 0