自底向上的语法分析

本文详细介绍了自底向上的语法分析,包括移入-归约分析的步骤、LR分析法及其不同类型,如LR(0)、SLR和LR(1)分析。讨论了分析过程中的状态、句柄识别、分析表结构以及可能遇到的冲突解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


参考哈工大课件

自底向上的语法分析

从分析树的底部(叶节点向顶部根节点方向构造分析树,可以看成是将输入串归约为文法开始符号S的过程

自顶向下的语法分析采用最左推导方式;
自底向上的语法分析采用最左归约方式,实际上是 反向构造最右推导

自底向上语法分析的通用框架:移入-归约分析

1)在对输入串的一次从左到右扫描过程中,语法分析器将零个或多个输入符号移入到栈的顶端,直到它可以对栈顶的一个文法符号串β进行归约为止
2)它将β归约为某个产生式的左部
3)语法分析器不断地重复这个循环,直到它检测到一个语法错误,或者栈中包含了开始符号且输入缓冲区为空(当进入这样的格局时,语法分析器停止运行,并宣称成功完成了语法分析)为止
注意:每步规约都是规范规约,每次规约“句柄”
移入-归约分析器可采取的4种动作:

  • 移入:将下一个输入符号移到栈的顶端
  • 归约:被归约的符号串的右端必然处于栈顶。语法分析器在栈中确定这个串的左端,并决定用哪个非终结符来替换这个串
  • 接收:宣布语法分析过程成功完成
  • 报错:发现一个语法错误,并调用错误恢复子例程

移入-归约分析中存在的问题
造成错误的原因:错误地识别了句柄

LR分析法概述

LR文法是最大的、可以构造出相应移入-归约语法分析器的文法类

L: 对输入进行从左到右的扫描
R: 反向构造出一个最右推导序列
LR(k)分析:需要向前查看k个输入符号的LR分析。当省略(k)时,表示k =1

  1. LR 分析法的基本原理
    自底向上分析的关键问题是:如何正确地识别句柄。
    句柄是逐步形成的,用“状态”表示句柄识别的进展程度
    LR分析器基于这样一些状态来 构造自动机进行句柄的识别

例:S→bBB
S→·bBB 移进状态
S→b·BB / S→bB·B 移进、待归约状态
S→bBB· 归约状态
注意: 产生式A→ε 只生成一个项目A→ ·

  1. LR 分析器(自动机)的总体结构
    在这里插入图片描述
    LR 分析表的结构:
  • sn:将符号a、状态n 压入栈
  • rn:用第n个产生式进行归约

例:文法
① S→BB
② B→aB
③ B→b
在这里插入图片描述

输入bab#

状态 剩余输入 动作
0 # bab#
04 #b ab# 0和b比较s4,移入b,添加4
02 #B ab# 4和a比较r3,归约文法B→b右部长度1,在符号栈和状态栈中分别移出1个符号,在符号栈中进入B。此时栈顶是0,遇到刚规约出的B,到状态2,添加2状态
023 #Ba b# 2和a比较s3,移入a,添加3
0234 #Bab #</
### Python 实现自底向上语法分析 在Python中实现自底向上语法分析通常涉及使用LR解析方法,其中最常见的是SLR(1),LALR(1)和LR(1)。这些算法通过从输入串的左端开始逐步将其转换为目标文法中的起始符号来完成解析过程[^1]。 #### SLR(1) 解析表构建与工作原理 为了更好地理解自底向上解析的工作方式,先来看一看简单的SLR(1)解析器是如何工作的: - **状态集**:由项目集合构成的状态机表示。 - **动作(action)** 表格:定义了对于给定状态和当前读取到的终结符应采取的动作(移入(shift), 归约(reduce) 或 接受(accept))。 - **goto** 表格:指示当执行归约操作后应该转移到哪个新状态。 下面是创建一个简易版本的SLR(1)解析器所需的几个主要步骤: 1. 构建识别合法前缀的语言自动机; 2. 计算每个状态对应的闭包(Closure); 3. 使用Goto函数扩展状态并形成新的状态直到不再有变化为止; 4. 基于上述信息填充action 和 goto表格; #### 示例代码 - 简单表达式求值 (E -> E + T | T, T-> num) 下面给出一段基于以上理论编写的简单四则运算表达式的自底向上解析程序示例: ```python from collections import defaultdict class Parser: def __init__(self): self.stack = [] self.input = [] # 定义文法规则 self.rules = { "S'": ["E"], "E": [["T", "+", "E"], ["T"]], "T": [["num"]] } # 初始化 action 和 goto 表格 self.action_table = defaultdict(dict) self.goto_table = {} self._build_parsing_tables() def _add_rule(self, lhs, rhs_list): """ 添加一条或多条规则 """ for rhs in rhs_list: if isinstance(rhs, str): # 单项处理 rhs = [rhs] key = f"{lhs} -> {' '.join(rhs)}" setattr(self, key.replace(' ', '_'), len(getattr(self, '__dict__', {}))) def _build_parsing_tables(self): """ 构造 LR(0) 的 ACTION 和 GOTO 表""" pass def parse(self, tokens): """ 对输入 token 序列进行解析 """ parser = Parser() tokens = ['num', '+', 'num'] result = parser.parse(tokens) print(result) ``` 这段代码展示了如何设置基本的数据结构以及初始化部分逻辑。然而,完整的`_build_parsing_tables()` 方法需要更复杂的计算才能得到正确的ACTION和GOTO表,这超出了这里可以展示的内容范围。实际应用时还需要考虑错误恢复机制等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值