编译器的词法分析是基于finite automata(有穷自动机) 和 regular expression(正则表达式)
alphabet:finite set of symbols 字母表:有限符号的集合
string:sequence of symbols from a given alphabet 字符串:给定字母表的符号序列
language:set of string 字符串的集合
例如x12 = 32;中有token
x12 identifier
= assignment
32 unsigned int
; end of statement
这里的4个token其实可以看作4门语言 每门语言都有其独特的字符构成
当把一个string(或者说一个token)传给finite automata或者regular expression的时候 它会返回告诉你这是不是一个合法的token 是不是一个属于它的语言的token
finite automata和regular expression作为一个工具来识别语言只能识别regular language(标准语言)
DFA相对来说要求会更加严格 每一个可能的输出都有且只有一条输出
L = { w | w contains 101 as substring}
DFA(deterministic finite automata)(确定有限自动机) for L
transition table for DFA:
代码实现
switch(state)
case q0:
if sym == 0 go to q0
if sym == 1 go to q1
case q1:
if sym == 0 go to q1
if sym == 1 go to q2
每一个DFA也是一个NFA 但不是每一个NFA是一个DFA
NFA(non-deterministic finite automata)(非确定有限自动机) for L
transition table for NFA
NFA转DFA的方法:subset construction 子集构造法
那么如果用代码实现的话 是DFA更容易实现还是NFA更容易实现呢?
答案是DFA 所以在词法分析的过程中 通常会建立一个DFA
L = {w | w contains the substring 101 or the substring 111}
NFA:
L = {w | w contains the substring 101 or end with the substring 111}
NFA:
regular expression(正则表达式)
Thompson’s Construction: 把 regular expression 转换成 NFA
NFA转DFA的方法:subset construction 子集构造法
正则表达式是我们人类最容易理解的方式 我们需要把regular expression先转换成NFA 然后再通过子集构造法转换成最终的DFA
只有转换成DFA 我们才能直观的进行代码编写
有一个叫做flex的工具 可以帮助我们完成这些转换 我们只要输入一个正则表达式 这个工具就能返回c语言代码
L = { w | w contains 101 as substring} 的正则表达式为:
(0 U 1)* 101 (0 U 1)*
或者也可以写成 ∑* 101 ∑* //这里的∑*就代表所有可能的输入
接下来再给出两个正则表达式的例子
L = {w | w has an even length} //偶数长度
(∑∑)*
L = {w | w has an odd length} //奇数长度
∑(∑∑)*
正整数的正则表达式
regular expression for unsigned int: [0 - 9]* 允许0开头 且 允许空字符串
0 U [1 - 9][0 - 9]* 不允许0开头
0 U [1 - 9][0 - 9]* 的NFA:
变量的命名规则和其正则表达式 (_ U [a - z]) ([a-z] U [0 - 9] U _)*
它的NFA: