简单的解析完成后来看看 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 来获取表中的数据了。
总结到此整个词法解析器的全部内容都已经完成了,虽然实现的是一个小功能,但我自己花的时间可不少,其中光复习编译原理就让人头疼。
但这还只是整个编译语言知识点的冰山一角,后续还有语法、语义、中间、目标代码等一系列内容,都是一个比一个难啃。
其实我相信大多数人和我想法一样,这个东西太底层而且枯燥,真正从事这方面工作的也都是凤毛麟角,所以花这时间干啥呢?
所以我也决定这个弄完后就弃坑啦。
哈哈,开个玩笑,或许有生之年自己也能实现一门编程语言,当老了和儿子吹牛时也能有点资本。