编译原理笔记6:从正规式到词法分析器(3):DFA最小化、词法分析器的构造、Lex 使用示例

简介:

从 DFA 到最小 DFA

关于星闭包的补充:一个语言被认为是所有可能字的子集。所有可能字的集合可以被认为是所有可能的字符串串接的集合。

DFA 最小化的过程,就是通过某些等效转换减少原 DFA 状态数的过程——这里的“等效转换”,就是对多余的状态进行合并。

那,什么叫多余?这里的多余,指的是对于同样的输入会得到同样的结果——比如在上面NFA转DFA的例子中,我们观察得到的DFA,发现其中的A、C状态对于字母表中任意的输入,都会给出相同的结果。那么这个A和C对任意输入而言就是等效的,它们两个就可以互相替代,我们也就可以把它们合并成一个状态。

将DFA最小化需要去除多余状态,所以如何最小化DFA的问题就转化为了如何找出“多余状态”的问题。我们需要一个方法来帮助我们判断某个状态是否是多余的。这里引入“等价”、“可区分”、“划分”的概念:

等价

定义:设 p、q ∈ S,对于任一输入序列 w∈Σ*,有 move(p, w)∈F 且 move(q, w)∈F,则称状态 p 和 q 等价。否则称 p、q 是可区分的,也就是存在 x∈Σ*,使得move(p, x) 和 move(q, x) 不能同时进入终态。

可区分

对于DFA中的任意两个状态t、s,若从其中一个状态出发能够接受输入字符串 ω,而从另一个状态出发却不能接受 ω,则称 ω区分状态t和s。如果存在某个能够区分状态 t 和 s 的串,那么状态 t 和 s 就是可区分的。

因此,如果我们找到这样一对 t 和 s ,对于从它们两个状态分别出发的任何的输入序列 ω,都能够最终到达相同的结果,那么 t 和 s 就可以合并成一个状态。

因此,最小化 DFA 的本质,就是将 DFA 中的状态分成不同的组,使得同一个组中的状态之间不可区分(也就是等价的),而不同组的状态之间可区分(也就是不等价)。当我们把每个组内的状态都合并成为一个状态后,我们就能够得到一个最小 DFA 了

(其实就是把DFA中的各个状态划分成几个等价类,然后把等价类内的状态进行合并。这样最终得到的最小DFA的状态数就是之前我们划分的等价类数。每一个等价类对应最小DFA中的一个状态)

划分

给定一个DFA,我们可以确定:

  • DFA 的终态和非终态是可区分的;(使用 ε 即可区分终态和非终态。因为 DFA 中不存在 ε 转移。DFA 中的任意状态经过 ε 都不会发生改变)
  • 若分别从 s 和 t 出发,沿着标记为 x 的路径到达的两个状态p、q是可区分的,那么 s 和 t 也是可区分的。
    这里的 p、q 是我们已知可区分的——因为对于 p、q,如果有相同的输入序列 y 使得他们分别到达终态和非终态,那么 p、q 就是可区分的了。一旦 p、q 可区分,则 s、t 经过输入序列 xy 就能够分别到达 f、g ,也就随之满足可区分的定义了

3_11

算法:最小化 DFA 的状态数(DFA化简)

输入:DFA D = {S, Σ, move, s0, F }

输出:等价的 D' = {S', Σ, move', s0', F' }(D' 的状态数最少)

主要步骤:

  1. 进行初始化分,获得终态和非终态;
  2. 利用“可区分”的概念,反复分裂划分中的组 Gi,直到不可再分裂;
  3. 由最终划分构造 D',关键是用等价的概念对一些状态进行合并,选出新的代表状态并修改状态转移;
  4. 消除可能的死状态的不可达状态。

化简的基本思路,其实就是把原来的状态集按照等价关系进行划分(划分后的子集互不相交),同一子集内元素等价,不同子集元素可区分。将每一个子集中的状态合并成一个状态,就可以得到一个新的状态集 Snew,原初态s0所在子集就成为化简后状态机 Dnew 的新初态 s0new ,原终态所在子集就成为化简后的 Dnew 的一个新终态。

下面用这个算法来化简我们前面的 DFA
6_1
每个DFA都能够最小化,这里有个定理:

对于一个 DFA D = {S, Σ, mvoe, s0, F}, 存在唯一一个最小状态(就状态数而言)DFA D' = {S', Σ, move', s0, F'} 与 D 等价。

手写 DFA

建出来了 DFA 的状态转移图,我们就可以通过直接编码的方式来为我们的 DFA 手写词法分析器了。由于操作复杂,故实际应用中不会使用这种方法构造词法分析器,而是会使用 Lex 进行该工作。

此处先略,日后再补。。。(坑)

词法分析器的构造

实际应用中,我们使用工具来生成词法分析器。因为从正规式到词法分析器这个过程中的每一步都有对应的算法来实现。我们构造自己的词法分析器,只需要使用 Lex 就可以了。
6_2

Lex 使用示例

6_3
点击 Lex 中的 编译按钮 ,将会生成一个 .c 和一个 .h 文件

对于词法解析错误的输入,lex 编译出的程序将会直接把错误的输入回显

相关文章
|
自然语言处理 算法 编译器
编译原理复习一:正则表达式-NFA NFA-DFA DFA最小化(附题目与答案 超详细)
编译原理复习一:正则表达式-NFA NFA-DFA DFA最小化(附题目与答案 超详细)
1124 0
|
Ubuntu 安全
Ubuntu 安全重启 / Ubuntu 系统死机解决方法
初装Ubuntu双系统时,经常会遇到各种各样的问题导致系统崩溃、卡死、黑屏等情况,新手或者小白可能直接选择长按电源键强制重启了
4336 0
|
9月前
|
JSON API 网络架构
HTTP常见的请求方法、响应状态码、接口规范介绍
本文详细介绍了HTTP常见的请求方法、响应状态码和接口规范。通过理解和掌握这些内容,开发者可以更好地设计和实现W
1369 83
|
编译器
区分LR(0),SLR(1),LR(1)和LALR(1)
区分LR(0),SLR(1),LR(1)和LALR(1)
1547 0
|
12月前
|
监控 NoSQL Java
若依RuoYi项目环境搭建教程(RuoYi-Vue + RuoYi-Vue3版本)
若依(RuoYi)是一款基于Spring Boot和Vue.js的开源Java快速开发脚手架,支持OAuth2、JWT鉴权,集成多种安全框架和持久化框架。它提供了系统管理、监控管理、任务调度、代码生成等常用功能模块,适合中小型公司快速搭建Web应用。本文主要介绍若依框架的特点、版本发展、优缺点及项目部署步骤,帮助开发者快速上手并部署若依项目。
13414 3
若依RuoYi项目环境搭建教程(RuoYi-Vue + RuoYi-Vue3版本)
|
12月前
|
运维 监控 安全
Landing Zone一站式上云框架场景和实践
本文将介绍阿里云Landing Zone的方案、应用场景及新功能。Landing Zone是云上安全可控、可扩展的架构,涵盖资源规划、财务管理、身份权限、合规审计、网络规划、安全防护、运维管理和自动化模块八大方面,帮助企业敏捷创新并满足IT治理需求。具体应用包括零售行业的多品牌管理、生命科学的数据交换、自动驾驶的合规监管和金融行业的严格合规要求。新功能则聚焦于财年上线的统一管控产品,如配额管理、Prometheus监控和网络IPAM方案,以及降低跨账号安全门槛。
|
SQL 关系型数据库 MySQL
在 MySQL 中使用 Exists
【8月更文挑战第11天】
1868 0
在 MySQL 中使用 Exists
|
存储 虚拟化 云计算
|
存储 JSON JavaScript
【YAML语法规范指南】从入门到精通,揭秘神秘语法,引领配置文件解析指南(基础结构篇)
"YAML Ain't Markup Language"(简称YAML)是一种专为人类设计的数据序列化语言,适用于多种现代编程语言,可广泛应用于各类日常任务。它是一种以人类可读形式呈现的、适用于多种语言的Unicode数据序列化标准。它基于敏捷编程中常见的本地数据结构,广泛应用于配置文件、互联网消息传递、对象持久化以及数据审计等多个领域。遵循Unicode标准、
1113 8
【YAML语法规范指南】从入门到精通,揭秘神秘语法,引领配置文件解析指南(基础结构篇)
|
安全 Unix Linux
在 openEuler 上安装桌面环境
在 openEuler 上安装桌面环境
740 0