AST 抽象语法树简介

抽象语法树简介

如果不先了解语法树的概念,就不可能考虑Java语言解析器将如何有用。

首先,我们尝试想象源代码可以表示为一棵树。

两者都有一个起点,从这里分支彼此独立地形成,无论是作为代码语句,还是在树的情况下,都是实际的分支。

与真实树的分支一样,将复杂的语句分解成较小的部分的过程将继续进行,直到我们碰到末端或叶子为止。

代表Java代码的树将具有一个代表整个文件的根,并且根节点连接到文件的所有顶部元素(例如导入或类声明)。

从单个类声明中,我们可以到达多个节点,它们代表该类的字段或方法。

  • 图1.1

image

就像是真实树上的分支除了通过其源头之外,没有与其他分支的连接一样,对于表示源代码的树也是如此。

作为人类或编译器,您知道变量引用或方法调用与源代码的另一部分有关,而语法树则与源代码的另一部分无关,这是一个重要的区别⁸。

一切都是一个节点(Node)

但是,树的隐喻只带我们走了这么远。

在经典计算机科学意义上,当谈论带有顶点和边的图时,或者在有树的情况下谈论有向图时。

根据您正在阅读的文献,它们也可能是节点和关系的同义词。

出于本书的目的,我们使用节点,因为它不那么复杂,并且与库类一致。

有一些简单的规则可以控制什么是树。

除根节点外,所有节点都将只有一个传入关系。

根节点将为零。

所有节点可以具有零到许多外向关系。

那些外向关系为零的节点被认为是叶节点,不被视为父节点。

相反,那些具有传出关系的节点被视为一个或多个子节点的分支和父节点。

当节点具有子节点时,就JavaParser创建的对象模型而言,它简单地表示为Node类上的一个名为childrenNodes的 List <Node>

树木的词汇量还进一步取决于家庭定义:具有相同父母的子节点被视为兄弟姐妹。

当可以分别通过立即向上或向下导航树来关联节点时,也使用祖先和后代。

因此,所有节点都是根节点的后代。

为了在库中对此模型建模,您与MethodDeclaration,Statement,Parameter等一起使用的Java语言概念最终将成为JavaParser库中Node类的后代(在面向对象的意义上)。

在大多数情况下,JavaParser尝试保持对官方语法规范(用于类命名)中定义的名称的正确性。

什么时候是节点,而不是节点?

通常当它是另一个节点的属性时。

除了具有描述语言概念的特定类型外,它们还表示例如 MethodDeclaration节点应具有描述其特征的属性。

行号是一个很好的例子,对于AST中的所有节点,在解析库时都会记录每个节点的行号。

如果考虑使用MethodDeclaration,它将具有代表其名称,其参数参数(如果有)的子节点,其类型(即返回的内容和主体)。

可以用来定义方法的其他语言关键字呢? 最终,静态,抽象等?

好吧,这些被定义为MethodDeclaration本身的修饰符属性。

这些本身是否可以是单独的节点实体,而不是属性?

是。 像大多数事物一样,以这种方式表示它们是一种设计选择,并且您会发现支持者争论这两种情况。

构建我们第一颗树

为了确定对于相当抽象的讨论的直觉,我们将看一下将通过使用JavaParser解析简单类来创建的图形表示。

import java.time.LocalDateTime;

public class TimePrinter {

    public static void main(String[] args) {
        System.out.print(LocalDateTime.now());
    }

}

上述的类用树表示如下:

image

该图显示了编译单元有三个子级。

一个用于程序包声明,一个用于导入,最后一个用于类声明。

这不是整棵树,但是,请考虑端子上方树的底部的三角符号表示该部分已汇总。

我们的ClassOrInterfaceDeclaration有一个代表名称NameExpr的子项,还有一个MethodDeclaration,尤其是这个将进一步分支。

image

现在,我们可以看到该方法的名称,返回类型和参数,以及BlockStmt,可以再次对其进行详细说明。

image

最后,但也许最重要的是,我们有代表 BlockStmt 的树的分支。

就其本身而言,它构成了整个树的重要部分,但仅代表一行代码。

我们希望您可以从该示例中看到语法树会变得相当复杂!

超越抽象

我们还应该考虑什么使AST抽象,而不是说具体的语法树或语法分析树。

正如它在计算机科学的更广泛领域中的含义一样,它与信息的遗漏有关。

通常,在AST空格中,省略了注释标记,以及可以通过树的结构推断出的括号。

然而,在JavaParser库的支持期间,我们意识到许多人都希望获得与注释有关的信息。

因此,默认情况下,在解析时,JavaParser库将记录注释信息并将其包括在树表示中。

通过配置选项可以排除注释。

此外,该团队还在研究在编写类文件时为保留空白和漂亮的打印选项提供支持的方法。

参考资料

官方语法书