编译原理笔记17:自下而上语法分析(4)LR(0)、SLR(1) 分析表的构造

news2025/1/16 7:43:08

目录

    • LR(0) 文法
      • LR(0) 分析表的构造
    • SLR(1) 文法
      • SLR 分析表构造
    • 非 SLR(1) 文法举例
      • 二义文法都不是 SLR(1) 文法
      • 不是二义文法的非 SLR(1) 文法

LR(0) 文法

若一个文法 G 的拓广文法 G’ 的识别活前缀的自动机中的每个状态(项目集)均不存在下述情况:

  1. 既有移进项目又有规约项目(移进-规约冲突);
  2. 含有多个规约项目(规约-规约冲突),

则称 G 为一个 LR(0) 文法

(移进项目就是指圆点右边是终结符的项目,规约项目指的就是圆点在右部最右端的项目)

如下图所示就不是一个 LR(0) 文法,红框状态中的项目中均存在移进-规约冲突,且均是上面的项目为规约项、下面的项目为移进项。

在这里插入图片描述

LR(0) 文法可以直接通过识别活前缀的 DFA 来构造 LR 分析表

LR(0) 分析表的构造

假定 C = {I0, I1, … , In} (aka. LR(0) 项目规范族、DFA 状态集)

首先为文法产生式进行编号,拓广文法的产生式要标记为 0(这里就是后面分析表中 rj 的产生式编号 j 的由来)

然后令每个项目集 Ik 的下标 k 作为分析器的状态(行首),包含 S’ → .S 的集合下标为分析器的初态(也就是 DFA 的初态,一般都是 0 )。

下面用一个例子来说明 ACTION、GOTO 子表的构造:

  1. 对产生式进行编号并画出 DFA

    (0)  S' → E
    (1)  E → aA
    (2)  E → bB
    (3)  A → cA
    (4)  A → d
    (5)  B → cB
    (6)  B → d
    

在这里插入图片描述

  1. 根据 DFA 的项目集确定分析器状态,写出分析表的行下标(行首)。并根据分析表的要求写出 ACTION、GOTO 子表的列下标(列首)。ACTION 表列下标是所有的终结符,GOTO 表的列下标是除了拓广文法新加入的非终结符之外的所有其他非终结符
    在这里插入图片描述

  2. 填写表格内容——实际上就是把 DFA 中的各个转移的边都挪进来。具体就是要逐个去看

    1. 对于移进项目:从初始的 0 状态出发,有一条标记为 a 的边连接到 2 状态。这就说明,进行语法分析的过程中,当栈顶为 0 状态且剩余输入为 a 时,就需要执行移进动作——将 a 移进栈,并紧接着将 DFA 的状态转移到 2。因此,0 行 a 列填入 s2。同理,0 行 b 列填入 s3。
      在这里插入图片描述

    2. 对于待约项目:对标记为非终结符的边,填写 GOTO 表 。例如,次栈顶为 0、栈顶为 E 时,语法分析器会转移到 1 状态。因此将 1 填写在第 0 行 E 列的位置上。
      在这里插入图片描述

    3. 对于接收状态。接受状态时输入序列全部读完,所以剩余输入是 # 。即,当前栈顶为 1 状态且剩余输入为 # 时可以执行接收动作,因此第 1 行 # 列填入 acc。
      在这里插入图片描述

    4. 对于规约项。用状态 6 举例。当到达状态 6 时,无论剩余输入字符是什么终结符,都可以进行规约了。对于状态 6 中项目所描述的 E → aA.,显然可以用产生式 (1) E → aA进行规约。因此,ACTION 表中第 6 行的所有列均填入 r1

    用上面四点的规则填写整张表,最后得到完成的 LR(0) 分析表如下图所示

在这里插入图片描述

SLR(1) 文法

SLR(1) 为解决冲突提出了一个简单的方法:通过识别活前缀的 DFA 和【简单向前看一个终结符】构造 SLR(1) 分析表。

如果我们的识别活前缀的 DFA 中存在移进-规约冲突、规约-规约冲突,都可以尝试使用这个方法来解决冲突。(这里说【尝试】,当然是因为 SLR 也只能解决一部分问题,并不是万能的灵丹妙药。。)

这里,我们拿前面那个 LR(0) 解决不了的文法来举例

在这里插入图片描述

该文法不是 LR(0) 文法,但是是 SLR(1) 文法。

观察上图 DFA 中的状态2,想象当我们的自动机正处于这个状态:次栈顶已经规约为 T 了,栈顶也是当前的状态 2 ,而当前剩余输入为 *。

如果这个自动机不会【往前多看一步】的话,那么对处于这个状态的自动机来说,看起来状态 2 中的移进项目和规约项目都是可选的。这就是移进-规约冲突。

