编译原理笔记16:自下而上语法分析(3)构造 DFA、DFA 对下一步分析的指导(有效项目)

news2025/1/17 1:07:19

目录

    • 由 NFA 用子集法构造 DFA
    • 由 LR(0) 项目直接构造识别活前缀的 DFA
      • 构造 DFA
        • 求拓广文法 G'
        • CLOSURE & GO
          • 例:
        • 构造 DFA
    • DFA 指导下一步分析
      • 有效项目

看了前面的内容,我们已经了解到:分析表和驱动器算法,是 LR 分析器的核心。

在分析的过程中,语法分析器总是根据栈顶的状态、当前剩余输入的第一个终结符查询分析表,以确定改变格局的动作并执行,实现对栈和剩余输入的内容的修改,从一个格局转移到另一个格局,如此往复直至分析完毕(或报错)。

下面我们就来研究一下如何从文法构造 DFA —— 这是构造 LR(0) 、SLR(1) 分析表的第一步。

由 NFA 用子集法构造 DFA

前一篇博客中讲解了该如何构造 NFA,有了 NFA 就可以使用子集法构造 DFA 了。

构造方法与词法分析的 NFA 转 DFA 类似,此处不再重复,接下来说一些该 DFA 的特点。

在这里插入图片描述

DFA 中的每个状态都是原 NFA 的状态集(因为 DFA 是 NFA 使用子集法构造的)。而又因 NFA 的每个状态都对应一个项目,所以 DFA 中的每个状态又是一个项目集。

DFA 的初态由原 NFA 初态求 ε-闭包得到,DFA 中的所有状态都是其终态。

(类比子集法构造词法分析 DFA——DFA 的终态是包含原 NFA 终态的那些状态,而原来的那个 NFA 本身就已经所有状态均为终态了,也就是说从初态出发到达任何一个状态的路径所标记的连接都是该 DFA 可识别的活前缀。同理,原来的句柄识别态到这里依然是适用的,就是图中的 1、8、10、6、7、11、9 )

该识别活前缀的 NFA 和原来的词法分析 NFA 有一个重大差别:词法分析 NFA 状态号就只是一个编号,而此处的状态编号却是和项目相对应的——每个编号就对应着一个项目,而且状态的转移关系也是基于这些项目建立起来的。

那么。。其实也可以直接从项目构造 DFA

由 LR(0) 项目直接构造识别活前缀的 DFA

LR(0) 项目集规范族:构成识别一个文法活前缀的 DFA 的项目集(状态)的全体,称为这个文法的 LR(0) 项目集规范族。这个规范族提供了建立一类 LR(0) 和 SLR 分析器的基础。

实际上,这个【规范族】就是我们要构造的识别活前缀的 DFA 的状态的全体——上面那个 DFA 中所有的矩形状态加起来就是了。主要是因为 DFA 的每个状态都是一个 LR(0) 项目集,所以就想起来这么个骚名字叫做【LR(0) 项目集规范族】

(如果题目让计算一个LR(0) 项目集规范族,那其实就是要计算识别活前缀的 DFA。有了 DFA 就可以构造 LR(0) 分析表和 SLR(1) 分析表了)

我们先给项目做做分类、起起名字,后面要用到:

  • 圆点在最右端的项目(如 A → α. ,A 不是拓广文法的开始符号)称为”规约项目“,在出现规约项目的状态就可以进行规约动作;
  • 文法开始符号 S’ 的规约项目称为”接受项目“(比如 S’ → α. );
  • 形如 A → α.aβ 的项目称为”移进项目“,a 为终结符。在该状态下,如果下一个输入是终结符 a 则可以进行移进动作;
  • 形如 A → α.Bβ 的项目称为”待约项目“,B 为非终结符。”待约项目“的含义是【等待把 B 规约出来】:若想按照该产生式进行规约,就得先想办法把 B 搞出来,看到 B 之后才能进行后面的规约动作;(B 是非终结符,可是输入序列中么的非终结符啊。。因此,想要用这个产生式进行规约那需要凑齐该产生式的右部——先把输入序列中由 B 推导出来的符号序列规约成 B 就可以了)

构造 DFA

求拓广文法 G’

拓广文法: G’ = G ∪ { S’ → S }

