上一篇:
词法分析是编译原理中最容易理解的,就算没有了解过编译原理,也能写出一个词法分析器。我们不用理解正则表达式,不用理解状态机原理,就可以轻松的完成词法的分析。
这里首先介绍下自顶向下的解析过程,所谓的自顶向下,按我的理解,就是从一个大的集合解析到小的集合。例如:解析一个文件,那么进入文件,解析一个函数,进入一个函数,解析局部变量,解析表达式,进入表达式,解析变量、常量等等,最终完成一个C文件的解析过程。整个过程,其实就是一个猜测的过程。但是这个过程中,我们必须依赖于文件中的每个词(token),token可以看成是解析过程中的一个单位。 例如: 1. 关键词有:int char double long for while ...... 2. 运算符有:+ - * / ...... 3. 数字常量:12 0x34 3.45 4. 字符串 :"hello" ... 等等. 那么我们必须实现一个函数get_token,执行这个函数,我们获取文件中的一个token。例如现在一个C文件: int main(int agrc, char **argv ){ return 0; } 那么多次执行get_token,分别得到的token为: int main ( <----③ int argc ... ... 除了一个get_token函数外,还需要一个叫做put_back的函数,因为脚本解析是一个猜测的过程。有时候我们必须知道下一个的token是什么,才能判断该走哪个分支。还是上面的例子,在③的地方,我们得到了"(",所以知道main是一个函数,那么如果该token不是"(", 而是"=", 我们知道它不是一个函数,而是一个基本的变量定义,并且需要初始化。那么我们必须调用put_back函数,把该token重新放到缓存中,使得下次get_token的时候,还会拿到这个token,而不是下个token。 至于get_token和put_back函数如何实现,我就不多说了。我使用了最笨的方法,无非就是每个字符一个一个的向后扫描,判断是该返回什么标示。每个token被分为各种类型token_type: enum tok_types{ DELIMITER = 1, IDENTIFIER, KEYWORD, TEMP, STRING, CHARACTOR, NUMBER, TYPE, BLOCK, PRECOMPILE }; 类型 意义 例如 ----------------------------------------------------------------------------- DELIMITER 标示分隔符 ; | + - IDENTIFIER 标示ID标示符 var hello KEYWORD 关键字 int char while do STRING 字符串 "string" CHARACTOR 字符 'c' NUMBER 数字常量 123 012 0x34 TYPE 类型 typedef int int32; 那么int32就被标示为TYPE BLOCK 块标志 { } PRECOMPILE 预编译行 #define TEMP 保留 词法分析的目的就是扫描源码,区分出这些类型,变返回该token。供解释器的其他模块使用。