此次共享,腾讯内网 / 外网同步发布。
内部代码地址:https://git.code.oa.com/fatboyli/QBDF
外部代码地址:GitHub - ventureli/QBDF
两年前的一个混淆包(无源码):GitHub - ventureli/VLOCInterpreter
作者:腾讯fatboyli(李文强)
本章节主要讲解词法分析。此法分析其实是整个解释器里最简单的部分,编辑原理里的词法分析用一句话就能总结:把源程序的字符串变成单词(用token表示)数组。在整个过程中需要一些额外的 *** 作。例如针对OC需要修正部分单词,比如“interface”这个单词,如果在不同的位置是有不同的含义的。既可以作为变量名,也可以作为关键字。
先贴一张传统的词法分析的有穷自动机的示意图。
词法分析有穷自动机示意图
上面的不同的符号和表达方式很好懂,如果不理解的话,可以搜索引擎中搜索下有穷自动机即可查到相关的定义。
整个QBDF的此法分析是一个比较中规中规中矩的写法。具体的代码大家参考源文件 “QBDFTKProcess.m” 源文件的代码。
这里做一个简单的解析,比如对应数字的识别。可以看到这样的代码,这个代码就完全对应到了有穷状态自动机的数字这一块。
词法分析-数值匹配
所以根据这个状态机,就完成了一个最基本的词法解释器。其余的比如标示符的识别,标点符号的识别,关键字的识别等同理都是这个原理实现。
好了,现在我们基本了解了词法分析的套路,我们来看下QBDF的为词法分析做的定义。
首先我们定义一个单词的类型。
定义单词的类
每个单词都有一个类型,我们需要定义好这个类型,这部分的定义在文件“QBDFScriptMainDefine.h”中,我们截图一部分、
通过enum定义单词类型
注意:这里的开始一个枚举是从128开始的
当然单词里还有些特殊的变量,比如整形/字符串这种我们需要他们的值的,这个我们就存在tokenvalue里,至于为什么用id类型,想下就明白,在OC里也就只有id类型是最通用的了。我们这里只是保存值,至于是什么类型的由tokenType决定,完全可以用的时候通过id类型进行转换。
另外还有一点需要注意:QBDF的词法分析的过程中包括了注释剔除的工作,我们在这一步把所有的注释全部都过滤掉了。代码如下
去除注释
当初为了快速完成整个QBDF的架构,我们并没有支持/*。。。。*/ 这种注释,这里的代码是针对 // 开始的注释我们一直过滤处理下标到‘\n’为止,就实现了我们说的行注释
当然针对与OC还有一些修改。主要有以下两点。
1.特殊的token(单词)
比如对于‘@’开头的关键词是这样处理的。
a)“@interface”,“@end”,“@property” ,这些单词其实是没有必要在拆分了,他们可以作为一个最小的单元。
b)另外就是字符串 ,我们知道其他语言的字符串通常是用 单引号,或者双引号开头的,而OC是采用的 @“”进行的,这个也是没有必要进行再次拆分的,完全都可以把 @“abced” 作为一个token进行处理的。
这里贴下对与@开头的关键词的处理
‘@’开头的关键词处理
2.特殊符号的属性修正
我们通过词法分析最开始拿到的大部分都是标示符,但是其实这些标示符中有一部分是关键词的应该单独列出来。比如“if,else,while,continue,break”等等。所以我们写了一个一个方法对单词进行修正。
标示符号修正为关键词
关键词合并
还有部分变量类型的生命不是一个单词的,QBDF的词法解析也进行了处理了(这个并不是必须的,只是这样做会更简单方便),比如 “long long” ,“unsigned int ” 等多余两个单词表示为一个变量的其实也可以进行处理。
多个单词标示一个类型的标示符修正
有一点提下:对于一些标点符号我们是直接用他们的ASCII码的数值作为他们的类型的,具体看代码如下:
针对标点符号的处理
这也就是为什么在“QBDFScriptMainDefine.h”定义的第一个枚举是从128开始的,这样就肯定不会和我们的标点符号类型相碰撞。
另外还有一个注意点就是,C系列语言(包含OC),一个单引号包含一个字符,表示一个char这种情况,通常是可以作为一个整型表示的,所以QBDF也是这么处理的。这里就不同贴代码了。
经过词法分析我们把源程序字符串变成了一个一个的单词(token)队列。有了单词队列我们就可以了进行语法分析,只有经过了语法分析我们才能明白好一段程序的真正含义。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)