其实就是先引入一个新的非终结符 S’ 作为拓广文法的新的开始符号,并引入新的产生式 S’ → S

CLOSURE & GO

  1. CLOSURE( I ):从项目集 I 不经过任何文法符号到达的项目全体(和词法分析中的 ε-闭包(I) 的含义相同)
  2. GO( I, X ):所有从 I 经文法符号 X 能到达的项目全体(只需要到达就好了,不止一步也可以。因此要先计算直接到达的,再在能够直接到达的基础上求闭包。因此显然,GO 和词法分析 NFA 的 smove 的功能不对等:GO 含有闭包计算)。X 只是一个文法符号,终结符、非终结符均可。
例:

对于下面的文法 G,若 I={ S → .E }

S' → E
E → aA | bB
A → cA | d
B → cB | d
  • 求 CLOSURE(I)

    CLOSURE(I) = { S’ → .E, E → .aA, E → .bB }

    首先,S’ → .E 是项目集自身元素,自然不需要经过任何文法符号即可到达。后两个项目则是因为他们均可由初态通过 ε 边即可到达,同样满足【从项目集 I 不经过任何文法符号到达的项目】这一要求。(此处可以脑补一下 NFA 图)

  • 求 GO(I, a)

    GO(I, a) = { E→a.A, A→.cA, A→.d }

    首先, E→a.A 是直接而从 I 中的项目出发经过 a 能够到达的项目。后面两个项目则可由这个 E→a.A 通过 ε 边可到达。这也符合“所有从 I 经文法符号 a 【能】到达的项目全体”这一定义。

构造 DFA

构造下面的文法 G’ 的 DFA

E' → E
E → E-T | T
T → T*F | F
F → -F | id

首先求 CLOSURE( {E’ → .E} ),并将其作为整个 DFA 的初态,即:

I0 = CLOSURE( {E’ → .E} ) = { E’ → .E, E → .E-T, E → .T, T → .T*F, T → .F, F → .-F, F → .id }

将 I0 作为初态,其实也就是像下图左边这样,画一个矩形大方框再把 I0 里面的这些个项目依次写进去。。这整个一个方框就是我们的 DFA 的初态了。接下来就可以从该初态出发,逐步构造 DFA 。这个逐步构造的过程,无非也就是【挨个算一下从初态的各个项目起,经过哪些文法符号可以得到哪些新项目】,新项目自然也就可以形成新的状态,通过转移用的文法符号与原来的状态相连。

在这里插入图片描述

使用同样的规则重复操作(摊大饼),最后能得到如下图所示的 DFA

在这里插入图片描述

该 DFA 就能够用来识别活前缀了。与词法分析 DFA 不同的是,该 DFA 的任何一个状态都是终态。这也就意味着,从初态开始到任一个状态所形成的路径上面的标记连接起来,都是一个 DFA 能够识别的活前缀。

比如,对于状态3(即 I3),其能够识别的活前缀有 F 和 E-F;状态6能够识别的活前缀只有 E-

现在,我们再回头看一下移进规约的过程就会发现一些有意思的东西

在这里插入图片描述

确实,每个时刻,栈中的内容都和分析表、自动机有着关联。我们可以尝试去读栈中任一时刻的元素(从栈底到栈顶),这些状态号、文法符号相间的序列均能在上图左边的 DFA 中和一条路径相匹配。

DFA 指导下一步分析

  1. DFA 每个状态识别的活前缀不同;
  2. 对语法结构正确的输入序列进行分析的任一时刻,若此时分析器正处于 DFA 的某状态 i ,则状态 i 识别的活前缀出现在栈中,且状态 i 正位于栈顶。语法分析器正是根据此刻状态 i 中包含的 LR(0) 项目来指导下一步分析的;
  3. 状态 i 中出现的 LR(0) 项目对状态 i 能够识别的活前缀有效。

好的,DFA 看起来是个好东西,那么我们现在假设栈顶是 5 状态,此时 DFA 怎么指导下一步的分析呢?

有效项目

若存在最右推导:S’ =*> αAω => αβ1β2ω ,则称项目 A → β12 对活前缀 αβ1 有效。

项目 A → β12 对活前缀 αβ1 有效,作用是说明:在当前活前缀为 αβ1 的情况下,当前状态中的 A → β12 这个项目可以指导下一步的分析动作为: αAω => αβ1β2ω 。

