编译器设计 - 语义分析
-
简述
我们已经了解了解析器如何在语法分析阶段构建解析树。在该阶段构建的普通解析树通常对编译器没有用处,因为它不携带任何有关如何评估树的信息。制定语言规则的上下文无关语法的产生不适应如何解释它们。例如E → E + T
上面的 CFG 产生式没有与之相关的语义规则,它无助于理解这个产生式。 -
语义
一种语言的语义为其结构提供了意义,例如标记和语法结构。语义有助于解释符号、它们的类型以及它们之间的关系。语义分析判断源程序中构造的语法结构是否具有任何意义。CFG + semantic rules = Syntax Directed Definitions
例如:int a = “value”;
不应该在词法和句法分析阶段发出错误,因为它在词法和结构上是正确的,但它应该产生语义错误,因为赋值的类型不同。这些规则由语言的语法设置并在语义分析中进行评估。在语义分析中应完成以下任务:- 范围解析
- 类型检查
- 数组绑定检查
-
语义错误
我们已经提到了语义分析器应该识别的一些语义错误:- 类型不匹配
- 未声明的变量
- 保留标识符滥用。
- 在一个范围内多次声明变量。
- 访问超出范围的变量。
- 实际参数和形式参数不匹配。
-
属性语法
属性文法是上下文无关文法的一种特殊形式,其中一些附加信息(属性)附加到其一个或多个非终结符以提供上下文相关信息。每个属性都有明确定义的值域,例如整数、浮点数、字符、字符串和表达式。属性语法是为上下文无关语法提供语义的媒介,它可以帮助指定编程语言的语法和语义。属性语法(当被视为解析树时)可以在树的节点之间传递值或信息。Example: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 中获取值。Expansion:根据语法规则将非终结符扩展为终结符时Reduction: 当一个终结符根据语法规则被简化为它对应的非终结符时。语法树是自上而下和从左到右解析的。每当减少发生时,我们都会应用其相应的语义规则(动作)。语义分析使用语法定向翻译来执行上述任务。语义分析器从其前一阶段(语法分析)接收 AST(抽象语法树)。语义分析器将属性信息附加到 AST 中,称为 Attributed AST。属性是两个元组值,<属性名,属性值>例如:int value = 5; <type, “integer”> <presentvalue, “5”>
对于每个产生式,我们附加一个语义规则。 -
S 属性的 SDT
如果 SDT 仅使用合成属性,则称为 S-attributed 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 属性的定义。