The Wayback Machine - https://web.archive.org/web/20221028220219/https://baike.sogou.com/kexue/d10003.htm

抽象语法树

编辑
下列代码是欧几里德算法的抽象语法树: while b ≠ 0 if a > b a := a − b else b := b − a return a

在计算机科学中,抽象语法树(AST),或者简称语法树,是用编程语言编写的源代码的抽象语法结构的树表示。树的每个节点表示源代码中出现的一个构造。语法是“抽象的”,因为它不代表真实语法中出现的每一个细节,而只是结构性的、与内容相关的细节。例如,分组括号隐含在树结构中,像if-condition-then表达式这样的语法结构可以通过具有三个分支的单个节点来表示。

这将抽象语法树与具体语法树区分开来,具体语法树通常被指定为解析树,解析树通常由解析器在源代码翻译和编译过程中构建。一旦建立,通过后续处理,例如上下文分析,将附加信息添加到AST中。

抽象语法树也用于程序分析和程序转换系统。

1 编译器中的应用编辑

抽象语法树是编译器中广泛用于表示程序代码结构的数据结构。AST通常是编译器语法分析阶段的结果。它通常在编译器要求的几个阶段中充当程序的中间表示,并对编译器的最终输出有很大影响。

1.1 动机

AST有几个特性有助于编译过程的进一步步骤:

  • AST可以用它包含的每个元素的属性和注释等信息进行编辑和增强。这种编辑和注释在程序的源代码中是不可能的,因为这意味着要改变它。
  • 与源代码相比,AST不包含无关紧要的标点和分隔符(大括号、分号、圆括号等)。
  • 由于编译器的连续分析阶段,AST通常包含关于程序的额外信息。例如,它可以存储源代码中每个元素的位置,允许编译器打印有用的错误消息。

由于编程语言及其文档的固有性质,需要ASTs。语言本质上常常是模糊的。为了避免这种歧义,编程语言通常被指定为上下文无关文法(CFG)。然而,编程语言的某些方面经常是CFG无法表达的,但却是语言的一部分,并记录在它的规范中。这些细节需要上下文来确定它们的有效性和行为。例如,如果一种语言允许声明新的类型,CFG不能预测这些类型的名称,也不能预测它们的使用方式。即使一种语言有一组预定义的类型,强制正确使用通常也需要一些上下文。另一个例子是鸭子类型(duck typing),其中元素的类型可以根据上下文而改变。运算符重载是另一种根据上下文确定正确用法和最终函数的情况。Java提供了一个很好的例子,其中“+”运算符是字符串的数字加法和串联。

虽然编译器的内部工作还涉及其他数据结构,但AST执行一个独特的功能。在第一阶段,语法分析阶段,编译器生成一个解析树。这个解析树可以通过语法导向翻译来执行编译器的几乎所有功能。尽管这种方法可以提高编译器的效率,但它违背了编写和维护程序的软件工程原则。AST相对于解析树的另一个优势是大小,尤其是AST的高度更小,元素数量更少。

1.2 设计

AST的设计通常与编译器的设计及其预期特性密切相关。

核心要求包括以下内容:

  • 必须保留变量类型,以及每个声明在源代码中的位置。
  • 可执行语句的顺序必须明确表示和定义。
  • 二进制操作的左和右组件必须被存储和正确识别。
  • 必须为赋值语句存储标识符及其赋值。

这些要求可用于设计AST的数据结构。

有些操作总是需要两个元素,例如两个加法项。然而,一些语言构造需要任意数量的参数,例如从命令shell传递给程序的参数列表。因此,用于表示用这种语言编写的代码的AST也必须足够灵活,以允许快速添加未知数量的参数。

AST的另一个主要设计要求是,应该可以将AST反折为源代码形式。重新编译后,生成的源代码在外观上应与原始代码足够相似,在执行上也应完全相同。

1.3 设计模式

由于AST需求的复杂性和编译器的整体复杂性,应用合理的软件开发原则是有益的。其中之一是使用经验证的设计模式来增强模块化和开发的容易性。

不同的操作不一定有不同的类型,所以有一个合理的节点类层次结构是很重要的。随着编译器的发展,这对于AST的创建和修改至关重要。

因为编译器遍历树几次以确定语法正确性,所以使遍历树成为一个简单的操作是很重要的。编译器根据每个节点的类型,在到达它时执行一组特定的操作,所以使用访问者模式通常是有意义的。

1.4 使用

AST在语义分析中被大量使用,编译器在语义分析中检查程序元素和语言的正确使用。编译器还在语义分析期间基于AST生成符号表。树的完整遍历允许验证程序的正确性。

验证正确性后,AST作为代码生成的基础。AST通常用于生成代码生成的中间表示(IR),有时称为中间语言。

阅读 1253
版本记录
  • 暂无