编译原理笔记11:自上而下语法分析(1)基础概念、左递归和公共左因子处理、递归下降分析(咕咕咕)

news2025/4/17 16:25:36

目录

    • 自上而下分析的一般方法
      • 用推导的方法分析输入序列
      • 左递归问题及其消除(消除左递归)
        • 消除直接左递归
        • 消除间接左递归
        • 左递归消除算法
      • 公共左因子问题及其消除(提取左因子)
        • 提取左因子
    • 递归下降分析

词法分析,是把源程序分析成记号流,识别其中的单词。

语法分析,是要分析词法分析产生的记号流中的语法结构是否正确——对词法分析得到的记号流进行分析,以确认其是不是一个可以由我们定义好的文法推出来的句子。如果语法结构正确,语法分析器最终要为输入序列构造出一棵语法树。

在推导的过程中,我们其实会同时保有两个序列:一个是词法分析器给的输入序列,另一个则是我们自己推导的序列。如果最后两个序列都能够一一匹配上,那么就说明输入序列是符合语法规则的,我们构造出的就是合法的语法树。

语法分析有两种方式,分别是自上而下分析和自下而上的分析。我们在此仅对前者进行简单的学习,重点都放在后者上(各种略……精力实在不够,写不动了)。

自上而下分析有两种方式:【递归下降分析】和【使用预测分析器的预测分析】。无论是哪种,都对文法有一些要求——文法不能有二义性,产生式不能有左递归,也不能有公共左因子

自上而下分析的一般方法

用推导的方法分析输入序列

词法分析器给我们的记号流,在这里被称为【输入序列】。我们使用边推导边匹配的方法对它进行分析,该方法描述如下:

  1. 对输入序列 ω,从 S 开始进行最左推导,直到得到一个合法句子或非法结构。(因为对输入序列的扫描是从左到右的,所以我们的推导也要从左到右进行。在推导的过程中,也总是尝试推导出最左端的终结符,以将其和输入序列中的最左边的记号进行匹配)
  2. 从左到右扫描输入序列,自上而下构造这个序列的分析树;
  3. 通过推导分析输入序列的过程是一个反复试探的过程,这个过程中会不断尝试使用不同的产生式,尝试让推导与输入序列相匹配。

用推导分析输入序列的过程中,会由于文法产生式的某些“特征”而遇到如下的两个问题,导致推导过程的回溯。

左递归问题及其消除(消除左递归)

左递归产生式形如: A → Aa

左递归会导致分析陷入死循环:我们可以总用 Aa 来替换掉上一层的 Aa 中的 A,无法停下来。想要避免死循环的出现,我们就需要消除左递归

消除直接左递归

我们通过引入新的非终结符来消除左递归。

给出一般的左递归产生式如下图左侧,要消除该产生式的左递归,只需要将其改写为下图右侧的两个产生式即可。下图产生式中,α1 非空, βj 均不以 A 开始(即不包含左递归)

在这里插入图片描述

在修改之前的文法中,总是需要靠这些 β 来终止对 A 的推导,即通过 β 出现在最左端的方式来停止递归。所以现在推出来的序列,一定也要是以 β 们开头的序列,β后面链接新的终结符。由A‘ 推出后面可以重复出现的 α 们。最后再为新增的非终结符加一个 ε 推导的选项,用于最终停止递归推导

下图展示一个简单的左递归产生式改写,及改写产生式在语法分析树上的体现

在这里插入图片描述

消除间接左递归

对于一般情况的核心步骤:

  1. 对各个在产生式左部的非终结符进行排序:A1, A2 … An(【合理排序】,自己看着办,排序方法不唯一)
  2. 用 Aj → δ1 | δ2 |… | δk 的右部替换 Ai → Ajγ 中的 Aj(也就是将一个非终结符在另一个产生式的非终结符中展开),得到 Ai → δ1γ | δ2γ |…| δkγ

例:消除下面文法中的左递归

S → Aa | b
A → Ac | Sd | ε

这里存在两个左递归:A的直接左递归和 S 的间接左递归

