【编译原理】一篇搞定语法分析器对文法的要求(上下文无法文法、消除二义性文法、消除左递归)

🌈 个人主页:十二月的猫-CSDN博客
🔥 系列专栏: 🏀编译原理_十二月的猫的博客-CSDN博客

💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 

 

目录

1. 文法要求

1.1 上下文无关文法

1.2 二义性

1.2.1 定义

1.2.2 消除二义性(改写原文法)

1.3 左递归

1.3.1 定义

1.3.2 方法

2. 总结 


1. 文法要求

语法分析这里提供了6种语法分析算法,但是这些算法对输入的文法是有要求的(很没有规则的一些文法是无法识别的,只能识别规则感很强的文法),不同算法要求的严格度不相同。

本部分的重点内容如下:

  • 不同语法分析算法对文法的要求是什么?
  • 如何转变文法满足分析算法要求?

1.1 上下文无关文法

上下文无关文法是所有语法分析算法最基本的要求

上下文无关文法(Context-Free Grammar,CFG)是一种形式语言描述工具,用于描述上下文无关语言的语法结构。它是计算机科学中的一种形式化的表示方法,广泛应用于编译器设计、自然语言处理和人工智能等领域。上下文无关文法由四个元素组成:

  • 一个非终结符集合

  • 一个终结符集合

  • 一个产生式规则集合

  • 一个起始符号。

其中,非终结符表示语法结构的符号,终结符表示语言中的实际词汇,产生式规则定义了语法结构的生成规则,起始符号表示语法结构的起点。

上下文无关文法的生成过程是通过不断地应用产生式规则来替换非终结符,直到最终得到一个只包含终结符的字符串,即语法结构的句子。这个过程可以看作是一个推导过程,其中每一步应用的产生式规则被称为推导步骤。

上下文无关文法可以表示一类语言,称为上下文无关语言。这类语言在形式上具有简单的结构,不依赖于上下文信息,因此被广泛应用于描述自然语言的语法结构和编程语言的语法规则。常见的编程语言如C、Java和Python都可以用上下文无关文法来描述其语法结构

推导是指将非终结符替换为它的某个产生式的体一次替换,连续多次替换也称推导。语法分析树就是推导过程的图形表示。推导和解析树是多对一的,给定文法和某个句子,可能有多个推导对应一棵解析树,例如:  

解析树无法捕捉推导所采用产生式的先后次序,但这不是问题,反而是优点,因为我们的最终目标是确定程序的结构,而推导过程本身并不是语法分析的最终目标。

根据推导的顺序可以将推导分为最左推导和最右推导:

  • 最左推导
  • 最右推导

二者和解析树都是一对一的,其中最右推导及其对应的最左规约也被称为规范推导和规范规约。

1.2 二义性

通常要求程序设计语言的文法是无二义性的,否则就会导致一个程序有多种“正确”的解释。即使文法看似允许二义性(以方便文法或语法分析器的设计),但仍需要在文法之外加以说明,来剔除不要的语法分析树

二义性有两个主要的来源:

  • 算术表达式(算符结合性二义,算符优先级二义)
  • 悬空else(dangling else,else与哪个then匹配二义)

消除二义性的两个主要方法:

  • 改写原文法(rewriting)
  • 引入消除二义性的规则(disambiguating rule)

1.2.1 定义

若文法G对同一句子产生不止一棵分析树,则称G是二义的。

例3.7 句子id+id*id和id+id+id可能的分析树
E→E+E | E*E |(E)| -E | id

深度越深,越远离开始节点,优先级越高。
非终结符在终结符(如+)的左边是左结合,右边是右结合。  

由此可见优先级和结合性都会导致二义性 

1.2.2 消除二义性(改写原文法)

引入消除二义性的规则:具体是在解析器(例如Yacc上)利用特殊的语句来引入结合性和优先级,从而让编译器自动处理好这个问题。

(都自动了,有什么好学习的,没意思🫠🫠)

所以,下面只学习 改写原文法

