首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Stanford公开课《编译原理》学习笔记(2)递归下降法

需要注意左递归文法会使得递归下降遍历进入死循环,在文法设计时应该避免,龙书中也提供了一种通用的拆分方法来解决这个问题。 二....所谓语法规则,通常是指一系列CFG表示的产生式,大多数开发者并不具备设计一套语法规则的能力,此处直接借鉴Mozilla中的Javascript引擎SpiderMonkey中的文法定义来进行基本产生式,由于...的产生式,E的判断规则里需要判断A,而A的逻辑里又再次调用了E,这里就是一种左递归,如果不进行任何处理,在代码运行时就会陷入死循环然后爆栈,这也就是前文强调的需要在语法产生式设计时消除左递归的场景。...这里并不是说spiderMonkey的parserAPI是错的,因为消除左递归的语法改造只是一种等价形式的转换,是为了防止产生式产生无限递推(或者说程序实现时进入无限递归的死循环)而做的一种形式处理,改造的过程可能只是引入了某个中间集合来消除这种场景的影响...下文示例代码中并没有进行严谨的"左递归消除",而是简单地使用了一个E_集合,与原本的E进行一些微小的差异区分,从而避免了死循环。

1.1K10

自顶向下分析:解决回溯及无限循环问题

在自顶向下的语法分析中,我们会遇到回溯的问题以及无限循环的问题。 无限循环 递归下降解析器的无限循环问题主要来自于左递归文法。...事实上,这个消除的过程就是把左递归换成了右递归,使得递归下降解析器能正常工作。 天下没有免费的午餐,消除左递归需要付出的代价就是,引入了新的非终结符和新的\varepsilon \_ 产生式。...: S \Rightarrow Aa \Rightarrow Sda 对于间接左递归文法,我们可以通过带入的方式,不断的穷举、替换,把它转换成直接左递归文法,然后用消除直接左递归的方法来做。...,然后再使用消除直接左递归的方法来解决了。...通用的方法 对于不含循环推导和空产生式的文法G,有以下方法来消除左递归: 回溯问题 对于回溯问题,则是由于公共左因子的存在,解析器暂时还没有获得足够的信息,无法做出确定的决策,不知道到底应该转移到哪个状态

