赞
踩
抽象语法树(Abstract Syntax Tree, AST)使用树形结构来表示源代码的抽象语法结构,树上的每一个节点都对应源代码中的一种结构。
表达式:1+2*(3-4)+5
抽象语法树:
抽象语法树:
作用:AST的工厂类,用于创建表示各种语法结构的节点。一般用于创建AST。
作用:用于表示Java中的所有语法结构。每个具体的子类,都代表着一种Java语法结构。某一个节点源代码具体到底是什么类型的节点,可以通过ASTView来查看。
如何获取具体ASTNode节点中的数据呢?
public class Demo1 { /* * 字段1、字段2 */ private String field1 = "Hello World", field2; /** * * @param d1 被除数 * @param d2 除数 * @return */ @RequestMapping("/divide") public Double divide(Double d1, Double d2) { Double result = null; if (d2 == null) { result = (double) 0; } else { result = d1 / d2; for (int i = 0; i < 10; i++) { result /= d2; } } return result; } // 加法 public void plus(int a, int b) { System.out.println(a + b); } /* * 字段3 */ private String field3; }
ASTVisitor子类:
public class DeclarationSeriesVisitor extends ASTVisitor { @Override public boolean visit(FieldDeclaration node) { List fragments = node.fragments(); for (Object obj : fragments) { VariableDeclarationFragment v = (VariableDeclarationFragment) obj; System.out.println("Field:" + v.getName()); } return true; } @Override public boolean visit(MethodDeclaration node) { System.out.println("Method:" + node.getName()); return true; } @Override public boolean visit(TypeDeclaration node) { System.out.println("Class:" + node.getName()); return true; } }
客户端类:
public class App {
public static void main(String[] args) {
String javaFilePath = "F:\\workspace\\codeview-demo\\src\\main\\java\\com\\heshj\\codeview_demo\\Demo1.java";
CompilationUnit compilationUnit = JdtAstUtil.getCompilationUnit(javaFilePath);
DeclarationSeriesVisitor declarationSeriesVisitor = new DeclarationSeriesVisitor();
compilationUnit.accept(declarationSeriesVisitor);
}
}
debug跟一遍代码,感受一下这个具体代码树。
ast使用树状结构存储,采用组合模式分析。我们试想,如果组合模式中的各个节点,都拥有相同的接口操作的话,操作将变得简单,在进行树遍历的时候,甚至可以不用在意具体类的实现。但是分析语法树是一件很严谨的事,由于Java语法很多,因此各个具体节点类都存在或多或少的差异。ast牺牲了通用性,采用各个具体子类具体分析,从而能够看出分析的复杂性。
优点:
1.ast采用ASTVisitor访问者模式来获取想要的任意节点信息;
2.其内部各个具体子节点类,已经封装好遍历下属节点的操作。我们无需自己去遍历树节点,自己遍历也遍历不完。
3 建议获取数据都采用访问者的方式获取,充分利用ast各个节点封装的解析。
缺点:
1.跨文件:ast只能分析彼此独立的java文件(编译单元),以编译单元为根节点的树形节点之间的关联,ast没有提供支持。举个例子,A文件中调用B文件的某个方法,那么在解析A文件这个编译单元时,访问到该调用方法表达式节点的时候,无法指向B文件对应的哪个申明方法节点。因此跨文件调用方法、获取属性字段等,将受到限制。
2.运行时:继承、接口实现、抽象的方法调用、属性继承等操作,无法找到对应的具体类。因为ast是静态代码扫描,无法获取到运行时的具体类型,这是一个局限。
针对上述两个不足,我们应该如何处理呢?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。