我觉得吧:已经读到并且已经入栈的东西,全都是活前缀。活前缀呢,就是仍然可以活动的前缀——根据其后添加的符号不同,这个活前缀可能会变成某个句柄——也就是说,活前缀能够在后面加入某些新的符号之后成为某个产生式的右部,也就可以被用这个产生式规约掉。

对于符号串 αβ1β2ω ,看起来应该是可以使用 A → β1β2 对其进行规约。读写头在读输入序列的时候是一个一个符号去读,读到了要移进的也是一个接着一个压栈。当栈中是 αβ1 (即当前活前缀是 αβ1 )时,如果我们已经知道有这么个项目: A → β12 ,那就说明如果下一个读到了 β2 ,栈顶就能够形成该产生式的句柄,我们也就可以利用这个项目的下一步项目 A → β1β2. 进行规约了。

这其实就体现了 DFA 对分析的指导作用。

在这里插入图片描述

可知:同一项目集中的所有项目,对此项目集的所有活前缀均有效。即,项目集中的每个项目均有同等权利指导下一步动作。

有效项目的意义:

  1. 项目到目前为止的分析均是正确的;
  2. 可以指导下一步的分析:
    1. A → α.aβ(可移进项):若当前剩余输入为终结符 a ,则移进 a;
    2. B → β. (可规约项):按产生式 B → β 进行规约。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/678326.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实训四:索引与视图 - SQL视图(teachingdb数据库)

SQL视图的定义与操纵 第1关:创建视图任务描述相关知识视图的定义创建视图 编程要求测试说明参考代码 第2关:创建视图-练习一任务描述相关知识编程要求测试说明参考代码 第1关:创建视图 任务描述 本关任务:建立计算机系的学生的视…

团体程序设计天梯赛-练习集L1篇⑧

🚀欢迎来到本文🚀 🍉个人简介:Hello大家好呀,我是陈童学,一个与你一样正在慢慢前行的普通人。 🏀个人主页:陈童学哦CSDN 💡所属专栏:PTA 🎁希望各…

C语言scanf/fscanf/sscnaf和printf/fprintf/sprintf的区别

总结 1.scanf/printf 是标准输入输出流函数(键盘、屏幕)。 2.fscanf/fprintf 适用于所有输入输出流(文件、键盘、屏幕…)。 3.sscanf/sprintf 是把格式化的数据写入某个字符串中,从某个字符串中读取格式化的数据。 第一组:scanf/printf scanf/printf是…

Oracle数据库从入门到精通系列之十八:详细总结Oracle数据库核心知识点

Oracle数据库从入门到精通系列之十八:详细总结Oracle数据库核心知识点 一、Oracle数据库核心概念二、Oracle非容器数据库三、Oracle容器数据库四、容器数据库和非容器数据库的区别五、Oracle数据库多租户六、Oracle数据库多租户数据库模型七、Oracle数据库类型八、O…

实训四:索引与视图 - MySQL开发技巧 - 索引

MySQL开发技巧 - 索引 任务描述相关知识索引是什么索引的分类索引的创建和删除查询表中索引 编程要求测试说明代码参考: 任务描述 本关任务:按照要求完成索引的创建。 相关知识 为了完成本关任务,你需要掌握: 索引是什么&#…

【Leetcode60天带刷】day31回溯算法——455.分发饼干 ,376. 摆动序列 , 53. 最大子序和

​ 题目: 455. 分发饼干 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块…

Android 13(T) - binder阅读(3)- binder相关的类

原先准备在binder阅读(3)中记录ServiceManager的使用,但是写着写着发现,如果不了解和binder相关的类,那么阅读起来将会由很多困惑,所以就先来记录binder相关的类了。记录完发现特别凌乱…先就这样吧。 1 UM…

【致敬未来的攻城狮计划】打卡3:点亮LED

