第三章.词法分析
词法分析器作用
将源程序的字符串流,组成词素,生成一个词法单元序列(词法单元包含词法单元名和属性值构成)。
对于词法分析器发现的标识符词素时,会将词素添加到符号表中。
词法分析器→语法分析器
常见的词法单元和词素
词法单元 | 描述 | 词素 |
---|---|---|
if | 字符i,f | if |
else | 字符e,l,s,e | else |
comparison | 大于小于 | > < |
id | 字母开头的变量 | po,D2 |
number | 数字 | 3.14 2 |
词法单元的规约
正则表达式:用来描述词素的重要表示方法。
串相关
- 前缀,后缀,子串,子序列(字符可以不连续)
正则表达式可以由娇小的正则表达式按照规则递归构建。
r={a,b,c,d...x,y,z} s={0,1,2,3...9}
- (r)|(s) 等价于 L(r)交L(s) 共36个
- (r)(s) 等价于 L(r)xL(s) 共26*10个
- (r)* 所有r字母构成的集合,包括空串
- s+表示一个或多个数位构成的串的集合
正则的扩展
- 一个或多个实例。用单目运算符+
- 零个或一个实力。用单目运算符? ,r?等价 r|空
词法单元识别
状态转换图:构造词法分析器的一个中间步骤,构造状态转换图。
- 双圈表示接受状态,可以是返回词法单元的相关属性值
- *星号表示回退上一个状态。
可以用while,switch实现状态转换图
有穷自动机(finite automata)
将出入程序变成一个词法分析器,自动机的本质是与状态转换图类似的图。
- 有穷自动机是识别器,只能对每个可能的输入串回答Y/N
- 不确定有穷自动机(Nondeterministic Finite Automata,NFA)对边上的标号没有任何限制。
- 确定的有穷自动机(Deterministic Finite Automata,DFA)对于每个状态及自动机输入的字母表符号,有且只有一条离开状态。
不确定的有穷自动机(NFA)
对边上的标号没有任何限制,一个符号标记离开同一状态的多条边,空串也可以作为标号。
- 可用转换表表示,行为状态,列为输入符号,记录各个可能的所有状态
状态 | a | b | c |
---|---|---|---|
0 | {0,1} | {0} | 空 |
1 | 空 | {2} | 空 |
2 | 空 | {3} | 空 |
3 | 空 | 空 | 空 |
确定的有穷自动机(DFA)
属于NFA的一个特例,说NFA是一个抽象表示的识别串的算法,DFA就是一个具体的识别串的算法。
- 没有输入 空 之上的转换动作
- 对于每个状态s每个输入符号a,有且只有一条标号为a的边离开s
从正则表达式到自动机
利用子集构造法将NFA转成DFA
基本思想让构造得到的DFA每个状态对应于NFA的一个状态集合
输入:一个NFA N
输出:一个转换后的DFA D
方法:为D构造一个转化表Dtran,D的每个状态都是一个NFA状态集合,利用Dtran,使D可以"并行"的模拟N遇到一个给定输入串时可以执行的所有动作。须要解决的问题包括,正确处理N的 空串 的转换。
最小化一个DFA的状态数
例中A和C等价,都不接受状态,对于任意输入总能转到同一个状态。
结论:对于任何正则语言都有一个唯一的 状态数目最少的DFA,通过分组合并并等价的状态,可以构造状态数最少的DFA。
死状态:所有输入符号上都转向自己的非接受状态。在一个DFA中,每个状态出发每个输入符号上都会有一个转换,发现正确词素的时候DFA结束。
从正则表达式构造NFA
可以将任何正则表达式变为接受相同语言的NFA。这个算法是语法制导的,就是沿着正则表达式的语法分析树自底向上递归进行处理。
对于每个子表达式,构造一个只有一个接受状态的NFA。
不同方法的开销
自动机 | 初始开销 | 每个串的开销 |
---|---|---|
NFA | O(r) | O(rxs) |
DFA typical case | O(r^3) | O(s) |
DFA worst case | O(r^2*2^r) | O(s) |
如果处理字符串所花时间很多,更倾向DFA。然而像grep这样的命令,只会对一个符号串运行自动机,通常使用NFA方式。