编译原理学习笔记——第四讲 词法分析
1. 词法分析器的设计——状态转换图
1.1 词法分析概述
- 词法分析的任务:从左至右逐个字符地对源程序进行扫描,产生一个个单词符号。
- 词法分析器(Lexical Analyzer) / 扫描器(Scanner)
功能:输入源程序、输出单词符号
单词符号的种类:基本字、标识符、常数、运算符、界符。
输出的单词符号的表示形式:(单词种别,单词自身的值) - 词法分析器在编译器中地位
1.2 词法分析器的设计
词法分析程序自动生成有哪些困难?
- 编程过程的设计以及二义性问题。
1.2.1 词法分析器的结构
- 为保证可以扫描完全,我们将扫描缓冲区分为两个半区,互补使用。
- 比如有些语言规定,标识符长度不能超过128,我们就可以推断出编译器的扫描缓冲区总长度为256。
1.2.2 超前搜索
-
某些语言允许程序员编写程序时,不写空格,或可以将基本字再定义。给程序员带来了便利,却给词法分析带来的困难。
-
比如上述的例子,必须超前搜索到“,”与“.” 处,才能分辨出两条语句的不同,才能确定哪些是基本字。
-
几点限制——不必使用超前搜索
所有基本字都是保留字;用户不能用它们作自己的标识符
基本字作为特殊的标识符来处理,使用保留字表
如果基本字、标识符和常数(或标号)之间没有确定的运算符或界符作间隔,则必须使用一个空白符作间隔
1.2.3 状态转换图
- 状态转换图是一张有限方向图
- 结点代表状态,用圆圈表示
- 状态之间用箭弧连结,箭弧上的标记(字符)代表射出结状态下可能出现的输入字符或字符类
- 一张转换图只包含有限个状态,其中有一个为初态,至少要有一个终态
1.2.4 状态转换图的实现
1.2.4.1 不含回路的分叉结点
- 可用一个CASE语句或一组IF-THEN-ELSE语句实现
1.2.4.2 含回路的分叉结点
- 对应一段由WHILE结构和IF语句构成的程序
1.2.4.3 终态结点
- 表示识别出某种单词符号,对应返回语句
其中,C为单词种别,VAL为单词自身值
2. 词法规则的形式化
2.1 正规集和正规式
- 正规式和正规集的递归定义,对给定的字母表Σ:
(1)ε和∅都是Σ上的正规式,它们所表示的正规集为{ε}和∅;
(2)任何a∈Σ ,a是Σ上的正规式,它所表示的正规集为{a} ;
(3)假定e1和e2都是Σ上的正规式,它们所表示的正规集为L(e1)和L(e2),则:
1.(e1|e2)为正规式,它所表示的正规集为L(e1)∪L(e2)
2.(e1.e2)为正规式,它所表示的正规集为L(e1)L(e2)
3.(e1)*为正规式,它所表示的正规集为(L(e1))*仅由有限次使用上述三步骤而定义的表达式才是Σ上的正规式,仅由这些正规式表示的字集才是Σ上的正规集。 - 对正规式,下列等价成立:
2.2 确定有限自动机(DFA)
- 对状态图进行形式化定义
- 确定有限自动机(Deterministic Finite Automata,DFA)
M是一个五元式 M=(S,Σ, f, S0, F),其中:
(1)S: 有穷状态集
(2)Σ:输入字母表(有穷)
(3)f: 状态转换函数,为S×Σ→S的单值部分映射,f(s,a)=s’表示:当现行状态为s,输入字符为a时,将状态转换到下一状态s’,s’称为s的一个后继状态
(4)S0∈S是唯一的一个初态
(5)F⊆S:终态集(可空) - 例:DFA M=( {0,1,2,3},{a,b},f,0,{3}),其中f定义如下:
f(0,a)=1 f(0,b)=2
f(1,a)=3 f(1,b)=2
f(2,a)=1 f(2,b)=3
f(3,a)=3 f(3,b)=3 - 上题对应状态转换矩阵与状态转换图:
- 对于Σ*中的任何字α,若存在一条从初态到某一终态的道路,且这条路上所有弧上的标记符连接成的字等于α,则称α为DFA M所识别(接收)
- DFA M所识别的字的全体记为L(M)
L(M)={含aa或bb的字}
2.2 非确定有限自动机(NFA)
- 一个非确定有限自动机(Nondeterministic Finite Automata,NFA)
M是一个五元式
(1)M=(S,Σ, f, S0, F),其中:
(2)S: 有穷状态集
(3)Σ :输入字母表(有穷)
(4)f: 状态转换函数,为S×Σ*→2S的部分映射S0⊆S是非空的初态集
(5)F⊆S :终态集(可空) - 从状态图看NFA 和DFA的区别
(1)NFA可以有多个初态
(2)弧上的标记可以是Σ*中的一个字(甚至可以是一个正规式),而不一定是单个字符
(3)同一个字可能出现在同状态射出的多条弧上
(4)DFA是NFA的特例
- 对于Σ*中的任何字α,若存在一条从初态到某一终态的道路,且这条路上所有弧上的标记字连接成的字等于α(忽略那些标记为ε的弧),则称α为NFA M所识别(接收)。
- 例题:
答:L(M1)={含aa或bb的字}
答:L(M2)={ambn | m,n≥1}
2.3 DFA和NFA
- 定义:对于任何两个有限自动机M和M’,如果L(M)=L(M’),则称M与M’等价
- 自动机理论中一个重要的结论:判定两个自动机等价性的算法是存在的
- 对于每个NFA M存在一个DFA M’,使得L(M)=L(M’)
- DFA与NFA识别能力相同!
- DFA很容易用程序来实现,但设计较难
- NFA设计更容易
3. 有限自动机等价性
3.1 解决初始状态唯一性
- 引进新的初态结点X和终态结点Y,X,Y∉S,从X到S0中任意状态结点连一条ε箭弧, 从F中任意状态结点连一条ε箭弧到Y。
3.2 简化弧上的标记
- 对M的状态转换图进一步施行替换,其中k是新引入的状态。
3.3 NFA确定化——子集法(解决ε弧和转换关系)
-
设I是的状态集的一个子集,定义I的ε-闭包,ε-closure(I)为:
ε-closure(I)=I∪{s’|从某个s∈I出发经过任意条ε弧能到达s’} -
设a是Σ中的一个字符,定义Ia=ε-closure(J)
其中,J为I中的某个状态出发经过一条a弧而到达的状态集合。 -
例题:
-
Ia=ε-closure(J)其中,J为I中的某个状态出发经过一条a弧而到达的状态集合
-
对于上一部分的NFA M’,有:
- 这样就得到了状态集之间的关系转换表
- 把表看成状态转换矩阵,子集视为状态,于是转换表唯一刻划了一个DFA
- 初态是ε-closure({X})
终态是含有原终态Y的子集 - 于是:NFA和DFA等价
- 对刚刚的转换表以及M’进行化简,就将NFA转换为了一个DFA:
3.4 DFA的化简
3.4.1 状态的等价性
- DFA的化简(最小化)就是:对于给定的DFA M,寻找一个状态数比M少的DFA M’,使得L(M)=L(M’)
- 状态的等价性定义:如果从状态
s出发能读出某个字α而停止于终态,那么同样,从t出发也能读出α而停止于终态;反之亦然
两个状态不等价,则称它们是可区别的 - DFA化简基本思想:把M的状态集划分为一些不相交的子集,使得任何两个不同子集的状态是可区别的,而同一子集的任何两个状态是等价的。最后,让每个子集选出一个代表,同时消去其他状态。
3.4.2 化简算法
- 首先,把S划分为终态和非终态两个子集,形成基本划分Π。
- 一般地,对某个a和I(i),若Ia(i) 落入现行Π中 N个不同子集,则应把I(i)划分成N个不相交的组,使得每个组J的Ja都落入的Π同一子集。
重复上述过程,直到Π所含子集数不再增长 - 我们对刚刚得到的DFA进行化简:
- 划分终态与非终态:
I(1)={0, 1, 2},I(2)={3, 4, 5, 6} - 写出Ia(1)={1, 3} ,发现分别落入两个子集,说明第一个子集应该继续划分:
I(11)={0, 2},I(12)={1},I(2)={3, 4, 5, 6} - 写出Ia(11) ={1},Ib(11)={2, 4},发现Ib(11)落入两个子集,应该继续划分:
I(111) ={0},I(112) ={2},I(12) ={1},I(2)={3, 4, 5, 6} - 前三个子集都只有一个元素,不需要看了,看最后一个子集
写出Ia(2) ={3, 6},Ib(2) ={4, 5}
发现这两个子集都在划分的这一子集中
划分完毕,新子集为:{0} {1} {2} {3, 4, 5, 6}
用3来代表4,5,6,对图进行化简:
(所谓代表,就是456射出的弧,都由3来射出,射入也一样)
至此,由NFA等价变换为DFA,并将得到的DFA化简的内容结束。
4. 正规式与有限自动机的等价性
- 一个正规式r与一个有限自动机M等价
L( r )=L(M) - FA ->正规式
对任何FA M,都存在一个正规式r,使得L( r )=L(M)。 - 正规式 -> FA
对任何正规式r,都存在一个FA M,使得L(M)=L( r )。 - 由于NFA与DFA是等价的,所以这里的FA具体是哪个并不重要,后续的讨论将使用NFA。
4.1 为NFA构造正规式
- 定理:对Σ上任一NFA M,都存在一个Σ上的正规式r,使得L®=L(M)。
- 假定NFA M=<S,Σ,δ, S0, F>,我们对M的状态转换图进行以下改造:
- 在M的转换图上加进两个状态X和Y,从X用ε弧连接到M的所有初态结点,从M的所有终态结点用ε弧连接到Y,从而形成一个新的NFA,记为M’,它只有一个初态X和一个终态Y,显然L(M)=L(M’)。
- 然后,反复使用下面的三条规则,逐步消去结点,直到只剩下X和Y为止。
即:增加弧上的标记,减少状态的数量。 - 最后,X到Y的弧上标记的正规式即为所构造的正规式r
显然L( r )=L(M’)=L(M)
- 得证: 对Σ上任一NFA M,都存在一个Σ上的正规式r,使得L®=L(M)。
4.1 为正规式构造NFA——数学归纳法
- 定理: 对于Σ上的正规式r,都存在一个NFA M,使L(M)=L®,并且M只有一个初态和一个终态,而且没有从终态出发的箭弧。
- 对给定正规式r中的运算符数目进行归纳:
4.1.1 验证r中的运算符数目为0时,结论成立。
若r具有零个运算符,则r=ε或r=φ或r=a,其中a∈Σ。
结论成立
4.1.2 假设结论对于运算符数目少于k(k≥1)的正规式成立
- 假设对于运算符数目少于k(k≥1)的正规式成立。
- 当r中含有k个运算符时,r有三种情形:
4.1.2.1 r = r1|r2
- 由归纳假设,对ri存在Mi=<Si,Σi,δi, qi, {fi}>,使得L(Mi)=L(ri),并且Mi没有从终态出发的箭弧(i=1,2)。
- 不妨设S1∩S1=φ,在S1∪S2中加入两个新状态q0,f0。
- 令M=<S1∪S2∪{q0,f0},Σ1∪Σ2,δ, q0, {f0}>,其中δ定义如下:
于是:L(M)=L(M1)∪L(M2)=L(r1)∪L(r2)=L(r1|r2)= L( r )
4.1.2.2 r = r1·r2
- 令M=<S1∪S2,Σ1∪Σ2,δ, q1, {f2}>,其中δ定义如下:
于是:L(M)=L(M1)L(M2)=L(r1)L(r2)=L(r1·r2)=L( r )
4.1.2.3 r = r1*
- 令M=<S1∪{q0, f0},Σ1,δ, q0,{f0}>,其中q0, f0∉S1,δ定义如下(M的状态转换如右图) :
于是:L(M) = L(M1)* = L(r1)* = L(r1*)= L( r )
至此,基于该假设,证明结论对于运算符数目为k的正规式成立。
4.1 为正规式构造NFA——算法与示例
- 现给一个正规式:(a|b)* (aa|bb) (a|b) *
- 构造一个等价的NFA
最后得到:
我们还可以根据之前学到的子集法,把上面这个NFA化简为一个DFA。
有了这些等价关系,我们可以实现词法分析的自动生成。
5. 词法分析程序自动生成——LEX
LEX的工作过程:
- 对每条识别规则Pi构造一个相应的非确定有限自动机Mi;
- 引进一个新初态X,通过ε弧,将这些自动机连接成一个新的NFA;
- 把M确定化、最小化,生成该DFA的状态转换表和控制执行程序。
- 词法分析程序的自动产生——理论和实践相结合的典范:经典理论是我们进行实践操作的理论支撑。先进技术工具是我们要提高自身能力必须使用的方式。二者结合才能综合提高自身能力。