编译原理第三章笔记 -- 词法分析

本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社

对词法分析器的要求

词法分析的任务

从左到右逐个字符地扫描源程序,产生一个个的单词符号,把作为字符串的源程序改造称为单词符号串的中间程序

词法分析器/扫描器:执行词法分析的程序

词法分析器的功能如下图:

输入源程序,输出单词符号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Iv41XUs9-1678365454067)(http://cdn.hydrion-qlz.top/gitee/202201211134972.png#pic_center)]

  • 关键字
    • 由程序语言定义的具有固定意义的标识符。也可以称为保留字或基本字。如:if,else。他是确定
  • 标识符
    • 用来表示各种名字,如变量名、数组名、函数名等,他是不限
  • 常数
    • 常数的类型一般有整型、实型、布尔型、文字型等。他是不限的。
  • 运算符
    • 运算符:如+、-、*、/等,他是确定
  • 界符
    • 界符:如逗号、分号、括号等,他是确定

确定:代表该类型符号是可枚举的

不限:代表该类型符号是不可枚举的

单词符号的表示形式

词法分析器的功能和输出形式

词法分析器所输出的单词符号常常表示成二元式:(单词种别,单词自身的值)

单词种别可以用以下形式表示:

  1. 一类单词统一用一个整数值代表其属性。例如:1代表关键字,2代表标识符等
  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作为一个独立的子程序
  • 词法分析器的任务为输出单词符号

预处理

  • 必要性:编辑性字符如空白符、回车符等,除了出现在文字常数中以外,在别处出现都没有意义。
  • 功能:剔除无用字符
  • 实现:预处理子程序

image-20220228081222033

  • 输入:曾经是纸带,所以图中的样子是多个文件
  • 列表是对输入缓冲区的内容进行统计记录
  • 预处理子程序从输入缓冲区读入字符,将扫描结果放入扫描缓冲区交由扫描器使用
  • 语法分析器调用扫描器,扫描器调用预处理子程序,预处理子程序和扫描器都可以返回当前处理结果
  • 扫描器查看扫描缓冲区是否准备好字符串,如果没有准备好则调用预处理子程序

例子:识别输入语句IF (5.EQ.M) GOTO 100

image-20220228085906436

缓冲区的大小不够容纳整条语句

image-20220228085920785

image-20220228085933863

扫描缓冲区的结构

  • 缓冲区大小:120个字符
  • 采用两个指示器:起点指示器、搜索指示器
  • 两个互补的缓冲区

单词符号的识别----超前搜索

单词符号识别的简单方法:超前搜索

FORTRAN语言是第一个高级编程语言,所以本门课程大量使用FORTRAN程序代码

  • 标识符的识别
    • 多数语言的标识符是字母开头的“字母/数字”串,而且在程序中标识符的出现后都跟着算符或界符。因此不难识别
  • 常数的识别
    • 对于某些语言的常数的识别也需要使用超前搜索
  • 算符和界符的识别
    • 对于诸如C++语言中的“++”、“–”,这种复合成的算符,需要超前搜索

状态转换图

  • 转换图:是一张有限方向图。在状态转换图中,结点代表状态,用圆圈表示。状态之间用箭弧连接。箭弧上的**标记(字符 )**代表在射出节点状态下可能出现的输入字符或字符类
  • 状态转换图的功能:识别符合一定要求的字符串
    • 可能有若干条要求,对于每一个要求都可以建立一个状态转换图
    • 状态转换图可以与词法分析器中的每一个程序段对应起来
  • 初态:一张完整状态转换图的启动条件,至少有一个,用圆圈表示
  • 终态:一张完整状态转换图的结束条件,至少有一个,用双圈表示
  • 终态上的*:表示多读进了一个不属于标识符部分的字符

简单的状态转换图的示例

a:是状态转换图的子图,是不完整的

b:识别标识符的转换图

c:识别整数的转换图

d:识别FORTRAN实型常数的转换图,例如 1.23E+4 和 .56E-7

image-20220228083356450

综合示例----做出识别下表所示的小语言的单词符号的状态转换图

  • 标志符和常数都是一类一种,其他的是一类一种,所以没有内码值
  • 每一行都是一条构词规则

image-20220519190021439

词法分析的转换图

image-20220519190030793

状态转换图的实现

  • 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(或者是一个整数值,或者无定义)

为了把状态转换图转化成程序,每个状态要建立一段程序,它要做的工作如下:

  1. 从输入缓冲区中取一个字符。为此,我们使用函数GetChar,每次调用它,推进先行指针,送回一个字符
  2. 确定在本状态下,哪一条箭弧是用刚刚来的输入字符标识的。如果找到,控制就转到该弧所指向的状态;若找不到,那么寻找该单词的企图就失败了
  3. 先行指针必须重新回到开始指针处,并用另一状态图来搜索另一单词。如果所有的状态转换图都试过之后,还是没有匹配的,就表明这是一个词法错误,此时,调用错误校正程序

image-20220228100845535

状态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, _)

