词法分析
词法分析的双重含义:
规定单词形成的规则(构词规则,词法规则)
根据构词规则识别输入序列(词法分析)
记号、模式和单词
基本分类:关键字(保留字)、标识符、字面量、特殊符号
模式:产生和识别单词的规则
记号:按照某个模式(规则)识别出的元素。
记号至少包含两个信息:一个是记号的类别,另一个是记号的值
一般我们将记号的类别简称为记号,记号的其他信息记为记号的属性
记号的类别标识一类记号
记号的类别加属性标识一个记号实例
单词:指被识别出的元素自身的值
如果把记号看做是一个类型的话,那么单词就是一个类型的实例。词法分析器识别出的序列称为记号流
词法分析器的作用和工作方式
词法分析器是编译器中唯一与源程序打交道的部分
作用:
- 滤掉源程序中的无用成分,如注释,空格,回车等
- 处理与具体平台有关的输入
- 识别记号,并交给语法分析器(这是词法分析器最主要的任务)
- 调用符号表管理器或出错处理器,进行相关处理(词法错误往往不是由词法分析器检查出来的,而是由语法分析器发现的)
工作方式:
- 词法分析器作为语法分析器的子程序。语法分析器每需要一个记号,就调用词法分析器一次
- 词法分析器单独进行一遍扫描(以源程序为输入,输出是记号流形式表示的源程序)
- 与语法分析器并行工作,两者同时工作。(采用队列的结构,词法分析器将记号输出到队列中,语法分析器从队列中取得记号,只要队列中有记号且未满,两者就可同时工作)
输入缓冲区
词法分析器是编译器中读入源程序字符序列的唯一阶段
输入缓冲区的安排一般采用单缓冲区或双缓冲区(缓冲区对)的方式。
字符串与语言
语言L是有限字母表∑上有限长度字符串的集合;
从词法分析角度看程序语言,它是由记号组成的集合
语言是一个集合,集合中的元素是字符串。字符串的长度是有限的。
字母表是有限的,即字母表中的元素是有限多个;
字符串的长度是有限的,即字符串中字符的个数时有限多个;
字符串的基本概念 | 字符串集合的基本运算 |
---|---|
长度 | 空集合 Φ |
空串 | 空串 {ε} |
连接 | 并:X=L∪M |
n次方 | 交:X=L∩M |
前缀 | 连接:X=LM |
后缀 | 闭包:X=L* |
子串 | 正闭包X=L+ |
真前缀 | 差:X=L-M |
真后缀 | |
真子串 | |
子序列 |
正规式与正规集(很无聊的定义,看不看无所谓)
令Σ是一个有限字母表,则Σ上的正规式及其表示的集合递归定义如下:
1. ε是正规式,它表示集合L(ε)={ε}
2. 若a是Σ上的字符,则a是正规式,它表示集合L(a)={a}
3. 若正规式r和s分别表示集合L( r)和L(s),则
(a) r|s是正规式,表示集合L( r)∪L(s),
(b) rs是正规式,表示集合L( r)L(s),
(c) r*是正规式,b表示集合(L( r ))*,
(d)( r)是正规式,表示的集合仍然是L( r)。(加括弧改变优先级、结合性)
可用正规式描述的语言称为正规语言或正规集。
正规集是一个集合,而正规式是表示正规集的一种方法。
不同的正规式也可以表示同一个正规集,即正规式与正规集之间是多对一的关系。
如果正规式P和Q表示了同一个正规集,则称P和Q是等价的,记为P=Q
例如:
正规式 | 正规集 |
---|---|
a,b,c | {a},{b},{c} |
a(a或b)* | {a,aa,bb,ab,aba,abb,aab,···} |
a或b | {a,b} |
正规式的代数性质
记号的说明
正规式的表示方法:
举个栗子:
relation = < | <= | <> | > | >= | =
正规式的说明记号的公式为:
记号 = 正规式
还可以引入辅助定义式来简化正规式的书写
比如:
char = [a-zA-Z]
digit = [0-9]
有限自动机
有限自动机:自动机的状态数是有限的。
若有限自动机M和N识别同一个正规集,那么称M和N是等价的。
有限自动机分为:
确定的有限自动机(DFA)
不确定的有限自动机(NFA)
M=(S, ∑, move, S0, F)
S:有限个状态的集合
求和:有限个输入字符的集合(包括ε)
move:状态转移函数的集合
S0:唯一的初态(开始状态)
F:终态集合(接受状态集),是S的子集,包含所有终态
有限自动机可以用直观的方式表示:
状态转换图
状态转移矩阵
NFA的特点:
不确定性,即它的下一个状态是不确定的,有多个。
NFA存在的问题:
- 只有尝试了所有可能的路径,才能确定一个输入序列不可被接受
- 识别过程中需要大量的回溯,算法复杂。
造成这一问题存在的原因就是:NFA的不确定性。
DFA的特定:
确定性,即它的下一个状态是确定的,最多仅有一个。
DFA无需回溯。
对于任何一个NFA,都可以构造一个DFA来识别它。
正规式描述正规集
自动机识别正规集
构造词法分析器的一般方法和步骤:
- 用正规式对模式进行描述
- 为每个正规式构造一个NFA,它识别正规式所表示的正规集
- 将构造出的NFA转换成等价的DFA(确定化)
- 优化DFA(最小化)
- 根据优化后的DFA构造词法分析器
由正规式构造NFA而不是构造DFA的原因是正规式到NFA有规范的一对一的构造算法
由DFA而不是由NFA构造词法分析器的原因是DFA识别记号的方法优于NFA识别记号的方法
从正规式到NFA
Thompson算法
将正规式r 分解成最基本的正规式。分解从正规式的最右端开始,然后按照规则构造。
构造一个新的NFA最多增加两个状态
规则如下:
规则不给描述了,能看懂。看不懂看书
从NFA到DFA
将不确定的下一状态确定化
如果从当前状态出发经c可能到达不止一个状态,则将所有这些状态组成一个集合。显然,从当前状态出发经c到达的这一状态集是唯一的。
S和T分别表示状态集。
smove(S,a):从当前状态集S中的任何状态s出发,经字符a可直接到达状态的全体。
ε_闭包(T):表示从状态集T出发,经ε可以到达的所有状态。
模拟DFA的构造
S = ε_闭包({ s0 })
a = nextchar;
while a != EOF
S = ε_闭包(smove(S, a));
a = nextchar;
if S&&F==0
return NO
else
return YES
ε_闭包
即,将从该状态集中的每一个状态,经ε可以到达的状态,并入一个集合。该新集合即为ε_闭包求得的下一个集合。
在经过ε一次到达一个状态A后,该状态经ε还可以到达一个状态B,那么就把A,B都并入。
子集构造算法
ε_闭包({s0})是Dstates仅有的状态,且尚未标记
while Dstates有尚未标记的状态T
标记T
for(每一个输入的字符a)
U= ε_闭包(smove(T,a))
if U not in Dstates
push U as 未被标记 in Dstates
Drtan[T,a]=U
由于DFA的一个状态是NFA全体状态的子集,所以在最坏的情况下,有n个状态的NFA,其等价DFA的状态数可能是O(2n)的
最小化DFA
将一个DFA等价变换为另一个状态数最少的DFA的过程称为最小化DFA
对于任意两个状态 t 和 s, 若从一状态出发接受输入字符串w,而从另一状态出发不接受w,或者从t出发和从s出发到达不同的接受状态,则称w对状态t和s是可区分的。
算法思想:
一开始:将非终态集合和终态集合划分
经过一系列区分,把可区分的状态分离出来,直到不可区分为止,所有不可区分的状态可以合并为一个状态。
对G进行划分,G中的两个状态s和t被划分在同一组的充要条件:对于任何输入字符a,move(s,a)和move(t,a)在同一组中。
步骤:
划分集合
终结态与非终结态
然后根据每个集合里,对于每个输入序列,看下一个状态是否仍在这个集合中,如果在,那么就把这些仍处在同一集合的S划分在一起;
如果不在,那么就把不在的划分出去。把划分的组做成新的标记,并对move(S,a)的a进行记录,对新集合进行改造。
消除可能的死状态和不可到达的状态。
由DFA构造词法分析器
- 表驱动型词法分析器
- 直接编码型词法分析器
- 两者的区别:
在表驱动的词法分析器中,DFA是被动的,需要一个驱动器来模拟DFA的行为,以实现对输入序列的分析。
直接编码的词法分析器,将DFA和DFA识别输入序列的过程合并在一起,直接用程序代码模拟DFA识别输入序列的过程。
一般来说,直接编码型的词法分析器适用于词法比较简单的情况。