46180
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    消除文法的左递归

    简介 1.直接左递归的消除 消除产生式中的直接左递归是比较容易的。例如假设非终结符P的规则为 P→Pα / β 其中,β是不以P开头的符号串。...P开头,将上述规则改写为如下形式即可消除P的直接左递归: P→β1 P’ / β2 P’ /…/βm P’ P’ →α1P’ / α2 P’ /…/ αn P’ /ε 2.间接左递归的消除 消除间接左递归的方法是...,把间接左递归文法改写为直接左递归文法,然后用消除直接左递归的方法改写文法。...利用此算法可以将上述文法进行改写,来消除左递归。 首先,令非终结符的排序为R、Q、S。对于R,不存在直接左递归。把R代入到Q中的相关规则中,则Q的规则变为Q→Sab/ ab/ b。...接着,要解决间接左递归问题,因此将间接左递归转换成直接左递归。最后将消除直接左递归。

    4.1K30

    编译原理文法详解_编译原理为什么存在递归文法

    引言 学完了词法分析,我们知道词法分析器将正则表达式转换成词法单元流,但对于这个记号流我们不知道是否能由正确的文法产生,因此我们需要通过语法分析器来检测其合法性。...左递归的判定和消除 左递归的判定:一个文法G,若存在P经过一次或多次推导得到Pa(即能推导出以P开头的式子), 则称G是左递归的。...左递归消除: 1.直接左递归 使用公式: (原始) A → Aα1 | Aα2 | … | Aαm| β1 | β2 | … | βn (转化) A → β1 A’ | β2 A’ | … |...βn A’ A’ → α1A’ | α2A’| … | αmA’ | e 2.间接左递归 间接左递归就是要通过多次推导才能看出文法有左递归。...总结 这一节的主要内容应该是自顶向下分析,为了构建这一棵语法树,我们使用上下文无关文法,定义了推导的概念,发现我们要使用左推导,并且解决了二义性,顺便消除了左递归,这才成功构建出这样一棵语法树。

    76010

    腾讯电脑管家:Win10安全特性之执行流保护

    二、CFG 实现CFI需要在jmp、call 一个寄存器(或者使用寄存器间接寻址)的时候,目的地址有时必须通过动态获得,且改写的开销又很大,这些都给CFI的实际应用造成了一定的困难。...CFG是Control Flow Guard的缩写,就是控制流保护,它是一种编译器和操作系统相结合的防护手段,目的在于防止不可信的间接调用。...以win10 preview 9926中IE11的Spartan html解析模块为例,看一下CFG的具体情况: 这里就是被编译器插入的CFG校验函数。...这是ntdll中的检测函数 原理是在进入检测函数之前,把即将call的寄存器值(或者是带偏移的寄存器间接寻址)赋值给ecx,在检测函数中通过编译期间记录的数据,来校验这个值是否有效。...四、尾声 CFG防护方法需要在编译链接阶段来完成准备工作,同时需要操作系统的支持。CFI无需编译时的帮助,且不仅能够防御call调用,能够对全部执行流进行保护。

    1.1K50

    65.精读《手写 SQL 编译器 - 文法介绍》

    左推导与右推导 上面提到的推导符号 => 在实际运行过程中,显然有两种方向左和右: E + E => ? 从最左边的 E 开始分析,称为左推导,对语法解析来说是自顶向下的方式,常用方法是递归下降。...消除左递归 消除左递归一般通过转化为右递归的方式,因为左递归完全不消耗 Token,而右递归可以通过消耗 Token 的方式跳出死循环。...,提取左公因式也会降低文法的可读性,需要进行人为修复。...不过提取左公因式的修复没办法在文法中处理,在后面的 “函数式” 处理环节是有办法处理的,敬请期待。...3 总结 在实现语法解析前,需要使用文法描述 SQL 的语法,文法描述就是语法分析的主干业务代码。 下一篇将介绍语法分析相关知识,帮助你一步步打造自己的 SQL 编译器。

    57120

    理解递归下降分析和parsec应用

    本文的亮点是使用 typescript 编写组合子编译器,对于前端开发某些特定领域会有重要意义和价值。同时本文注重实用价值,配合简短 js 代码示例来帮助理解。 2....在含有递归的语法中,不能出现左递归(包括间接左递归),也不能有二义性,没有左递归且没有二义性的语法符合 LL(1)文法,就可以使用递归下降分析法解析。...左递归无法使用递归下降分析的原因是会让程序死循环,具体可以参考编译原理龙书 2.4.5 Left Recursion 章节。 3. 递归下降分析 符合 LL(1)文法的语法可以使用递归下降分析法解析。...Parser Combinators 编译器开发中有两个流派,自底向上和自顶向下,递归下降分析就是属于自顶向下分析。...应用价值: 在编写 BNF 的时候,可以更好的理解编程语言语法设计理念。有助于写出能够被编译器优化的语法。

    1.7K00

    深入理解 C++ 右值引用和移动语义:全面解析

    即使你的代码中并不直接使用右值引用,也可以通过标准库,间接地从这一特性中收益。为了更好地理解该特性带来的优化,以及帮助我们实现更高效的程序,我们有必要了解一下有关右值引用的意义。...举个例子:int a = 2; 这里的a是等号左边,可以通过取址符&来获取地址,所以是一个左值。而5在等号右边,无法通过取址符&来获取地址,所以只一个右值。...在C++11之后,编译器自动生成的函数中又新增了2个,它们就是移动构造和移动赋值运算符重载函数,通过它们,我们可以很好地实现对用户自定义类型的移动操作。...,当我们在面对产生临时的对象的时候,编译器就会根据传入的参数是左值还是右值来选择调用拷贝还是移动。...如果还要继续使用该对象,就要使用拷贝而不是移动操作 右值引用变量本身是个左值,如果想要右值引用指向右值引用,需要使用move转成右值 const 左值引用也可以指向右值,但是无法进行修改 最后 看完如果觉得有帮助

    2.1K20

    控制流完整性简介

    首先是 CFG 的构建,控制流图 (Control-Flow Graph) 是基于静态分析的用图的方式来表达程序的执行路径。下图展示了几个普通的 CFG ,分支指令作为边,圆圈则表示普通指令。...CFI 中的 CFG 构建只考虑将可能受到攻击的间接调用、间接跳转和 RET 指令作为边。...右图以方框代表基本块,箭头代表边,展示了该代码片段的 CFG。其中细虚线表示直接调用,不需要检查。实线代表间接调用,粗虚线代表返回指令,这两者的目标地址需要检查。...这篇文章是 Google 将 CFI 机制应用到编译器中的实践。...因为随着软硬件的发展,不同的硬件、操作系统、编译器甚至语言都会有不同的实现方式,而且没有哪一种是完美的。安全和性能在实际使用中还需要用户自行抉择。 0x05.

    1.4K20

    第四章 自顶向下语法分析方法

    一个文法提取了公共左因子后,只解决了相同左部产生式的FIRST集不相交问题,当改写后的文法不含空产生式,且无左递归时,则改写后的文法是LL(1)文法,若还有空产生式时,则还需要用LL(1)文法的判别方式进行判断才能确定是否为...4.2 左递归消除 4.2.1 关于非终结符P的规则 直接左递归定义:若P → Pα|β,且α、β ∈V* 4.2.2 方法 改写为等价的右递归,形如:P → Pα|β ,α非ε,β不以P开始。...’ \Rightarrow βαP’ \Rightarrow βα 4.2.3 消除多个直接左递归 若有多个左递归的产生式如:P→Pα_1| Pα_2 |…| Pα_m |β_1| β_2 |…|β_n...消除左递归后变为: P→β_1P’ |β_2 P’|…|β_nP’ P’ → α_1P’ | α_2 P’|…| α_mP’| ε 消除左递归要求文法: 1.无回路(A \overset *...\Rightarrow A) 2.无空产生式(A → ε) 4.2.4 消除间接左递归 间接左递归定义: 若P\overset + \Rightarrow Pα \ \ \ \ \ α∈V^* 例如:

    1.3K30

    语法分析

    自顶向下的分析 最左推导 lm表示的是最左 最右推导 自顶向下的语法分析采用最左推导方式 例子 自顶向下语法分析的通用形式 预测分析 文法转换 两个问题 消除直接左递归 消除直接左递归的一般形式...消除间接左递归 提取左公因子 LL(1)文法 S_文法 例子 非终结符的后继符号集follow 产生式的可选集select 串首终结符集first 比如求x的first集合,那么就是求的...x—>字符串,所有字符串首字母构成的集合 LL(1)文法定义 判断一个文法是不是LL(1)的,只需要查看它们的同一非终结符的各个产生式的可选集select集互不相交就可以 first集和follow...$,不可以有空串ε 计算需要反复 算法 例:表达式文法各产生式的select集 select的计算: select(A->空)它的结果是A的follow集合 select(A->B)它的结果是...A的first集合 select(A->a)它的结果就是a 预测分析表 递归的预测分析法 非递归的预测分析法 例 两种方法进行对比 预测分析法实现步骤 预测分析中的错误处理 预测分析中的错误检测

    30230

    大学课程 | 编译原理知识点

    什么是字母表,元符号,正则表达式的三种基本操作 0/1/2/3型文法?什么是最左推导?最右推导?什么是终结符,非终结符?什么是产生式?如何识别二义性,消除方法?语言到文法? 递归下降?...消除左递归,提取左公因子,First集follow集,构造分析表,对一个句子分析。LL(1)三种基本动作:生成(最左推导),匹配,接受。 自底向上? 语义分析:什么是属性?什么是属性文法?什么是联编?...编译器分类结构 根据语言文法的难易程度以及识别它们所需要的算法分类:如乔姆斯基分类结构: 4类:分为0型,1型,2型,3型文法 0型文法为:无限制文法 1型文法为:上下文有关文法 2型文法为:上下文无关文法...LL(1)三种基本动作:生成(最左推导),匹配,接受 将BNF写为LL(1)分析算法 消除左递归: 提取左公因子: FIRST集 定义: 令 X 为一个文法符号(一个终结符或非终结符)或 ε ,...需要注意的是,SELECT集是针对产生式而言的。

    1.3K30

    如何设计一门编程语言?

    常见的语法分析算法有自顶向下分析(如递归下降分析)和自底向上分析(如 LR 分析)。...类型系统的文档和工具支持 类型文档 类型注释:提供详细的类型注释和文档,帮助开发者理解类型系统的设计和使用。 示例代码:提供示例代码展示类型系统的用法和最佳实践。...四、设计编译器和解释器涉及理论 设计编译器和解释器时,需要依据多种计算机科学理论,这些理论提供了设计和实现语言处理器所需的基础和指导。以下是设计编译器和解释器时需要遵循的主要计算机理论: 1....解释器:实现基于栈或基于寄存器的解释执行模型。 编译器:将语法树转换为目标代码,进行简单的优化如常量折叠和死代码消除。...五、设计编程语言的工具链和开发环境 设计编程语言的工具链和开发环境需要考虑开发者在创建、测试、调试和部署代码时的整体工作流程。以下是设计一个完整工具链和开发环境的关键组成部分: 1.

    18610

    陈天奇团队LLM结构化生成新引擎XGrammar:百倍加速、近零开销

    在每个解码步骤中,约束解码都会检查词表,并通过将无效 token 的概率设置为零来过滤掉违反指定结构的 token。为了支持多种多样的结构格式,需要一种灵活的机制来指定和检查这些约束。...使用 JSON 方案实现约束解码 上下文无关语法(CFG)就能提供一种通用方法,即通过一组规则来定义结构。其中每条规则都包含一个字符序列或其他规则,并允许递归组合来表示复杂的结构。...下图展示了一个用于数组和字符串的 CFG,可以清楚地看到其中的递归结构。 但是,也正因为 CFG 很灵活,所以直接将其应用于约束解码的效率并不高。...首先,每个解码步骤都需要对词表中每个可能的 token 解释 CFG,在 Llama 3.1 中,这个词表的大小可能高达 128k。...此外,CFG 解释需要一个堆栈状态来跟踪之前匹配的递归规则,因此无法提前计算和缓存堆栈模式的所有组合。

    14210

    CS143 编译器笔记

    多种解析方式递归下降:容易实现,但是一旦成功匹配非终结符 X 的某条生成式,便无法再回溯去尝试 X 的其它生成式。可以改写语法,将左公因式提取出来。...将 result 放在第一个位置,调用者就可以通过自身栈的固定位移找到它。AR 布局和代码生成必须一起设计。因为在编译时,生成的代码需要正确地访问 AR。...$rajr reg:跳转到寄存器 reg 中包含的位置可以通过递归遍历 AST 生成代码。...管理缓存:光靠编译器比较难做到,还需要靠程序员,比如写循环时,将内循环的变量赋值给外循环,可以提高缓存利用率。自动内存管理 / 垃圾回收如何知道一个对象不会再被用到?程序只能使用它可以找到的对象。...问题:需要空间来构建 todo 列表,todo 列表的大小又不可预知。解决:使用反向指针,将指针反向指向其父,从而将 free 列表保存在 free 对象中。清除阶段:回收垃圾对象。

    60820

    Java递归下降分析器_递归下降语法分析器

    大家好,又见面了,我是你们的朋友全栈君。 用java语言编写的递归下降语法分析器,是一种适合手写语法编译器的方法,且非常简单。...如果需要产生解析的结果(比如本例中的二叉树),在方法返回之前将它构造出来。 我们马上来试验一下。首先建立一个类,然后存放一个索引变量来保存当前扫描位置。...大家感兴趣可以继续补全一些辅助代码,然后用真正的字符串输入试验一下,是否工作正常。前面假设输入字符串的语法是正确的,但真实世界的程序总会写错,所以编译器需要能够帮助检查语法错误。...大家可以用调试器跟踪一遍递归下降语法分析器的分析过程,就能很容易地感受到它的确是最左推导的(总是先展开当前句型最左边的非终结符)。最后括号中的k表示需要超前查看k个字符。...我们想像一下,如果在编写E的递归下降解析函数时,直接在函数的开头递归调用自己,输入字符串完全没有消耗,这种递归调用就会变成一种死循环。所以,左递归是必须要消除的文法结构。

    1.2K20

    数据结构+算法(第08篇):史上最猛之递归屠龙奥义

    动态编程》讲述了递归算法的优化,但是在大量的实际项目、工程和大家关心的求职面试中,却会碰到大量消除递归的需求。于是产生了两个问题: 1. 为什么会有消除递归的需求? 2....变通的方法是找到返回地址的对应物。 推论8.1: 返回地址对应递归展开树中的某个节点。 ? 定位递归展开树中的任意一个节点,需要两部分位置信息: 1. 在树的哪一层("宏观地址")?...注意:不要只是以各子递归在代码中的静态位置来判断调用次序,有的时候实际运行时的调用次序与代码中的静态位置次序是不一样的。...第三步:设计"微观地址"的锚定。 因为不存在逻辑时序链,所以不需要设计"微观地址"的锚定。 因为是并列关系,所以这两个子递归调用的非递归代码可以合并。 根据在第8章节中讲到的:尝试转化成右递归模型。...上面我们用单向链表来存储二叉树节点,如果改用数组来存储,就可以利用完全二叉树子节点在数组中的下标与父节点在数组中的下标的线性关系来快速处理消除递归。

    65730

    codeql基础

    AST抽象语法树 源代码------》》》》 转换为 -----》》》》 AST 抽象语法树 abstract syntax  code  AST,是源代码的抽象语法结构的树状表示,树上的每个节点都表示源代码中的一种结构...,抽象语法树并不会表示出真实语法出现的每一个细节,例如 嵌套括号被隐含在树的结构中,并没有以节点的形式呈现。...抽象语法树并不依赖于源语言的语法,也就是说语法分析阶段所采用的上下文无文文法,因为在写文法时,经常会对文法进行等价的转换(消除左递归,回溯,二义性等),这样会给文法分析引入一些多余的成分,对后续阶段造成不利影响...因些,很多编译器经常要独立地构造语法分析树,为前端,后端建立一个清晰的接口。 抽象语法树在很多领域有广泛的应用,比如浏览器,智能编辑器,编译器。...抽象语法树实例 从局部看起,从下网上看 迭代 消除左递归 递归分为立即左递归和非立即左递归

    45430

    深入剖析 JavaScriptCore

    前言 最近开始涉及 JS 的解析和处理工作,所以专门研究了下这块。特别是动态类型的处理以及不同引擎对于平台无关的字节码的设计和处理会有很大的帮助。...rev=211697 程序会被表示成树,每个节点都有与其相关的代码,这些代码都可以递归的调用树中的子节点。...DFG JIT 将低效字节码转成更优化的高效形式。DFG 结合传统编译器的优化,比如寄存器的分配,控制流图的简化,公共子表达式消除,死代码消除和稀疏条件常量传播等。...但是正儿八经的编译器是需要知道变量类型和堆里面的对象的结构的,这样才能更好的优化。DFG JIT 使用的是 LLInt 和 Baseline JIT 里分析出的变量类型来推断的。...根据求值顺序,对于二元运算的节点,是先遍历左子节点的。所以当左值是复杂表达式需要计算时是会优先进行计算的。

    1.2K10

    hiphop原理分析1

    1.4.1 设计文法 1.4.2 自顶向下的语法分析 1.4.3 自底向上的语法分析 1.4.1. 设计文法 1....词法分析和语法分析的区别 (1)词法为何使用正则表达式: 语法结构分为词法和非词法方便讲编译器前端模块化 词法比较简单,需要语法那样的强大功能进行描述规则 和语法相比,正则表达式提供了更加简洁且易于理解的表示词法单元的方法...左递归消除 exprexpr+term 这样的话,expr就会进入无限的循环: expr expr+term+term exprexpr+term+term+term exprexpr+term...+term+……+term 这样就没有终结了,所以一般改写为: exprexpr+term|term 这样当找到终结符term时,他就不会再进行递归了,这样就消除了左递归 4....语义分析器 语义分析器使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。同时也收集类型信息,并把这些信息放到语法树或符号表中。 语义分析重要部分:类型检查和抽象语法树。

    1.4K70
    领券