点亮LED 本文主要参考文章:【致敬未来的攻城狮计划】— 连续打卡第十一天:FSP固件库开发点亮第一个灯。_嵌入式up的博客-CSDN博客 在32阶段我们已经接触过类似做法了。初始化引脚模式(可以手动库函数,或者在工具包图形化界面里配…

实训四:索引与视图 - MySQL开发技巧 - 视图

MySQL开发技巧 - 视图 任务描述相关知识视图的定义创建视图操作视图删除视图 编程要求测试说明参考代码 任务描述 本关任务:通过学习视图,创建一个单表视图和一个多表视图。 相关知识 为了完成本关任务,你需要掌握: 视图的定义…

工地扬尘智能监测系统 yolov7

工地扬尘智能监测系统通过yolov7网络算法模型技术,实时监测工地施工中的扬尘情况。工地扬尘智能监测系统利用AI视频智能分析技术,并将数据传输到数据中心进行分析。YOLOv7 的发展方向与当前主流的实时目标检测器不同,研究团队希望它能够同时支…

数据库管理-第八十四期 X10M来了(20230624)

数据库管理 2023-06-24 第八十四期 X10M来了1 Intel -> AMD2 PMEM -> XRMEM3 DDR4 -> DDR54 Flash cards总结 第八十四期 X10M来了 在第四十三期的时候,我曾经憧憬过Exadata X10M的到来,Oracle于6月22日正式公布Exadata X10M系列。其实5月已经…

chatgpt赋能python:Python在电气行业中的应用——从数据分析到自动化控制

Python在电气行业中的应用——从数据分析到自动化控制 介绍 Python语言作为一种高级编程语言,越来越受到电气行业的关注。随着互联网、物联网以及大数据时代的到来,电气行业需要将传统的工业控制与现代化的数据分析、智能决策等技术相结合,…

Java——《面试题——Dobbo篇》

前文 java——《面试题——基础篇》 Java——《面试题——JVM篇》 Java——《面试题——多线程&并发篇》 Java——《面试题——Spring篇》 Java——《面试题——SpringBoot篇》 Java——《面试题——MySQL篇》​​​​​​ Java——《面试题——SpringCloud》 目录…

springboot+mybatis笔记学习

1.环境搭建 1.引入pom依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version> </dependency> <dependency><groupId>org…

人工智能(2):机器学习算法分类

根据数据集组成不同&#xff0c;可以把机器学习算法分为&#xff1a; 监督学习无监督学习半监督学习强化学习 1 监督学习 定义&#xff1a; 输入数据是由输入特征值和目标值所组成。 函数的输出可以是一个连续的值(称为回归&#xff09;&#xff0c;或是输出是有限个离散值&…

07- c语言字符串 (C语言)

一 字符串的定义及基本使用 1、什么是字符串 被双引号引用的字符集合&#xff01;例如&#xff1a;”hello” 、”world”&#xff0c;或者是以 \0 结尾的字符数组&#xff01;&#xff01;&#xff01; 比如&#xff1a;char ch[] {h, e, \0} 注意&#xff1a;”hello” 中…

Win10同时安装MYSQL5.7和MYSQL8.0版本

一、准备好两个MySQL版本的压缩包 官网下载网址&#xff1a;https://dev.mysql.com/downloads/ 二、安装 MYSQL5.7 2.1、解压文件夹&#xff0c;然后新建一个 my.ini文件 my.ini文件内容: [mysql] # 设置mysql客户端默认字符集 default-character-setutf8 port 3305 [mysq…

leetcode1.两数之和

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【LeetCode】 &#x1f353;希望我们一起努力、成长&#xff0c;共同进步。 题目链接 给定一个整数数组 nums 和一个整数目标值 target&am…

FPGA-DFPGL22学习1-上手开发板

文章目录 前言一、FPGA是什么&#xff1f;二、FPGA内部结构1) 可编程输入/输出单元2) 基本可编程逻辑单元3) 嵌入式块 RAM4) 丰富的布线资源5) 底层嵌入功能单元 Logos 系列芯片 前言 和原子哥一起学习FPGA 开发环境&#xff1a;正点原子 ATK-DFPGL22G 开发板 参考书籍&…

mysql没有data和my.ini文件怎么办?

目录 一、前言 二、其他知识 一、前言 data是存储mysql数据的地方&#xff0c;ini是mysql配置文件的地方&#xff0c;要配置文件就可以在ini里面配置就好了。在mysql的安装位置没有发现这两个文件&#xff0c;不是没有&#xff0c;而是在其他地方。&#x1f447; 其实这两个…