(1)改写二义文法的关键步骤:

  • 划分优先级和结合性
  • 引入一个新的非终结符,增加一个子结构并提高一级优先级(优先级的判断);
  • 递归非终结符在终结符左边,运算具有左结合性,否则具有右结合性。
  • 原数值都要保留(id、括号内的数等等),数本身优先级最高

(2)例子

例3.10 改写二义文法
E→E+E | E*E |(E)| -E | id

  1. 优先级从低到高: [+][*][( ), -, id]
  2. 结合性:
    左结合[+, *]
    右结合[-]
    无结合[id]
  3. 非终结符与运算:
    E:+ (E产生式,左递归)
    T:* (T产生式,左递归)
    F:-,( ),id (F产生式,右递归)

改写后答案为: 

E → E + T | T
T → T * F | F
F → (E) | -F | id

1.3 左递归

1.3.1 定义

左递归是指在产生式规则中存在直接或间接地将同一非终结符作为产生式右侧的第一个符号的情况。例如,对于产生式 A→Aα,其中 A是非终结符,α 是由终结符和非终结符组成的符号串,就存在左递归。

左递归可能导致语法分析过程中的无限循环或者无法终止,从而使分析器陷入死循环。这是因为在尝试匹配左递归产生式时,分析器会不断地展开同一非终结符,而无法向后推导到其他的产生式规则。

1.3.2 方法

为了消除左递归,可以采取以下步骤:

  1. 检测左递归:对于每个非终结符 A,检查其产生式规则中是否存在以 A 开头的产生式右侧。如果存在,则存在左递归。

  2. 消除直接左递归:对于存在直接左递归的非终结符 A,可以通过引入新的非终结符来消除左递归。具体步骤如下:

    • 将所有以 A 开头的产生式规则拆分为两组:一组是直接左递归的规则,另一组是非左递归的规则。
    • 对于直接左递归的规则,创建一个新的非终结符 A′,将这些规则中的左递归部分替换为 A′。同时,添加一个新的产生式规则 A′→βA′,其中 β 是直接左递归规则中的非左递归部分。
    • 对于非左递归的规则,将其末尾添加新的产生式规则 A′→γ,其中 γ是原始规则的右侧部分。
  3. 消除间接左递归:如果存在间接左递归,即存在形如 A→Bα 和 B→Aβ 的产生式规则,可以通过以下步骤消除间接左递归:

    • 为每个非终结符 A 创建一个新的非终结符 A′。
    • 对于每个存在间接左递归的规则 A→Bα,将其替换为 A→A′α。
    • 对于每个存在间接左递归的规则 B→Aβ,将其替换为 A′→Aβ。

以下为一个简单的消除直接左递归的例子:

消除直接左递归:1、创建新的非终结符;2、将左递归转为右递归;

以下为一个简单的消除间接左递归的例子:

消除间接左递归:1、将间接左递归变为直接左递归;2、消除直接左递归

2. 总结 

本文到这里就结束啦~~

本系列专栏将专注于【编译原理】知识。

内容包括:知识点讲解、习题练习、重点知识带练等~~目前已完成:

【编译原理】编译原理知识点汇总·概论与文法-CSDN博客

【编译原理】编译原理知识点汇总·词法分析器(正则式到NFA、NFA到DFA、DFA最小化)-CSDN博客

【编译原理】词法分析器设计(山东大学实验一)_山东大学编译原理实验-CSDN博客

【编译原理】语法、语义分析器设计(山东大学实验二)_语法分析实验-实现一个简单语法分析器(自上而下方法)实验小结-CSDN博客

【编译原理】代码生成器的构建与测试(山东大学实验三)_编译原理实验语义分析代码-CSDN博客 【编译原理】一篇搞定正规式到NFA、NFA到DFA、DFA最小化-CSDN博客

期待您的关注~~🥰🥰

猫猫陪你永远在路上💪💪

如果觉得对你有帮助,友友们可以点个赞,收个藏呀~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十二月的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值