想要解决这个冲突,就轮到【往前多看一步】上场了——把当前剩余输入考虑进来,辅助进行项目的选择:

  • 如果,按照第一个项目将 T 规约为 E,那么接下来的 * 就要跟在 E 后面了。而 * ∉ FOLLOW(E),也就是说 * 是不能跟在 E 后面的——这就意味着,如果我们将 T 规约为 E 将出现错误;
  • 如果,按照第二个项目进行移入,那么* 被移入后就将跟在 T 后面。而 * ∈ FOLLOW(T) ,因此将 * 移入不会引起任何问题 。
  • 这里就能看出 SLR(1) 的缺陷了——如果 * 同时属于 FOLLOW(T) 和 FOLLOW(E) ,那么我们这种判断方式就不灵了,也就是说这种冲突无法被 SLR(1) 解决。

对其他的冲突也使用同样的方法进行判断。

这种冲突性动作的解决办法叫做 SLR(1) 解决办法

SLR 分析表构造

准备工作部分,与 LR(0) 分析表的构造差不多:同样使用每个项目集的状态编号作为分析器的状态编号,也就同样用作行下标;同样使用拓广文法产生式作为 0 号产生式。

填表也和 LR(0) 类似,唯一的不同体现在对规约项的处理方法上:如果当前状态有项目 A → α.aβ 和 A → α. ,而次栈顶此时是 α 且读写头读到的是 a,那么当且仅当 a∈FOLLOW(A) 时,我们才会用 A → α 对 α 进行规约。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h0i95yr7-1687259478634)(./img/2020-08-04_13-47-34.png)]

如果构造出来的表的每个入口都不含多重定义(也就是如上图中表格那样的,每个格子里面最多只有一个动作),那么该表就是该文法的 SLR(1) 表,这个文法就是 SLR(1) 文法。使用 SLR(1) 表的分析器叫做一个 SLR(1) 分析器。

非 SLR(1) 文法举例

二义文法都不是 SLR(1) 文法

任意的二义文法都不能构造出 SLR(1) 分析表

例:悬空 else

A → S
S → iCtSS' | a
S' → eS | ε
C → b

在这里插入图片描述

不是二义文法的非 SLR(1) 文法

例:

S → L=R | R
L → *R | id
R → L

这里的 L 可以理解为左值,R 可以理解为右值

经过计算可以确定其 DFA 如下图所示。

在这里插入图片描述

在 状态4 中,由于 “=” 同时存在于 FOLLOW(L) 与 FOLLOW® 中,因此该状态内存在移进-规约冲突,故该文法不是 SLR(1) 文法。

这样的非二义文法可以通过增加向前看终结符的个数来解决冲突(比如LL(2)、LR(2))但这会让问题更加复杂,故一般不采用。而二义文法无论向前看多少个终结符都无法解决二义性。

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

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

相关文章

【一文通】C/C++与Go语言混合编程入门级教程(Windows平台完成)

一、概述 Go语言可以通过自带的 cgo 工具进行 CGO 混合编程,这个工具放在go安装目录的 pkg\tool 下,其源代码则在 src\runtime\cgo 里面,当然作为入门教程本文不打算对cgo的实现原理进行深入研究,仅从 Hello World 的角度来实际体…

快速查询银行卡发卡省市和归属银行,了解自己的财务状况!

API接口是现代软件开发的基本组成部分。它们允许应用程序通过互联网连接到其他软件系统,并从这些系统中获取或传输数据。银行卡归属地查询API接口是为开发人员提供的一种工具,可以帮助他们轻松地查询银行卡的归属地信息。在本文中,我们将介绍…

内网横向移动—IPCATschtasks

内网横向移动—IPC&AT&schtasks 1. IPC介绍1.1. IPC利用条件关系1.1.1. IPC$空连接介绍1.1.2. 139与445端口介绍1.1.3. 默认共享 1.2. IPC连接问题1.2.1. IPC连接失败原因1.2.2. IPC连接常见错误 2. 横向移动常用命令2.1. IPC命令介绍2.1.1. IPC常用命令演示2.1.1.1. 建…

docker非root用户下取消sudo前缀

解决非root用户下执行docker命令提示权限不足,必须添加sudo的问题。 第一步:执行 sudo gpasswd aby docker 命令,将当前用户aby加入docker组中。 第二步:执行 sudo chmod arw /var/run/docker.sock 命令修改sock权限

数据结构之堆——算法与数据结构入门笔记(六)

本文是算法与数据结构的学习笔记第六篇,将持续更新,欢迎小伙伴们阅读学习。有不懂的或错误的地方,欢迎交流 引言 当涉及到高效的数据存储和检索时,堆(Heap)是一种常用的数据结构。上一篇文章中介绍了树和完…

chatgpt赋能python:Python列表转字符串——从新手到大师

Python列表转字符串——从新手到大师 在Python编程中,列表和字符串是非常常用的数据类型。有时候,我们需要将一个列表转换为一个字符串,以方便进行各种操作。幸运的是,Python内置了一些函数和方法,可以轻松地将列表转…