总结

词法分析方法包括以下步骤:

  1. 给出程序设计语言的单词规范
  2. 对照单词表设计识别改语言所有单词的状态转换图
  3. 根据状态转换图编写词法分析程序

该方法是手工方式,效率比较低

词法分析器的设计:

  1. 给出程序设计语言的单词规范——单词表
  2. 对照单词表设计识别该语言所有单词的状态转换图
  3. 根据状态转换图编写词法分析程序

正规表达式与有限自动机

预备知识

字母表是一个非空有穷集合,通常用 Σ \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={abaΣ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=Σn1Σ,n1

字母表的闭包

每个闭包都至少包含一个串,允许串无限长

  • Σ \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Σ+={ε}Σ+

字母表和闭包的关系举例:

image-20220519190057575

句子

建议用串来理解

对于任何 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=V0V1V2...
  • V的正则闭包: V + = V V ∗ V^+=VV^* V+=VV

空串 ε \varepsilon ε不是字母表中的元素,phi是吗?

ε \varepsilon ε是字,但是 Φ \Phi Φ不是字是集合

正规式与正规集的递归定义:

  1. ε \varepsilon ε Φ \Phi Φ都是字母表 Σ \Sigma Σ上的正规式,它们所表示的正规集分别为 { ε } \{\varepsilon\} {ε} Φ \Phi Φ
  2. 任何 a ∈ Σ a\in \Sigma aΣ,a是 Σ \Sigma Σ上的一个正规式,它所表示的正规集为 { a } \{a\} {a}

image-20220519190114603

仅由有限次使用上述三步骤而得到的表达式是字母表 Σ \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} 正规式(AB)(AB∣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} 正规式baa(ab)(ab)(aabb)(ab)正规集Σ上所有的以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(ab)=(ab)

关系

令U、V和W均为正规式,显而易见,下列关系普遍成立:

  • 交换律: U ∣ V = V ∣ U U|V = V|U UV=VU
  • 或结合律: U ∣ ( V ∣ W ) = ( U ∣ V ) ∣ W U|(V|W)=(U|V)|W U(VW)=(UV)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(VW)=UVUW
    • ( V ∣ W ) U = V U ∣ W U (V|W)U=VU|WU (VW)U=VUWU
  • 吸收律: ε 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),其中:

  1. S是一个有限集,它的每个元素称为一个状态
  2. Σ \Sigma Σ是一个有穷字母表,它的每个元素称为一个输入字符
  3. δ \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的一个后继状态
  4. s 0 ∈ S s_0\in S s0S是唯一的初态(不可空)
  5. F ⊆ S F\subseteq S FS是一个终态集(可空)

单值映射的后面一定是唯一的,也可以没有,即至多一个

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
则其相应的状态转换矩阵如下表:

状态ab
012
132
213
333

在该例子中共有四个状态,两个字符

另外如果题目要求由DFA转换为五元式的时候会在表中写出来初态和终态

初态其实可以根据图判断出来:只有出度,没有入度

一个DFA也可以用一张(确定的)状态转换图来表示。假定DFA M含有m个状态n个输入字符,那么,这个状态转化图含有m个状态结点,每个结点顶多有n条箭弧射出和别的结点相连接,整张图含有一个初态结点和若干个(可以为0)终态结点(需要双圈表示)。

image-20220519185602985

例如可以识别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表示全体实数

image-20220519190201001

DFA的五元式可以转换为状态转移矩阵,状态转移矩阵又和状态转换图有一一对应的关系

例3

约定进入的有向箭头表示初态节点

image-20220519190210773

例4

注意二者中的区别

串中只有一个b可以被接受的DFA:

image-20220519190220307

接受包含最多一个b的串的DFA:

image-20220519190230781

定理:如果一个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 sS和输入符号 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},其中:

  1. S是一个有限集,它的每一个元素称为一个状态
  2. Σ \Sigma Σ是一个有穷字母表,它的每个元素称为一个输入字符
  3. δ \delta δ是一个从 S × Σ ∗ S\times \Sigma^* S×Σ至S的子集的映射,即 δ : S × Σ ∗ → 2 s \delta:S\times \Sigma^*\rightarrow2^s δ:S×Σ2s
  4. S 0 ⊆ S S_0\subseteq S S0S是一个非空初态集
  5. F ⊆ S F\subseteq S FS是一个终态集(可空)

一个含有m个状态和n个输入字符的NFA可用一张如下的状态转换图来表示:该图含有m个状态结点,每个结点可以射出若干条弧与别的结点相连接,每条弧用 Σ ∗ \Sigma^* Σ中的一个字(可以是不同的字,也可以是空字)做标记,整张图至少含有一个初态结点和若干个(可以是0个)终态结点。某些结点既可以是初态结点也可以是终态结点

