
- 编译器设计教程
- 编译器设计 - 首页
- 编译器设计 - 概述
- 编译器设计 - 架构
- 编译器设计 - 编译器的阶段
- 编译器设计 - 词法分析
- 编译器 - 正则表达式
- 编译器设计 - 有限自动机
- 编译器设计 - 语法分析
- 编译器设计 - 解析类型
- 编译器设计 - 自顶向下解析器
- 编译器设计 - 自底向上解析器
- 编译器设计 - 错误恢复
- 编译器设计 - 语义分析
- 编译器 - 运行时环境
- 编译器设计 - 符号表
- 编译器 - 中间代码
- 编译器设计 - 代码生成
- 编译器设计 - 代码优化
- 编译器设计有用资源
- 编译器设计 - 快速指南
- 编译器设计 - 有用资源
编译器设计 - 语义分析
我们已经学习了在语法分析阶段解析器如何构建语法树。在该阶段构建的普通语法树通常对编译器没有用处,因为它不包含任何关于如何评估树的信息。上下文无关语法的产生式,它构成了语言的规则,并没有包含如何解释它们的规则。
例如
E → E + T
上述 CFG 产生式没有与其关联的语义规则,它无法帮助理解产生式。
语义
语言的语义为其结构(如标记和语法结构)提供含义。语义有助于解释符号、它们的类型以及它们彼此之间的关系。语义分析判断源程序中构建的语法结构是否有意义。
CFG + semantic rules = Syntax Directed Definitions
例如
int a = “value”;
不应该在词法和语法分析阶段发出错误,因为它在词法和结构上是正确的,但它应该生成语义错误,因为赋值的类型不同。这些规则由语言的语法设定并在语义分析中进行评估。语义分析中应执行以下任务
- 作用域解析
- 类型检查
- 数组边界检查
语义错误
我们已经提到了一些语义分析器预期识别的语义错误
- 类型不匹配
- 未声明的变量
- 保留标识符误用。
- 在一个作用域中多次声明变量。
- 访问超出作用域的变量。
- 实际参数和形式参数不匹配。
Explore our latest online courses and learn new skills at your own pace. Enroll and become a certified expert to boost your career.
属性文法
属性文法是上下文无关文法的一种特殊形式,其中一些附加信息(属性)被附加到一个或多个非终结符上,以提供上下文相关信息。每个属性都有一个定义良好的值域,例如整数、浮点数、字符、字符串和表达式。
属性文法是为上下文无关文法提供语义的一种媒介,它可以帮助指定编程语言的语法和语义。属性文法(当被视为语法树时)可以在树的节点之间传递值或信息。
例子
E → E + T { E.value = E.value + T.value }
CFG 的右侧包含指定如何解释语法的语义规则。这里,非终结符 E 和 T 的值相加,结果复制到非终结符 E。
语义属性可以在解析时从其域中分配给它们的值,并在赋值或条件时进行评估。根据属性获取其值的方式,可以将其大致分为两类:综合属性和继承属性。
综合属性
这些属性从其子节点的属性值获取值。为了说明,假设以下产生式
S → ABC
如果 S 从其子节点 (A,B,C) 获取值,则称其为综合属性,因为 ABC 的值被综合到 S 中。
在我们之前的示例 (E → E + T) 中,父节点 E 从其子节点获取其值。综合属性永远不会从其父节点或任何兄弟节点获取值。
继承属性
与综合属性相反,继承属性可以从父节点和/或兄弟节点获取值。如以下产生式所示,
S → ABC
A 可以从 S、B 和 C 获取值。B 可以从 S、A 和 C 获取值。同样,C 可以从 S、A 和 B 获取值。
扩展:当非终结符根据语法规则扩展为终结符时

归约:当终结符根据语法规则归约为其相应的非终结符时。语法树自顶向下、从左到右进行解析。每当发生归约时,我们都应用其相应的语义规则(动作)。
语义分析使用语法制导翻译来执行上述任务。
语义分析器从其前一阶段(语法分析)接收 AST(抽象语法树)。
语义分析器将属性信息附加到 AST,这些信息称为带属性的 AST。
属性是二元组值,<属性名称,属性值>
例如
int value = 5; <type, “integer”> <presentvalue, “5”>
对于每个产生式,我们都附加一个语义规则。
S 属性 SDT
如果 SDT 仅使用综合属性,则称为 S 属性 SDT。这些属性使用 S 属性 SDT 进行评估,这些 SDT 的语义操作写在产生式(右侧)之后。

如上所示,S 属性 SDT 中的属性在自底向上解析中进行评估,因为父节点的值取决于子节点的值。
L 属性 SDT
这种形式的 SDT 使用综合属性和继承属性,但限制不能从右侧兄弟节点获取值。
在 L 属性 SDT 中,非终结符可以从其父节点、子节点和兄弟节点获取值。如以下产生式所示
S → ABC
S 可以从 A、B 和 C 获取值(综合)。A 只能从 S 获取值。B 可以从 S 和 A 获取值。C 可以从 S、A 和 B 获取值。任何非终结符都不能从其右侧的兄弟节点获取值。
L 属性 SDT 中的属性以深度优先和从左到右的解析方式进行评估。

我们可以得出结论,如果一个定义是 S 属性的,那么它也是 L 属性的,因为 L 属性定义包含 S 属性定义。