7Z045 引脚功能详解

本文针对7Z045芯片,详细讲解硬件设计需要注意的技术点,可以作为设计和检查时候的参考文件。问了方便实用,按照Bank顺序排列,包含配置Bank、HR Bank、HP Bank、GTX Bank、供电引脚等。 参考文档包括: ds191-XC7Z030-X…

ruoyi-cloud版本(一)项目的下载与本地运行(亲测有效)

目录 1 架构2 架构图3 源码下载4 创建数据库5 下载nacos与运行6 打开运行基础模块(启动没有先后顺序)7 启动前端 1 架构 com.ruoyi ├── ruoyi-ui // 前端框架 [80] ├── ruoyi-gateway // 网关模块 [8080] ├── ruoyi…

canvas详解00-认识canvas

身为一个WEB开发人员,肯定都是想着能够开发出酷炫和激动人心的应用程序来。可以很多动画特效,例如黑客帝国的数字,彩色炫酷的例子动效。也可以实现各种图画面板,如实现类似于photoshop的web在线图像编辑。各种酷炫的表单等等。 #…

专项练习10

目录 一、选择题 1、执行以下程序,下列说法中,正确的是() 2、下面有关JavaScript中系统方法的描述,错误的是? 3、以下 JavaScript 代码,在浏览器中运行的结果是 4、假设DOM结构为 二、编程题 …

[ruby on rails] rails中使用graphQL

1. 添加gem gem graphql’是主要提供server的, gem graphiql-rails’是用来生成一个graphiql查询页面IDE,自己用来测试的group :development dogem graphiql-rails endgem graphql2.使用命令生成模板文件 rails g graphql:install在API only中,routes不会自动填充graphiql路…

chatgpt赋能python:Python的下载方法——从官网到第三方渠道

Python的下载方法——从官网到第三方渠道 Python 是一种翻译式、面向对象的、动态数据类型的高级程序设计语言,被广泛应用于数据分析、人工智能、物联网等领域。相信大多数程序员都知道 Python,并且使用它编写程序。那么,如何下载 Python&am…

人工智能(1):机器学习工作流程

1 什么是机器学习 机器学习是从数据中自动分析获得模型,并利用模型对未知数据进行预测。 2 机器学习工作流程 机器学习工作流程总结 1 获取数据 2 数据基本处理 3 特征工程 4 机器学习(模型训练) 5 模型评估 结果达到要求,上线服务没有达到要求&a…

程序编译连接加载过程详解

程序加载过程详解 可重定位的elf文件格式简介 首先我们打开目标文件看一下 上面的图就是目标文件的格式了,这里使用的是010editer,这个二进制编辑器很好用 可以看到大致分为三部分,首先是header,然后是sectionheader&#xff0…

MIT 6.S081 (BOOK-RISCV-REV1)教材第四章内容 -- Trap -- 下

MIT 6.S081 教材第四章内容 -- Trap -- 下 引言从内核空间陷入页面错误异常Page Fault BasicsLazy page allocationZero Fill On DemandCopy On Write ForkDemand PagingMemory Mapped Files 真实世界 引言 MIT 6.S081 2020 操作系统 本文为MIT 6.S081课程第四章教材内容翻译…

Windows编译OpenSSL Win10系统 vs2010

近期因为项目需要,需要用到openssl动态库,现在将编译的过程记录一下; 操作系统:Win10 64位 编译器:VS2010 编译步骤如下: 1、下载openssl版本(下载地址:​http://www.openssl.or…

chatgpt赋能python:Python分割——字符串处理中的必备技能

Python分割——字符串处理中的必备技能 如果你曾经遇到过需要将一个字符串根据一定规则切割成多个子串的情况,那么你一定会发现,Python中的分割功能能够让这个任务变得非常简单。 什么是Python分割? Python中的分割是指将一个字符串根据特…

端午节安康,佬们都了解端午节的哪些知识呢(附粽子大作战小游戏)

前言: 端午节假期,首先祝各位小伙伴儿们端午节安康。参考了一些资料,本篇文章将和大家分享关于端午节的由来,习俗,以及关于端午节的一个代码小游戏–粽子大作战。 希望大家看完此篇文章能对端午节有收获,也…

如何在gitee上托管项目

1、如果想要将一个项目托管到gitee上,第一步找到gitee官网: https://gitee.com/?utm_sourcebaidu&utm_mediumsem&utm_termgitee%CB%BD%D3%D0%B2%BF%CA%F0&utm_campaignenterprise&utm_contentcompetition&wl_kwid260644677393&wl_creativ…

chatgpt赋能python:用Python绘制区域图,探索数据背后的故事

用Python绘制区域图,探索数据背后的故事 随着大数据时代的到来,数据可视化变得越来越受到重视。而区域图(Area chart)是一种常用的数据可视化图表类型之一。它可以说明一个数量随着时间的变化而发生的趋势,以及各类数…