消除这样的左递归分两步走:

  1. 把不含有直接左递归的非终结符排在前面,含有直接左递归的N排在后面。因此这里以 S、A 顺序来处理。先把 S 展开到 A 里面,这么一搞,以后就没办法推回来 S 了。这样我们就只留下了一个A

    A → Ac | Aad | bd | ε
    
  2. 我们把S干掉了,也就已经消除了 S 的间接左递归,接下来腾出手单独处理 A 。按照标准的直接左递归消除方式来处理现在的情况即可,和之前的抽象题型一样了

    S → Aa | b
    A → bdA' | A'
    A' → cA' | adA' | ε
    

左递归消除算法

暂略,随缘补

公共左因子问题及其消除(提取左因子)

存在公共左因子的产生式形如:A → αβ1|αβ2

公共左因子会造成不必要的回溯——因为通过推导来分析输入序列是一个反复试探的过程,既然是试探那么就会出现试错了的情况,而显然,公共左因子的存在,就为“试错了”的出现创造了条件。

回溯会出现严重的浪费,所以我们其实可以像解决词法分析的回溯问题一样(有限自动机的确定化),通过将推导“确定化”来避免回溯的产生。具体的方式就是提取左因子

提取左因子

重复以下过程,直到所有 A 产生式中都不再含有公共前缀:

  1. 重排 A 产生式:A → αβ1 | αβ2 |… | αβn| γ
  2. 用 A → αA’ | γ 和 A’ → β1 | β2 | … | βn 取代原 A 的产生式

对于同时存在左递归和公共左因子的文法,先消除左递归。有时曾经存在的公共左因子会随着左递归的消失而消失

例:消除下面文法(悬空 else 文法)的公共左因子

S → iCtS | iCtSeS | a
C → b 

S → iCtSS’ | a
S’ → eS | ε
C → b

递归下降分析

递归下降分析是【确定的自上而下分析】的一种实现方式,能进行自上而下分析的文法必须是非二义、无左递归和公共左因子的。但满足这三个条件的文法也未必能进行自上而下分析。这种分析方法适用范围较小。

递归下降分析是一个【边推导边匹配】的过程,根据产生式写出子程序,通过子程序之间的调用来实现对非终结符的推导——文法产生式的每个终结符都对应着一个子程序,产生式右侧的非终结符对应子程序的调用,遇到右侧的终结符,则将该终结符与输入符号序列的匹配。

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

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

相关文章

基于物联网及云平台的光伏运维系统

系统结构 在光伏变电站安装逆变器、以及多功能电力计量仪表,通过网关将采集的数据上传至服务器,并将数据进行集中存储管理。用户可以通过PC访问平台,及时获取分布式光伏电站的运行情况以及各逆变器运行状况。平台整体结构如图所示。 光伏背景…

Cortext-M3系列:调试组件(9)

1、调试组件简介 在 CM3 中有很多调试组件,使用它们可以执行各种调试功能:断点、数据观察点、闪存地址重载以及各种跟踪等。软件开发人员也许永远无需了解调试组 的细节,因为它们通常只是由调试器及其周边工具使用的。 本文对每种调试组件做一…

基于Java学生公寓管理中心系统设计实现(源码+lw+部署文档+讲解等)

博主介绍: ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精…

IDEA2022.3.3支持Jrebel and Xrebel教程

目录 前言 思路 步骤 1、下载服务并启动 推荐下载windows环境的exe文件,直接点开就行。 如果用linux 需要安装go环境: 下载好后启动 2、idea安装Jrebel and XRebel插件 3、激活插件 前言 由于服务平台限制,只支持darwin、linux和windows环境。这…

(转载)无监督学习神经网络的分类(matlab实现)

对于监督学习神经网络,事先需要知道与输入相对应的期望输出,根据期望输出与网络输出间的偏差来调整网络的权值和阈值。然而,在大多数情况下,由于人们认知能力以及环境的限制,往往无法或者很难获得期望的输出&#xff0…

AbstractQueuedSynchronizer源码

介绍 基于队列的抽象同步器,它是jdk中所有显示的线程同步工具的基础,像ReentrantLock/DelayQueue/CountdownLatch等等,都是借助AQS实现的。 public abstract class AbstractQueuedSynchronizerextends AbstractOwnableSynchronizerimplemen…

Camera 基础知识点

