- 编译器设计教程
- 编译器设计 - 首页
- 编译器设计 - 概述
- 编译器设计 - 架构
- 编译器设计 - 编译器的阶段
- 编译器设计 - 词法分析
- 编译器 - 正则表达式
- 编译器设计 - 有限自动机
- 编译器设计 - 语法分析
- 编译器设计 - 分析类型
- 编译器设计 - 自顶向下分析器
- 编译器设计 - 自底向上分析器
- 编译器设计 - 错误恢复
- 编译器设计 - 语义分析
- 编译器 - 运行时环境
- 编译器设计 - 符号表
- 编译器 - 中间代码
- 编译器设计 - 代码生成
- 编译器设计 - 代码优化
- 编译器设计有用资源
- 编译器设计 - 快速指南
- 编译器设计 - 有用资源
编译器设计 - 自底向上分析器
自底向上分析从树的叶子节点开始,向上工作直到到达根节点。在这里,我们从一个句子开始,然后以相反的方式应用产生式规则,以便到达开始符号。下图描述了可用的自底向上分析器。
移进-归约分析
移进-归约分析使用两个独特的步骤进行自底向上分析。这些步骤称为移进步骤和归约步骤。
移进步骤:移进步骤指的是输入指针向下一个输入符号(称为移进符号)的推进。此符号被压入堆栈。移进符号被视为语法树的单个节点。
归约步骤:当分析器找到一个完整的语法规则(RHS)并将其替换为(LHS)时,称为归约步骤。当堆栈顶部包含一个句柄时,就会发生这种情况。为了归约,对堆栈执行 POP 函数,该函数弹出句柄并将其替换为 LHS 非终结符。
LR 分析器
LR 分析器是一种非递归的、移进-归约的、自底向上的分析器。它使用广泛的上下文无关语法,使其成为最有效的语法分析技术。LR 分析器也称为 LR(k) 分析器,其中 L 表示从左到右扫描输入流;R 表示反向构建最右推导,k 表示用于决策的前瞻符号数。
有三种广泛使用的算法可用于构建 LR 分析器
- SLR(1) – 简单 LR 分析器
- 适用于最小的语法类别
- 状态数少,因此表格非常小
- 简单快速的构建
- LR(1) – LR 分析器
- 适用于完整的 LR(1) 语法集
- 生成大型表格和大量状态
- 构建速度慢
- LALR(1) – 前瞻 LR 分析器
- 适用于中等大小的语法
- 状态数与 SLR(1) 相同
LR 分析算法
这里我们描述了一个 LR 分析器的骨架算法
token = next_token() repeat forever s = top of stack if action[s, token] = “shift si” then PUSH token PUSH si token = next_token() else if action[s, token] = “reduce A::= β“ then POP 2 * |β| symbols s = top of stack PUSH A PUSH goto[s,A] else if action[s, token] = “accept” then return else error()
LL 与 LR
LL | LR |
---|---|
执行最左推导。 | 反向执行最右推导。 |
从堆栈上的根非终结符开始。 | 以堆栈上的根非终结符结束。 |
当堆栈为空时结束。 | 从空堆栈开始。 |
使用堆栈来指定仍然需要期望的内容。 | 使用堆栈来指定已经看到的内容。 |
自顶向下构建语法树。 | 自底向上构建语法树。 |
连续地从堆栈中弹出非终结符,并压入相应的右侧。 | 尝试在堆栈上识别右侧,弹出它,并压入相应的非终结符。 |
扩展非终结符。 | 归约非终结符。 |
在从堆栈中弹出终结符时读取它。 | 在将终结符压入堆栈时读取它。 |
语法树的前序遍历。 | 语法树的后序遍历。 |
广告