1.词法分析的基本概念
词法分析也称为分词,此阶段编译器从左向右扫描源文件,将其字符流扫描分割成一个个的词(记号、token)。所谓token,就是源文件中不可再进一步分割的一串字符,类似英语中的单词,汉语中的词。
一般来说程序语言中的 token 有:
- 常数(整数、小数、字符、字符串等)
- 操作符(算术操作符、比较操作符、逻辑操作符)
- 分隔符(逗号、分号、括号等)
- 保留字
- 标识符(变量名、函数名、类名等)
2.直接扫描法
每轮扫描,根据第一个字符判断属于哪种类型的token,采取不同的策略扫描出一个完整的token,再接着进行下一轮扫描。
2.1A型单字符运算符
包括:+, -, *, /, %, 这种 token 只有一个字符,若本轮扫描的第一个字符为上述字符,则立即返回此字符所代表的 token ,然后移到下一个字符开始下一轮扫描。
2.2B型单字符运算符和双字符运算符
B型单字符运算符包括: < > = ! ,双字符运算符包括: <=, >=, ==, != 。若本轮扫描的第一个字符为B型单字符运算符时,先查看下一个字符是否是 “=” ,如果是,则返回这两个字符代表的 token ,如果否,则返回这个字符代表的 token 。
2.3关键词和标识符
关键词和标识符都是以字母或下划线开始、且只有字母、下划线或数字组成。若本轮扫描的第一个字符为字母或下划线时,则一直向后扫描,直到遇到第一个既不是字母、也不是下划线或数字的字符,此时一个完整的词就被扫描出来了,然后,查看这个词是不是为关键字,如果是,则返回关键字代表的 token ,如果不是,则返回 T_IDENTIFIER 以及这个词的字面值。
2.4整数常量
整数常量以数字开始,若本轮扫描的第一个字符为数字,则一直向后扫描,直到遇到第一个非数字字符,然后返回 T_INTEGERCONSTANT 和这个数字。
2.5字符串常量
字符串常量以双引号开始和结束,若本轮扫描的第一个字符为双引号,则一直向后扫描,直到遇到第一个双引号,然后返回 T_STRINGCONSTANT 和这个字符串。
2.6空格
若本轮扫描的第一个字符为空格,则跳过此字符。
2.7注释
注释仅考虑以 # 开始的情况,若本轮扫描的第一个字符为 #,则直接跳过此行字符流。
3.语言、形式语言、正则语言和正则表达式
先来思考上述内容的本质。
语言:程序本质上就是一个字符串,语言呢,就是一个合法程序组成的集合,其实本质就是一个字符串集合。
编译又是干什么的呢?编译的输入是程序,输出也是程序,有什么区别吗?
一个是判断输入程序是不是源语言中的合法程序,也就是判断一个元素是否属于一个集合。另一个是将源语言中的合法程序转换成目标语言中的合法程序,且两个程序的含义是一致的,也就是将一个集合中的元素映射到另一个集合中的元素中去。
所谓 正则语言(Regular language),是指这样的句子集合:
(1) 只有一个空句子的集合是一个正则语言,只有一个单符号句子的集合也是一个正则语言。如以下每个集合都是一个正则语言:
{ε}, {a}, {b}, ..., {z}
注意上面每个集合中都只有一个句子,每个句子要么是空句子、要么只有一个字符。另外注意 {ε} 不要和空集搞混了,空集中没有任何元素,{ε} 中有一个空句子元素。
(2) 如果句子集合 R1 和 R2 是正则语言,则 R1 和 R2 的并集 R 也是一个正则语言,R = R1 ∪ R2。
(3) 如果句子集合 R1 和 R2 是正则语言,则 R1 和 R2 的连接集合 R 也是一个正则语言。连接集合 R = { s1 s2 | s1 ∈ R1, s2 ∈ R2 } 。
(4) 如果句子集合 R 是正则语言,则 R 的重复集合 R* 也是一个正则语言,重复集合 R* = { s1 s2 ... sn | si ∈ R , n ∈ N },此处 n 可以等于 0 ,此时 R* 中只有一个空句子。
正则表达式就是按正则语言的构造方式来表示的:
(1) 只有一个空句子的集合的正则表达式为 ε ,只有一个单符号句子的集合 {θ} 的正则表达式为 θ 。
(2) 如果正则语言 R1 和 R2 的正则表达式为 r1 和 r2 ,那么正则表达式 r1|r2 表示 R1 和 R2 的并集。
(3) 如果正则语言 R1 和 R2 的正则表达式为 r1 和 r2 ,那么正则表达式 r1 r2 表示 R1 和 R2 的连接集合。
(4) 如果正则语言 R 的正则表达式为 r , 那么正则表达式 r* 表示 R 的重复集合 R* 。
(5) 正则表达式 (r) 和 r 是等价的。
4.有限状态自动机FA
有限状态自动机(finate automaton)是用来判断字符串(句子)是否和正则表达式匹配的假想机器,它有一个字母表 Σ 、一个状态集合 S ,一个转换函数 T ,当它处于某个状态时,若它读入了一个字符(必须是字母表里的字符),则会根据当前状态和读入的字符自动转换到另一个状态,它有一个初始状态,还有一些所谓的接受状态。
它的工作过程是:首先自动机处于初始状态,之后它开始读入字符串,每读入一个字符,它都根据当前状态和读入字符转换到下一状态,直到字符串结束,若此时自动机处于其接受状态,则表示该字符串被此自动机接受。
上图中圆圈表示各种状态,各箭头及签头上的字符表示状态的转换表,自动机只有一个初始状态,用一个不含字符的箭头指向此状态,可以认为此为自动机的入口,自动机可以有一个或多个接受状态,用双圆圈表示。上图中的自动机的字母表为 {a, b},初始状态为 S1 ,当它读入一个 a 后,就转到状态 S2 ,若读入的是 b ,则转到 S4,然后一个接一个字符的转换其状态,若字符结束时自动机处在其接受状态,则表示此字符串被其接受。经过观察可知,此图中的自动机能接受的字符串为 “ab”, “abb”, “abbb”, ... ,也就是说,此自动机与正则表达式 ab+ 是等价的。
简单的有限状态自动机可以通过上一小节的 与、连接和重复 搭建出复杂的自动机。数学家们已经证明了:任何一个正则表达式都有一个等价的有限状态自动机,任何一个有限状态自动机也有一个等价的正则表达式。