和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 1.1 Camera 工作原理1.2 Camera 模组组成1.3 Camera 常见缩写解释1.4 Camera 部分名词解释1.5 参考文献 一、Camera 基础知识 1.1 Camera 工作原理 外部…

[进阶]Java:线程安全问题、取钱模拟

什么是线程安全问题? 多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。 线程安全问题出现的原因? 存在多个线程在同时执行同时访问一个共享资源存在修改该共享资源 代码演示如下: 账户类&#xff…

深蓝学院C++基础与深度解析笔记 第 5 章 语句

1. 语句基础 ● 语句的常见类别 – 表达式语句:表达式后加分号,对表达式求值后丢弃,可能产生副作用 – 空语句:仅包含一个分号的语句,可能与循环一起工作 – 复合语句(语句体):由大…

软考A计划-系统集成项目管理工程师-信息系统集成及服务管理体系

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 👉关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

Flutter Dart 变量和内置类型

目录 一、变量 1.1 var 1.2 Object 1.3 dynamic 1.4 final与const 二、内置类型 2.1 num(数值) 2.2 Strings(字符串) 2.3 bool(布尔值) 2.4 List(列表) 2.5 Map(映射集…

Android apk 反编译后打包(含签名)

想分析某些app源码时,遇到烦人弹框,现在想反编译看看具体实现。 用到的工具: GDA4.06 apk反编译工具 apktool apk 打包工具 jdk 环境 一、反编译分析 将apk反编译打开 找到入口代码 弹框代码如图 二、解包、打包 使用apktool解包 ps: apktool工具…

unity游戏架构设计

1.unity架构的3个等级 EmptyGO 所有功能写一个脚本挂载object上面,没有单列manager。 Simple GameManager 写一个公用的管理器,方便调用 Manager of Managers 不同的类型的东西用不同的管理器【声音管理器,关卡管理器,】 2…

chatgpt赋能python:Python搜索快捷键

Python搜索快捷键 介绍 Python作为一门广泛应用在各个领域的编程语言,其强大的搜索功能也得到了广泛的应用和赞誉。但是,在日常的使用中,有时我们需要进行大量的搜索和筛选操作,这时候掌握一些Python搜索快捷键将能够极大地提高…

java入门2(运算符)

目录 运算符和C语言基本一样 算术运算符 单目运算符:自增自减运算符 比较运算符 逻辑运算符 位运算符(C语言好像没有) 优先级 交换算法 运算符和C语言基本一样 算术运算符 比如拆分一个三位数 public class java练习代码 {public…

Cortext-M3系统:NVIC与中断控制(4)

1、NVIC概述 向量中断控制器,简称NVIC,是Cortex-M3不可分离的一部分,它与CM3内核的逻辑紧密耦合。NVIC的寄存器以存储器映射的方式来访问,除了包含控制寄存器和中断处理的控制逻辑之外,NVIC还包含了MPU、SysTick定时器…

算法分析01--算法的基本概念

1.算法设计与分析的基本概念 1.1算法 算法(Algorithm)是对特定问题求解步骤的一种描述, 它是指令的有限序列, 其中每一条指令表示一个或多个操作。 算法具有以下5个重要特性: 1.有穷性 一个算法必须在有穷步内完成,并且每一步…

Vue2 到 Vue3, 5 个常用API的变化有哪些

Vue3之于Vue2最大的变化,当属composition API了,而除了引入composition API外,一些我们在Vue2上经常使用的东西到了Vue3时也发生了不小的变化,本文将介绍一些有Vue2到Vue3中几个比较重要且常用的知识点,欢迎感兴趣的同…

学习adaboost(一,遍历分类器,c#实现)

我看了很多遍,终于搞懂了,现在编程试一试, 参考文献(十三)通俗易懂理解——Adaboost算法原理 - 知乎 (zhihu.com) 先写一一段代码,把这个数据集里头的所有分类器找出来:一共四种结果&#xff1a…

C++基础(4)——类和对象(2)

前言 本文主要介绍了C中类和对象的基本知识。 4.2.5:深拷贝和浅拷贝 浅拷贝:编译器给我们提供的拷贝函数就是等号复制操作 深拷贝:自己手动重写一个拷贝构造函数,重新new 浅拷贝会出现的问题:如果使用编译器提供的…