本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
文章目录
对词法分析器的要求
词法分析的任务:
从左到右逐个字符地扫描源程序,产生一个个的单词符号,把作为字符串的源程序改造称为单词符号串的中间程序
词法分析器/扫描器:执行词法分析的程序
词法分析器的功能如下图:
输入源程序,输出单词符号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iv41XUs9-1678365454067)(http://cdn.hydrion-qlz.top/gitee/202201211134972.png#pic_center)]
- 关键字
- 由程序语言定义的具有固定意义的标识符。也可以称为保留字或基本字。如:if,else。他是确定的
- 标识符
- 用来表示各种名字,如变量名、数组名、函数名等,他是不限的
- 常数
- 常数的类型一般有整型、实型、布尔型、文字型等。他是不限的。
- 运算符
- 运算符:如+、-、*、/等,他是确定的
- 界符
- 界符:如逗号、分号、括号等,他是确定的
确定:代表该类型符号是可枚举的
不限:代表该类型符号是不可枚举的
单词符号的表示形式
词法分析器的功能和输出形式
词法分析器所输出的单词符号常常表示成二元式:(单词种别,单词自身的值)。
单词种别可以用以下形式表示:
- 一类单词统一用一个整数值代表其属性。例如:1代表关键字,2代表标识符等
- 每一个单词一个类别。例如:1代表Begin,2代表End
单词自身的值:其可以表示成:常量的二进制表示;常量、变量在符号表中的地址码,等等
注意:
一个语言的单词符号如何分种,分几种,怎样编码,这是一个技术问题。
- 标识符一般同归为一种。
- 常数则宜按照类型(整数、实数、布尔)分类
- 关键字可以将其全体视为一种,也可以一字一种
- 运算符可以采用一符一种,但也可以把具有一定共性的视为一种
- 界符一般采用一符一种。
若是一符一种分种,单词自身值就不需要了。否则,要查符号表
例子
151-FORTRAN编译程序的词法分析器在扫描输入串(下述代码)后,它输出的单词符号串是:
IF (5 · RQ · M) GOTO 100
类型 | 单词符号串 | 解释 |
---|---|---|
逻辑IF | (34,_) | IF为关键字,种别编码为34 用一符一种的编码方式 |
左括号 | (2,_) | ‘(’为界符,种别编码为2 采用一符一种的编码方式 |
整常数 | (20,‘5’的二进制表示) | 常数类型,种别编码为20 单词自身的值为‘5’的二进制表示 |
等号 | (6,_) | 等号为运算符,种别编码为6 采用一符一种的编码方式 |
标识符 | (26,‘M’) | M为标识符,种别编码26 单词自身值为M在符号表中的地址 |
右括号 | (16,_) | ‘)’为界符,种别编码为16} 采用一符一种的编码方式 |
GOTO | (30,_) | GOTO为关键字,种别编码为30 采用一符一种的编码方式 |
标号 | (19,‘100’的二进制表示) | 100位标号,种别编号为19 单词自身的值用100的二进制表示 |
词法分析与语法分析的关系
把词法分析从语法分析中脱离出来的优点:
- 使编译程序的结构更加简洁、清晰和条理化
- 词法分析和语法分析方法不同,词法分析可以使用正则文法自动构造scanner简单
- 有利于提高语法分析的效率
- 可以改善词法分析的细节,甚至于一个语法分析配几个scanner,把不同的输入变成一种内部表示
把词汇分析作为独立的一遍
- 将Scanner作为一遍
- scanner作为子程序
词法分析器的设计
设计前提:
- 把Scanner作为一个独立的子程序
- 词法分析器的任务为输出单词符号
预处理
- 必要性:编辑性字符如空白符、回车符等,除了出现在文字常数中以外,在别处出现都没有意义。
- 功能:剔除无用字符
- 实现:预处理子程序
- 输入:曾经是纸带,所以图中的样子是多个文件
- 列表是对输入缓冲区的内容进行统计记录
- 预处理子程序从输入缓冲区读入字符,将扫描结果放入扫描缓冲区交由扫描器使用
- 语法分析器调用扫描器,扫描器调用预处理子程序,预处理子程序和扫描器都可以返回当前处理结果
- 扫描器查看扫描缓冲区是否准备好字符串,如果没有准备好则调用预处理子程序
例子:识别输入语句IF (5.EQ.M) GOTO 100
缓冲区的大小不够容纳整条语句
扫描缓冲区的结构:
- 缓冲区大小:120个字符
- 采用两个指示器:起点指示器、搜索指示器
- 两个互补的缓冲区
单词符号的识别----超前搜索
单词符号识别的简单方法:超前搜索
FORTRAN语言是第一个高级编程语言,所以本门课程大量使用FORTRAN程序代码
- 标识符的识别
- 多数语言的标识符是字母开头的“字母/数字”串,而且在程序中标识符的出现后都跟着算符或界符。因此不难识别
- 常数的识别
- 对于某些语言的常数的识别也需要使用超前搜索
- 算符和界符的识别
- 对于诸如
C++
语言中的“++”、“–”,这种复合成的算符,需要超前搜索
- 对于诸如
状态转换图
- 转换图:是一张有限方向图。在状态转换图中,结点代表状态,用圆圈表示。状态之间用箭弧连接。箭弧上的**标记(字符 )**代表在射出节点状态下可能出现的输入字符或字符类
- 状态转换图的功能:识别符合一定要求的字符串
- 可能有若干条要求,对于每一个要求都可以建立一个状态转换图
- 状态转换图可以与词法分析器中的每一个程序段对应起来
- 初态:一张完整状态转换图的启动条件,至少有一个,用圆圈表示
- 终态:一张完整状态转换图的结束条件,至少有一个,用双圈表示
- 终态上的*:表示多读进了一个不属于标识符部分的字符
简单的状态转换图的示例
a:是状态转换图的子图,是不完整的
b:识别标识符的转换图
c:识别整数的转换图
d:识别FORTRAN实型常数的转换图,例如 1.23E+4 和 .56E-7
综合示例----做出识别下表所示的小语言的单词符号的状态转换图
- 标志符和常数都是一类一种,其他的是一类一种,所以没有内码值
- 每一行都是一条构词规则
词法分析的转换图
状态转换图的实现
- ch:字符变量,存放最新读进的源程序字符
- strToken:字符数组,存放构成单词的字符串
- GetChar:过程,将下一输入字符读入ch,搜索指示器前移一个字符
- GetBC:过程,检查ch中的字符是否为空白。若是,则调用GetChar直至ch中进入一个非空白字符
- Concat:过程,把ch中的字符链接到strToken之后
- IsLetter,IsDigit:布尔函数过程,他们分别判断ch中的字符是数字或字母
- Reserve:整型函数过程,用strToken中的字符串查保留字表,若是一个保留字则给予编码,否则会送0值(假定0不是保留字的编码)
- Retract:过程,把搜索指示器回调一个字符,把ch中的字符置为空白
以上函数和子程序过程都不难编制,使用他们能够方便地构造状态转换图的对应程序。一般地,我们可以让每一个状态结点对应一个程序段。例如:我们可以让不含回路的分叉结点对应一个CASE语句,或者是一组IF…THEN…ELSE。
终态结点一般对应一个return(code, value)
其中code为单词种别编码,value是字符数组的strToken(或者是一个整数值,或者无定义)
为了把状态转换图转化成程序,每个状态要建立一段程序,它要做的工作如下:
- 从输入缓冲区中取一个字符。为此,我们使用函数GetChar,每次调用它,推进先行指针,送回一个字符
- 确定在本状态下,哪一条箭弧是用刚刚来的输入字符标识的。如果找到,控制就转到该弧所指向的状态;若找不到,那么寻找该单词的企图就失败了
- 先行指针必须重新回到开始指针处,并用另一状态图来搜索另一单词。如果所有的状态转换图都试过之后,还是没有匹配的,就表明这是一个词法错误,此时,调用错误校正程序
状态1的代码如下所示:
C := GetChar;
if IsLetter(C) or IsDigit(C):
then goto state 1
else if Delimiter(C)
then goto state 2
else
Fail()
状态2的代码如下所示:
! Retract()是过程,由于分解符不属于标识符,所以我们需要把先行指针回调一个字符
Retract();
return ($id,Install())
如果同时识别标识符和关键字,则需要修改为下面这样:
Retract();
! Reserve()整型函数过程,针对strToken中的字符串进行查找,看其是否是保留字,是保留字给出它的编码,否则返回0(假定不是保留字编码)
C := Reserve();
if C = 0
then return ($id, Install())
else return (C, _)
总结
词法分析方法包括以下步骤:
- 给出程序设计语言的单词规范
- 对照单词表设计识别改语言所有单词的状态转换图
- 根据状态转换图编写词法分析程序
该方法是手工方式,效率比较低
词法分析器的设计:
- 给出程序设计语言的单词规范——单词表
- 对照单词表设计识别该语言所有单词的状态转换图
- 根据状态转换图编写词法分析程序
正规表达式与有限自动机
预备知识
字母表是一个非空有穷集合,通常用 Σ \Sigma Σ表示
字母表中的元素称为该字母表的字母(letter),或者符号(symbol),或者字符(character)
最好称之为字符,其他两个叫法会有歧义
字母表的两个特性:非空性和有穷性
字符的两个特性
- 整体性(monolith),或称为不可分性
- 可辨认性(distinguishable),或称为可区分性
字母表的乘积
Σ
1
\Sigma_1
Σ1与
Σ
2
\Sigma_2
Σ2的乘积记作
Σ
1
Σ
2
=
{
a
b
∣
a
∈
Σ
1
,
b
∈
Σ
2
}
\Sigma_1\Sigma_2=\{ab|a\in\Sigma_1,b\in\Sigma_2\}
Σ1Σ2={ab∣a∈Σ1,b∈Σ2}
字母表 Σ \Sigma Σ的幂
零次幂不是空集,是个空串
- Σ 0 = { ε } \Sigma^0=\{\varepsilon\} Σ0={ε},其中 ε \varepsilon ε是由 Σ \Sigma Σ中的0个字符组成的
- Σ n = Σ n − 1 Σ , n ≥ 1 \Sigma^n=\Sigma^{n-1}\Sigma,n\ge1 Σn=Σn−1Σ,n≥1
字母表的闭包
每个闭包都至少包含一个串,允许串无限长
-
Σ \Sigma Σ的正闭包(positive closure)
Σ + = Σ ∪ Σ 2 ∪ Σ 3 ∪ Σ 4 . . . \Sigma^+=\Sigma\cup\Sigma^2\cup\Sigma^3\cup\Sigma^4... Σ+=Σ∪Σ2∪Σ3∪Σ4...
-
Σ \Sigma Σ的克林闭包(Kleene closure) 与正闭包的区别只在于增加了零串,(默认是这个)
Σ ∗ = Σ 0 ∪ Σ ∪ Σ 2 ∪ Σ 3 ∪ . . . = Σ 0 ∪ Σ + = { ε } ∪ Σ + \Sigma^*=\Sigma^0\cup\Sigma\cup\Sigma^2\cup\Sigma^3\cup...=\Sigma^0\cup\Sigma^+=\{\varepsilon\}\cup\Sigma^+ Σ∗=Σ0∪Σ∪Σ2∪Σ3∪...=Σ0∪Σ+={ε}∪Σ+
字母表和闭包的关系举例:
句子
建议用串来理解
对于任何 x ∈ Σ ∗ x\in\Sigma^* x∈Σ∗,x即 Σ \Sigma Σ上的一个句子(sentence):
句子又可被称为字(word)、字符行/符号行(line)、或字符串/符号串(String)
程序设计语言的单词规范----单词表可以与正规集建立起一一对应关系,进而与正规式建立起一一对应关系
单词表是啥?字母表的闭包吗?单词表就是在说什么样的串是我这个语言允许的、可接受的
正规式非常简约,且可以表示单词表的所有东西
有一种工具,输入是正规式,输出是状态转换图对应的词法分析程序,直接跳过状态转换图这一步
正规式与正规集
Σ ∗ \Sigma^* Σ∗的子集U,V:
- 积: U V = { α β ∣ α ∈ U & β ∈ V } UV=\{\alpha\beta|\alpha\in U\&\beta\in V\} UV={αβ∣α∈U&β∈V}
- n次积: V n = V V V . . . V V^n=VVV...V Vn=VVV...V, V 0 = { ε } V^0=\{\varepsilon\} V0={ε}
- V的闭包: V ∗ = V 0 ∪ V 1 ∪ V 2 ∪ . . . V^*=V^0\cup V^1\cup V^2\cup... V∗=V0∪V1∪V2∪...
- V的正则闭包: V + = V V ∗ V^+=VV^* V+=VV∗
空串 ε \varepsilon ε不是字母表中的元素,phi是吗?
ε \varepsilon ε是字,但是 Φ \Phi Φ不是字是集合
正规式与正规集的递归定义:
- ε \varepsilon ε和 Φ \Phi Φ都是字母表 Σ \Sigma Σ上的正规式,它们所表示的正规集分别为 { ε } \{\varepsilon\} {ε}和 Φ \Phi Φ
- 任何 a ∈ Σ a\in \Sigma a∈Σ,a是 Σ \Sigma Σ上的一个正规式,它所表示的正规集为 { a } \{a\} {a}
仅由有限次使用上述三步骤而得到的表达式是字母表 Σ \Sigma Σ上的正规式,仅由这些正规式所表示的子集才是字母表 Σ \Sigma Σ上的正规集
| 或, · 连接, * 闭包
优先顺序,先 * 再 · 在 |
涉及到闭包一定是无穷集
证明两个正规集相等可以从正规集出发,证明集合相等
例子
例1:
令
Σ
=
{
A
,
B
,
0
,
1
}
\Sigma=\{A,B,0,1\}
Σ={A,B,0,1},则:
正规式
正规集
(
A
∣
B
)
(
A
∣
B
∣
0
∣
1
)
∗
Σ
上标识符的全体
(
0
∣
1
)
(
0
∣
1
)
∗
Σ
上数的全体
\begin{aligned} &正规式 &&正规集\\ &(A|B)(A|B|0|1)^* && \Sigma上标识符的全体\\ &(0|1)(0|1)^* &&\Sigma上数的全体 \end{aligned}
正规式(A∣B)(A∣B∣0∣1)∗(0∣1)(0∣1)∗正规集Σ上标识符的全体Σ上数的全体
例2:
令
Σ
=
{
a
,
b
}
\Sigma=\{a,b\}
Σ={a,b},下面是
Σ
\Sigma
Σ上的正规式和相应的正规集:
正规式
正规集
b
a
∗
Σ
上所有的以
b
为首,并且后跟任意多个
a
的字,
{
b
,
b
a
,
b
a
a
,
b
a
a
a
,
.
.
.
.
}
a
(
a
∣
b
)
∗
Σ
上所有的以
a
为首的字
(
a
∣
b
)
∗
(
a
a
∣
b
b
)
(
a
∣
b
)
∗
Σ
上所有含有两个连续的
a
或者
b
的字
\begin{aligned} &正规式 &&正规集\\ &ba^* && \Sigma上所有的以b为首,并且后跟任意多个a的字,\{b,ba,baa,baaa,....\}\\ &a(a|b)^* &&\Sigma上所有的以a为首的字\\ &(a|b)^*(aa|bb)(a|b)^* && \Sigma上所有含有两个连续的a或者b的字\\ \end{aligned}
正规式ba∗a(a∣b)∗(a∣b)∗(aa∣bb)(a∣b)∗正规集Σ上所有的以b为首,并且后跟任意多个a的字,{b,ba,baa,baaa,....}Σ上所有的以a为首的字Σ上所有含有两个连续的a或者b的字
若两个正规式表示相同的正规集,则认为二者等价,记为 U = V U=V U=V。
例如:
b ( a b ) ∗ = ( b a ) ∗ b ( a ∣ b ) ∗ = ( a ∗ b ∗ ) ∗ b(ab)^*=(ba)^*b\\ (a|b)^*=(a^*b^*)^* b(ab)∗=(ba)∗b(a∣b)∗=(a∗b∗)∗
关系
令U、V和W均为正规式,显而易见,下列关系普遍成立:
- 交换律: U ∣ V = V ∣ U U|V = V|U U∣V=V∣U
- 或结合律: U ∣ ( V ∣ W ) = ( U ∣ V ) ∣ W U|(V|W)=(U|V)|W U∣(V∣W)=(U∣V)∣W
- 连接结合律: U ( V W ) = ( U V ) W U(VW)=(UV)W U(VW)=(UV)W
- 分配率:
- U ( V ∣ W ) = U V ∣ U W U(V|W)=UV|UW U(V∣W)=UV∣UW
- ( V ∣ W ) U = V U ∣ W U (V|W)U=VU|WU (V∣W)U=VU∣WU
- 吸收律: ε U = U ε = U \varepsilon U = U \varepsilon =U εU=Uε=U
确定有限自动机(DFA)
定义
一个确定有限自动机(DFA) M是一个五元式: M = ( S , Σ , δ , s 0 , F ) M=(S,\Sigma,\delta,s_0,F) M=(S,Σ,δ,s0,F),其中:
- S是一个有限集,它的每个元素称为一个状态
- Σ \Sigma Σ是一个有穷字母表,它的每个元素称为一个输入字符
- δ \delta δ是一个从 S × Σ S\times\Sigma S×Σ至 S S S的单值部分映射, δ ( s , a ) = s ′ \delta(s,a)=s' δ(s,a)=s′意味着:当现行状态为s、输入字符为a时,将转换到下一状态 s ′ s' s′。我们称 s ′ s' s′为s的一个后继状态
- s 0 ∈ S s_0\in S s0∈S是唯一的初态(不可空)
- F ⊆ S F\subseteq S F⊆S是一个终态集(可空)
单值映射的后面一定是唯一的,也可以没有,即至多一个
3,4是为了体现定义中“确定”的要求
终态为空是因为当前这个图可能是在一个更大的图中的子图。但是在一般保证该图有意义的情况下都是不为空的
显然,一个DFA可以用一个矩阵表示,该矩阵的行表示状态,列表示字符,矩阵元素表示 δ ( s , a ) \delta(s,a) δ(s,a)的值,这个矩阵称为状态转换矩阵
例子
例1
有DFA
M
=
(
{
0
,
1
,
2
,
3
}
,
{
a
,
b
}
,
δ
,
0
,
{
3
}
)
M=(\{0,1,2,3\},\{a,b\},\delta,0,\{3\})
M=({0,1,2,3},{a,b},δ,0,{3}),其中
δ
\delta
δ为:
δ
(
0
,
a
)
=
1
δ
(
0
,
b
)
=
2
δ
(
1
,
a
)
=
3
δ
(
1
,
b
)
=
2
δ
(
2
,
a
)
=
1
δ
(
2
,
b
)
=
3
δ
(
3
,
a
)
=
3
δ
(
3
,
b
)
=
3
\begin{aligned} &\delta(0,a)=1 & \delta(0,b) =2\\ &\delta(1,a)=3 & \delta(1,b) =2\\ &\delta(2,a)=1 & \delta(2,b) =3\\ &\delta(3,a)=3 & \delta(3,b) =3 \end{aligned}
δ(0,a)=1δ(1,a)=3δ(2,a)=1δ(3,a)=3δ(0,b)=2δ(1,b)=2δ(2,b)=3δ(3,b)=3
则其相应的状态转换矩阵如下表:
状态 | a | b |
---|---|---|
0 | 1 | 2 |
1 | 3 | 2 |
2 | 1 | 3 |
3 | 3 | 3 |
在该例子中共有四个状态,两个字符
另外如果题目要求由DFA转换为五元式的时候会在表中写出来初态和终态
初态其实可以根据图判断出来:只有出度,没有入度
一个DFA也可以用一张(确定的)状态转换图来表示。假定DFA M含有m个状态n个输入字符,那么,这个状态转化图含有m个状态结点,每个结点顶多有n条箭弧射出和别的结点相连接,整张图含有一个初态结点和若干个(可以为0)终态结点(需要双圈表示)。
例如可以识别aa(0-1-3),bba(0-2-3-3),等
例2
数字常量的正则表达式对应的DFA:
digit = [0-9]
nat = digit+
signedNat = (+|-)?nat
number = signedNat("."nat)?
解释:
- 其中[0-9]表示可以取0-9中的任意一个数字,则digit表示的就是一位数字
- nat表示digit的闭包,也就是说nat中可以包含有1个或多个digit
- ”|“表示或者,“?” 表示可以有也可以没有,则signedNat则表示带符号的整数
- number是在signedNat后又加了小数点以及无符号数,则number表示全体实数
DFA的五元式可以转换为状态转移矩阵,状态转移矩阵又和状态转换图有一一对应的关系
例3
约定进入的有向箭头表示初态节点
例4
注意二者中的区别
串中只有一个b可以被接受的DFA:
接受包含最多一个b的串的DFA:
定理:如果一个DFA M的输入字母表为 Σ \Sigma Σ,则我们也称M是 Σ \Sigma Σ上的一个DFA。可以证明: Σ \Sigma Σ上的一个字集 V ⊂ Σ ∗ V\subset \Sigma^* V⊂Σ∗是正规的,当且仅当存在 Σ \Sigma Σ上的DFA M,使得 V = L ( M ) V = L(M) V=L(M)
DFA的确定性表现在映射 δ \delta δ: s × Σ → S s\times \Sigma\rightarrow S s×Σ→S是一个单值函数。即:对于任何状态 s ∈ S s\in S s∈S和输入符号 a ∈ Σ a\in \Sigma a∈Σ, δ ( s , a ) \delta(s,a) δ(s,a)唯一确定了一个状态。
将确定有限自动机转换为程序段时,也需要使用状态转换图中的方法
DFA M:确定有限自动机的那个五元式
正规式和正规集是一一对应的,DFA可以表达正规式,所以DFA可以表达正规集
如果允许是一个多值函数,那么就需要用到非确定性有限自动机
非确定有限自动机
定义
一个非确定有限自动机(NFA) M是一个五元式: M = { S , Σ , δ , S 0 , F } M =\{S,\Sigma,\delta,S_0,F\} M={S,Σ,δ,S0,F},其中:
- S是一个有限集,它的每一个元素称为一个状态
- Σ \Sigma Σ是一个有穷字母表,它的每个元素称为一个输入字符
- δ \delta δ是一个从 S × Σ ∗ S\times \Sigma^* S×Σ∗至S的子集的映射,即 δ : S × Σ ∗ → 2 s \delta:S\times \Sigma^*\rightarrow2^s δ:S×Σ∗→2s
- S 0 ⊆ S S_0\subseteq S S0⊆S是一个非空初态集
- F ⊆ S F\subseteq S F⊆S是一个终态集(可空)
一个含有m个状态和n个输入字符的NFA可用一张如下的状态转换图来表示:该图含有m个状态结点,每个结点可以射出若干条弧与别的结点相连接,每条弧用 Σ ∗ \Sigma^* Σ∗中的一个字(可以是不同的字,也可以是空字)做标记,整张图至少含有一个初态结点和若干个(可以是0个)终态结点。某些结点既可以是初态结点也可以是终态结点
例子
例一
下图所示的状态转换图 S , Σ , Σ ∗ S,\Sigma,\Sigma^* S,Σ,Σ∗如下:
看箭弧上标的是字母还是串
- 如果是串(或者包含 ε \varepsilon ε),则是NFA
- 否则是DFA
x,y是引入的一个状态节点,确保初态结点和终态结点只有一个,箭弧使用空字来表示
对于 Σ ∗ \Sigma^* Σ∗中的任何一个字 α \alpha α,若存在一条从某一初态结点到某一终态节点的道路,且这条道路上所有弧上的标记字依照顺序连接成的字(忽略 ε \varepsilon ε)等于 α \alpha α,则称 α \alpha α可以为NFA M识别
在本例中,从初态x到终态y的连接通路弧上,有如下标记字: ε ε a a ε ε \varepsilon\varepsilon a a \varepsilon \varepsilon εεaaεε,去除 ε \varepsilon ε,为aa,所以字aa可以被NFA接受
例二
语言:正确的有效的串的集合,与正规式对应的正规集
例三
DFA与NFA的区别
DFA可以看成是NFA的特例
- 从状态图看NFA和DFA的区别
- NFA可以有多个初态
- 弧上的标记可以是 Σ ∗ \Sigma^* Σ∗中的一个字(甚至可以是一个正规式),而不一定是单个字符
- 同一个字可能出现在同状态射出的多条弧上
- DFA是NFA的特例
NFA | DFA | |
---|---|---|
初始状态 | 不唯一 | 唯一 |
弧上的标记 | 字(单字符字、 ε \varepsilon ε) | 字符 |
转换关系 | 非确定 | 确定 |
确定化
这里有一道大题,比较简单
ε \varepsilon ε_CLOSURE(I)定义
DFA是NFA的特例,可以采用子集法将NFA确定化
假定I是NFA M的状态集的一个子集,我们定义 ε \varepsilon ε_CLOSURE(I)为:
- 若 s ∈ I s\in I s∈I,则 s ∈ ε _ CLOSURE(I) s\in \varepsilon\_\text{CLOSURE(I)} s∈ε_CLOSURE(I)
- 若 s ∈ I s\in I s∈I,那么从s出发经过任意条 ε \varepsilon ε弧而能到达的任意状态 s ′ s' s′,都属于 ε _ CLOSURE(I) \varepsilon\_\text{CLOSURE(I)} ε_CLOSURE(I)
- 状态集 ε _ CLOSURE(I) \varepsilon\_\text{CLOSURE(I)} ε_CLOSURE(I)称为I的 ε \varepsilon ε_闭包,即空字闭包
I a Ia Ia定义
假定 I I I是NFA M的状态集的子集, a ∈ Σ a\in\Sigma a∈Σ,定义: I a = ε _ CLOSURE(J) Ia=\varepsilon\_\text{CLOSURE(J)} Ia=ε_CLOSURE(J)
其中, J J J是那些可从 I I I中的某一状态结点出发经过一条 a a a弧而到达的状态结点的全体
一般都是先经过 a a a的一步转移,然后再找空字闭包
子集算法
- 表的初始化构造
Σ = { a 1 , a 2 , . . , a k } \Sigma=\{a1,a2,..,ak\} Σ={a1,a2,..,ak}。先构造一张表,该表的每一行含有 k + 1 k+1 k+1列。置该表的首行首列为 ε _ CLOSURE(I) \varepsilon\_\text{CLOSURE(I)} ε_CLOSURE(I)
- 处理表的一行
这里简化成了只有两个元素
如果某一行的第一列的状态子集已经确定,例如记为 I I I,那么,求出这一行的第二个和第三个子集 I a I_a Ia和 I b I_b Ib看它们是否已在表的第一列出现,将未出现的填入到后面空行的第一列中。
- 重复处理
重复上述过程,直至所有第二列和第三列的子集均已在第一列上出现了为止
例子
例一
处理步骤:
找初始节点的空字闭包,写到第一行的第一列
再找一步转移闭包,再找空字闭包,写第一行的后面所有各列
然后看该集合是不是在第一列出现了
- 如果没出现把他写到第一列继续处理
直到全部处理结束
最后得到如下图右侧的表格所示的状态转换矩阵
对右下图表中的所有子集重新命名,得到左图中的状态转换矩阵,从而得到相应的DFA。如图所示:
初态结点标记为0,其他继续往上加
包含了原终态结点的最后在状态转换图上全部都要画成终态结点,即两个圈圈的节点
例二
如果给的结点有多个初始结点,需要自己引入X转化为只有一个初始结点的NFA然后再开始化简
题目:使用子集法将非确定性有限自动机转换为确定有限自动机时,首先要引入状态结点X,其目的是为了解决初态节点的惟一性
正规文法与有限自动机的等价性
对于正规文法G和有限自动机M,如果 L ( G ) = L ( M ) L(G)=L(M) L(G)=L(M),则称G和M是等价的
关于正规文法和有限自动机的等价性,有以下结论:
- 对于每一个正规文法G,都存在一个有限自动机M,使得 L ( M ) = L ( G ) L(M)=L(G) L(M)=L(G)
- 对于每一个有限自动机M,都存在一个正规文法G,使得 L ( M ) = L ( G ) L(M)=L(G) L(M)=L(G)
正规式与有限自动机的等价性
L(r)是正规集,L(G)是有限自动机可以识别的符号集合
关于正规式和有限自动机的等价性,有以下结论:
- 对于任何有限自动机M,都存在一个正规式r,使得 L ( r ) = L ( G ) L(r)=L(G) L(r)=L(G)
- 对于任何正规式r,都存在一个有限自动机M,使得 L ( M ) = L ( r ) L(M)=L(r) L(M)=L(r)
这里的证明好像是可以不用会,看着了解一下就ok
确定有限自动机的化简
一个确定有限自动机的化简是指:寻找一个状态数比M少的DFA M’,使得 L ( M ) = L ( M ′ ) L(M)=L(M') L(M)=L(M′)。
一个DFA M的状态数最少化过程旨在将M的状态集分割成一些不相交的子集,使得任何不同的两个子集中的状态都是可区别的,而同一子集中的任何两个状态都是等价的。最后,在每个子集中的任何两个状态都是等价的。最后,在每个子集中选出一个代表,同时消去其他等价状态。
化简步骤:
- 先按终态和非终态结点进行分组
- 在两个组分别做一步转移(注意这里不用再找空字闭包了,因为已经是DFA了,DFA中不包含空串)
- 观察两个组的后继结点是不是前继结点的子集,如果不是则要进一步分割,如果是就不用了
- 根据后继结点是否相同进行分割
- 将分割后的结点写在左侧进行进一步的划分
例子
请化简如下DFA M:
-
根据是否为终态结点划分为两个组: { 3 , 4 , 5 , 6 } , { 0 , 1 , 2 } \{3,4,5,6\},\{0,1,2\} {3,4,5,6},{0,1,2}
-
其次,考察 { 3 , 4 , 5 , 6 } \{3,4,5,6\} {3,4,5,6},由于 { 3 , 4 , 5 , 6 } a \{3,4,5,6\}_a {3,4,5,6}a和 { 3 , 4 , 5 , 6 } b \{3,4,5,6\}_b {3,4,5,6}b都包含于 { 3 , 4 , 5 , 6 } \{3,4,5,6\} {3,4,5,6},所以它不能再划分
-
再考察 { 0 , 1 , 2 } \{0,1,2\} {0,1,2},由于 { 0 , 1 , 2 } a = { 1 , 3 } \{0,1,2\}_a=\{1,3\} {0,1,2}a={1,3},它既不包含于 { 3 , 4 , 5 , 6 } \{3,4,5,6\} {3,4,5,6},也不包含于 { 0 , 1 , 2 } \{0,1,2\} {0,1,2}中,因此,他要划分,由于状态1经过 a a a弧到达状态3,而状态0,2经过 a a a弧到达状态1,因此,应该把1分出来,形成 { 1 } \{1\} {1}、 { 0 , 2 } \{0,2\} {0,2}
-
再考察 { 0 , 2 } \{0,2\} {0,2},由于 { 0 , 2 } b = { 2 , 5 } \{0,2\}_b=\{2,5\} {0,2}b={2,5},它没有包括在上述三组中,因此他要划分,形成 { 0 } \{0\} {0}, { 2 } \{2\} {2}
-
至此,整个划分有4个组: { 3 , 4 , 5 , 6 } \{3,4,5,6\} {3,4,5,6}, { 1 } \{1\} {1}, { 2 } \{2\} {2}, { 0 } \{0\} {0}。每个组都不可再划分,令状态3代表 { 3 , 4 , 5 , 6 } \{3,4,5,6\} {3,4,5,6},把原来到达4,5,6状态的弧都导入3,并删除4,5,6.这样就得到了下图----化简后的DFA
S | a | b |
---|---|---|
{0,1,2} | {1,3} | {2,5} |
{3,4,5,6} | {3,5,6} | {4,5} |
{0,2} | {1} | {2,5} |
{1} | {3} | {2} |
{0} | {1} | {2} |
{2} | {1} | {5} |
问题:在化简有限自动机的方法中,对其状态集合进行第一次划分时,正确的做法是划分为终态结点和非终态结点