image-20220305231638807

例子

例一

下图所示的状态转换图 S , Σ , Σ ∗ S,\Sigma,\Sigma^* S,Σ,Σ如下:

看箭弧上标的是字母还是串

  • 如果是串(或者包含 ε \varepsilon ε),则是NFA
  • 否则是DFA

x,y是引入的一个状态节点,确保初态结点和终态结点只有一个,箭弧使用空字来表示

image-20220307081516963

对于 Σ ∗ \Sigma^* Σ中的任何一个字 α \alpha α,若存在一条从某一初态结点到某一终态节点的道路,且这条道路上所有弧上的标记字依照顺序连接成的字(忽略 ε \varepsilon ε)等于 α \alpha α,则称 α \alpha α可以为NFA M识别

在本例中,从初态x到终态y的连接通路弧上,有如下标记字: ε ε a a ε ε \varepsilon\varepsilon a a \varepsilon \varepsilon εεaaεε,去除 ε \varepsilon ε,为aa,所以字aa可以被NFA接受

例二

语言:正确的有效的串的集合,与正规式对应的正规集

image-20220307082540392

例三

image-20220307082823137

DFA与NFA的区别

DFA可以看成是NFA的特例

  • 从状态图看NFA和DFA的区别
    • NFA可以有多个初态
    • 弧上的标记可以是 Σ ∗ \Sigma^* Σ中的一个字(甚至可以是一个正规式),而不一定是单个字符
    • 同一个字可能出现在同状态射出的多条弧上
  • DFA是NFA的特例
NFADFA
初始状态不唯一唯一
弧上的标记字(单字符字、 ε \varepsilon ε字符
转换关系非确定确定

确定化

这里有一道大题,比较简单

ε \varepsilon ε_CLOSURE(I)定义

DFA是NFA的特例,可以采用子集法将NFA确定化

假定I是NFA M的状态集的一个子集,我们定义 ε \varepsilon ε_CLOSURE(I)为:

  • s ∈ I s\in I sI,则 s ∈ ε _ CLOSURE(I) s\in \varepsilon\_\text{CLOSURE(I)} sε_CLOSURE(I)
  • s ∈ I s\in I sI,那么从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的一步转移,然后再找空字闭包

子集算法
  1. 表的初始化构造

Σ = { 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)

  1. 处理表的一行

这里简化成了只有两个元素

如果某一行的第一列的状态子集已经确定,例如记为 I I I,那么,求出这一行的第二个和第三个子集 I a I_a Ia I b I_b Ib看它们是否已在表的第一列出现,将未出现的填入到后面空行的第一列中。

  1. 重复处理

重复上述过程,直至所有第二列和第三列的子集均已在第一列上出现了为止

例子
例一

image-20220519190320721

处理步骤:

  • 找初始节点的空字闭包,写到第一行的第一列

  • 再找一步转移闭包,再找空字闭包,写第一行的后面所有各列

  • 然后看该集合是不是在第一列出现了

    • 如果没出现把他写到第一列继续处理
  • 直到全部处理结束

最后得到如下图右侧的表格所示的状态转换矩阵

对右下图表中的所有子集重新命名,得到左图中的状态转换矩阵,从而得到相应的DFA。如图所示:

初态结点标记为0,其他继续往上加

image-20220307090242611

包含了原终态结点的最后在状态转换图上全部都要画成终态结点,即两个圈圈的节点

image-20220307090544793

例二

image-20220307091516682

如果给的结点有多个初始结点,需要自己引入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

image-20220308003244331

确定有限自动机的化简

一个确定有限自动机的化简是指:寻找一个状态数比M少的DFA M’,使得 L ( M ) = L ( M ′ ) L(M)=L(M') L(M)=L(M)

一个DFA M的状态数最少化过程旨在将M的状态集分割成一些不相交的子集,使得任何不同的两个子集中的状态都是可区别的,而同一子集中的任何两个状态都是等价的。最后,在每个子集中的任何两个状态都是等价的。最后,在每个子集中选出一个代表,同时消去其他等价状态。

化简步骤:

  • 先按终态和非终态结点进行分组
  • 在两个组分别做一步转移(注意这里不用再找空字闭包了,因为已经是DFA了,DFA中不包含空串)
  • 观察两个组的后继结点是不是前继结点的子集,如果不是则要进一步分割,如果是就不用了
  • 根据后继结点是否相同进行分割
  • 将分割后的结点写在左侧进行进一步的划分

例子

请化简如下DFA M:

image-20220307093520964

  • 根据是否为终态结点划分为两个组: { 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

image-20220308004714859

Sab
{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}

问题:在化简有限自动机的方法中,对其状态集合进行第一次划分时,正确的做法是划分为终态结点和非终态结点

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hydrion-Qlz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值