【eclipse高效开发】——eclipse AST(抽象语法树)简介

    xiaoxiao2021-12-14  18

    Eclipse AST

    什么是AST? 

    是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种 结构。抽象语法树(Abstract Syntax Tree ,AST)作为程序的一种中间表示形式,在程序分析等诸多领域有广泛的应用 利用抽象语法树可以方便地实现多种源程序处理工具,比如源程序浏览器、智能编辑器、语言翻译器等.

    eclipse AST简介:

    Eclipse AST是Eclipse JDT的一个重要组成部分,定义在包org.eclipse.jdt.core.dom中,用来表示Java语言中 的所有语法结构。Eclipse AST采用工厂方法模式和访问者模式来设计和实现,这样可以减轻用户深入了解其内部结 构的压力,并且方便用户利用它们构建并处理AST。你可以打开Eclipse帮助页面,通过鼠标依次点击窗口左边的目录 “JDT Plug-in Developer Guide”Æ“Reference”Æ“API Reference” Æ“org.eclipse.jdt.core.dom”,即可打 开这个包的详细说明。 在Eclipse AST中,相关的类主要有以下三部分: ASTNode类及其派生类:用于描述各种AST节点的类,每个AST节点表示一个 Java源程序中的一个语法结构,例如, 一个名字、类型、表达式、语句或声明等。 AST类:创建AST节点的工厂类,类中包含许多创建各类AST节点的工厂方法, 用户可以利用这些方法来构建AST。 ASTVisitor类:AST的访问者抽象类,类中声明了一组访问各类AST节点的visit( )方法、endVisit( )方法和 preVisit( )方法。

    AST节点类:

    在Eclipse AST中,Java源程序中的每个语法结构对应为一个AST节点,所有的AST节点按其在语法上的关系连接 形成一棵AST树。类ASTNode是AST树中各类节点的抽象基类,其余的AST节点类都由它派生。在ASTNode类中声明有各个 具体的AST节点类所对应的类型标识,如ASTNode.COMPILATION_UNIT代表Compilation_Unit节点类,这类节点用来表示 一个Java源程序文件。 为便于自顶向下(从父节点到子节点)或者自底向上(从子节点到父节点)访问AST树,AST 节点含有指向其父节点的parent域以及若干关联的子节点域。在AST节点类中,以属性(property)来统一处理子节点 以及用户自定义的节点属性,属性的访问方法有: void setProperty(String propertyName, Object data) // 设置指定属性的值 Object getProperty(String propertyName) // 取得指定属性的值 Map properties( ) // 返回节点的所有属性表,这个表是不可修改的 在每个具体的AST节点类中,以类常量形式声明该类节点所拥有的基本属性(即基本的子节点)类别,并定义了存放 属性值的域以及设置和访问属性的方法。例如,在一个Java源程序文件中,有可选的package声明、0个或多个import 声明以及至少1个类型声明(可以是类声明或接口声明),从而在表示Java源程序文件(称为编译单元)的AST节点类 CompilationUnit中就声明有final类变量PACKAGE_PROPERTY、IMPORTS_PROPERTY和TYPES_PROPERTY,分别表示package 属性、imports属性和types属性,同时还定义有如下的访问方法: List imports( ) // 该节点的所有import声明,按在程序中的出现次序排列 tob_id_3385 List types( ) // 该节点的所有顶层类型声明,按在程序中的出现次序排列 void setPackage(PackageDeclaration pkgDecl) // 设置该节点的package声明 PackageDeclaration getPackage( ) // 取得该节点的package声明 其中,类型相同的子节点组成的序列以java.util.List接口类来表示,这个接口类包含add、get、set、remove等方 用于访问和修改序列。在实际构造和访问AST树时,需要注意统一所使用的List接口类的实现类,例如,可以统一 使 用类java.util.LinkedList或者统一使用类java.util.ArrayList来表示序列。

    在AST节点类中,只提供获取父节点的方法,即 ASTNode getParent( ) 而没有提供设置父节点的方法,

    这是因为对节点的parent域的设置是伴随着将该节点设置为其他节点的子节点而自动进行的。一个新创建的AST节点

    是没有设置其父节点的。当节点A通过形如setCHILD方法,如A.setPackage(B)方法,或者通过序列的add或set方法,

    如A.types( ).add(B)方法,将节点B设为自己的孩子时,B节点的parent域将自动设置为对A节点的引用;对于那些

    因上述操作导致不再是A节点的子节点来说,其parent域将被自动设置为null。每个AST节点及其子节点只能归属于

    一棵AST树。如果将一棵AST树中的某个AST节点添加到另一棵AST树中,则必须复制这个节点及其所有的子孙节点,

    以保证这些节点只属于一棵AST树。此外,AST树中不能含有环,如果某些操作会导致AST有环,则这些操作将失败。

    为支持对源程序的分析和类型检查等,每个AST节点还含有一组位标志(用一个int型数表示) 用来传播与该

    节点有关的附加信息,这些位标志可以通过节点的以下方法来存取:

    void setFlags(int flags) 、int getFlags( ) 。

    此外,Eclipse AST还支持访问者模式,每个AST节点都含有方法: void accept(ASTVisitor visitor) 用于统一

    表示对当前节点访问时所要执行的任务,这个任务由参数visitor来给定。你可以进一步了解ASTVisitor类以及访问

    者模式来了解对AST树的访问。

    2.AST类:

    org.eclipse.jdt.core.dom.AST是AST节点的工厂类,即它提供一系列形如 TYPE newTYPE( ) 的工厂方法,用来创建名为TYPE的Eclipse AST节点类的实例,新创建的节点并没有设置父节点。例如,方法 CompilationUnit newCompilationUnit( ) 用来创建由这个AST所拥有的一个编译单元节点。 要使用这些方法,首先需要创建AST类的实例:  AST ast = AST.newAST(AST.JLS3); 其中,参数AST.JLS3指示所生成的ast包含处理JLS3(Java语言规范第3版)的AST API。JLS3是Java语言所有早期版本的超集,JLS3 API可以用来处理直到Java SE 6(即JDK1.6)的Java程序。

    3.AST类:

    org.eclipse.jdt.core.dom.ASTVisitor是AST树的访问者类,它提供一套方法来实现对给定节点的访问。这套方法中有两组是与具体的AST节点类T相关的,即visit方法和endVisit方法,有两个是与具体的AST节点类无关的,即preVisit方法和postVisit方法。这些方法都通过参数接收一个AST节点node,然后对这个节点进行访问以执行一些操作。当你需要对AST树实现特定的访问功能时,你只需要结合实际需求设计和实现ASTVisitor类的子类就可以了。例如,在本章的课程设计中,你需要实现ASTVisitor类的派生类InterpVisitor,在其中重写(override)与需要解释执行的语法结构相对应的visit( )方法。

    Eclipse AST使用示例:

    在这一节中,我们将演示如何利用Eclipse AST手工构建如下的SimpleMiniJOOL程序的AST中间表示。

    class Program { static void main() { i = 10; } }首先,你需要通过Eclipse AST工厂类中的方法newAST()建立一个AST实例:   AST ast = AST.newAST(JLS3);  利用这个AST实例,就可以按如下的方法创建各种AST节点,并构建完整的抽象语法树。 然后,利用Eclipse AST工厂类中的各种创建方法按如下步骤创建所需要的AST节点: 

    1) 整个SimpleMiniJOOL程序构成一个CompilationUnit:

      CompilationUnit cu = ast.newCompilationUnit();  

    2) 在CompilationUnit实例中包含一个TypeDeclaration,表示程序中的类Program: 

    TypeDeclaration type = ast.newTypeDeclaration( ); type.setName(ast.newSimpleName(“Program”)); // 定义类的名字 

    3) 在这个TypeDeclaration实例中添加类 Program中的方法main(): 

    MethodDeclaration method = ast.newMethodDeclaration( ); method.setName(ast.newSimpleName(“main”)); 

    type.bodyDeclarations().add(method); 

    // 设置方法main()的modifier为static

    method.modifiers().add( ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD)); 

    // 设置方法main()的返回类型为void method.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID));

    4) 构造main函数的函数体

    mainBody Block mainBody = ast.newBlock(); method.setBody(mainBody); 

    5) 向方法main函数体mainBody中添加语句 

    Assignment assign = ast.newAssignment(); // 构建赋值表达式  assign.setLeftHandSide(ast.newSimpleName("i")); // 设置赋值表达式的左值为i  assign.setOperator(Assignment.Operator.ASSIGN); // 设置赋值表达式的赋值算符为 assign.setRightHandSide(ast.newNumberLiteral("10")); // 设置赋值表达式的右值为数字10 

      ExpressionStatement statement = ast.newExpressionStatement(assign);// 由赋值表达式构建语句, 

    mainBody.statements().add(statement); //并把这个语句加入方法Main()的函数体

    至此,用Eclipse AST表示的SimpleMiniJOOL程序的抽象语法树就构建完毕lab1/src/edu/ustc/cs/compile/interpreter/TestCase.java中的createSampleAST( )方法给出了构建一个简单SimpleMiniJOOL程序对应的AST的完整示例。 需要再次强调的是,使用Eclipse AST构建的抽象语法树在拓扑结构上必须是无环的。无论是手工构建AST还是自动构建AST,你都需要小心的检查自己的代码,避免违反这个原则。

    <本文参考:《Eclipse AST(抽象语法树)使用指南》

    转载请注明原文地址: https://ju.6miu.com/read-964223.html

    最新回复(0)