【问题标题】:Generating an Abstract Syntax Tree for java source code using ANTLR使用 ANTLR 为 java 源代码生成抽象语法树
【发布时间】:2018-07-30 17:10:28
【问题描述】:

如何使用 ANTLR 从 java src 代码生成 AST?
有什么帮助吗?

【问题讨论】:

  • 太宽泛了。从 ANTLR 教程开始,或寻找现有的语法。
  • 获取 Java 语法。通过 ANTLR 生成的类运行 Java 源代码。不过,使用 Eclipse 的东西可能更容易。
  • 您能发布任何有用的链接或教程吗?谢谢

标签: java antlr abstract-syntax-tree


【解决方案1】:

好的,步骤如下:

  1. 转到ANTLR site 并下载最新版本
  2. here 下载Java.gJavaTreeParser.g 文件。
  3. 运行以下命令:

    java -jar antlrTool Java.g
    java -jar antlrTool JavaTreeParser.g
    
  4. 将生成5个文件:

    1. Java.tokens
    2. JavaLexer.java
    3. JavaParser.java
    4. JavaTreeParser.g
    5. JavaTreeParser.tokens

使用此 java 代码生成抽象语法树并打印它:

        String input = "public class HelloWord {"+
                   "public void print(String r){" +
                   "for(int i = 0;true;i+=2)" +
                   "System.out.println(r);" +
                   "}" +
                   "}";

    CharStream cs = new ANTLRStringStream(input);
    JavaLexer jl = new JavaLexer(cs);

    CommonTokenStream tokens = new CommonTokenStream();
    tokens.setTokenSource(jl);
    JavaParser jp = new JavaParser(tokens);
    RuleReturnScope result = jp.compilationUnit();
    CommonTree t = (CommonTree) result.getTree();

    CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);

    nodes.setTokenStream(tokens);

    JavaTreeParser walker = new JavaTreeParser(nodes);

    System.out.println("\nWalk tree:\n");

    printTree(t,0);


    System.out.println(tokens.toString());

    }

public static void printTree(CommonTree t, int indent) {
    if ( t != null ) {
        StringBuffer sb = new StringBuffer(indent);
        for ( int i = 0; i < indent; i++ )
            sb = sb.append("   ");
        for ( int i = 0; i < t.getChildCount(); i++ ) {
            System.out.println(sb.toString() + t.getChild(i).toString());
            printTree((CommonTree)t.getChild(i), indent+1);
        }
    }
}

【讨论】:

  • 谢谢@Aboelnour。但是您引用的页面不再存在。有什么帮助吗?
  • 另一个问题,如果JavaTreeParser.java不在生成的文件中,它是从哪里来的?
  • @MakanTayebi 我认为这会有所帮助:github.com/antlr/grammars-v4
  • @Aboelnour,你能更新一下这个 antlr v4 的答案吗?
  • 即使这个答案是旧的,我把链接放回去:habelitz.com/images/downloads/javagrammars/…
【解决方案2】:

使用antlr4生成java src AST的setps有:

  1. 安装 antlr4 你可以使用this 链接来做到这一点。
  2. 安装后下载JAVA grammar from here
  3. 现在使用命令生成 Java8Lexer 和 Java8Parser:

    antlr4 -visitor Java8.g4

  4. 这将生成几个文件,例如Java8BaseListener.javaJava8BaseVisitor.javaJava8Lexer.javaJava8Lexer.tokensJava8Listener.javaJava8Parser.javaJava8.tokensJava8Visitor.java

使用此代码生成 AST:

import java.io.File;
import java.io.IOException;

import java.nio.charset.Charset;
import java.nio.file.Files;

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.tree.ParseTree;

public class ASTGenerator {

    public static String readFile() throws IOException {
        File file = new File("path/to/the/test/file.java");
        byte[] encoded = Files.readAllBytes(file.toPath());
        return new String(encoded, Charset.forName("UTF-8"));
    }

    public static void main(String args[]) throws IOException {
        String inputString = readFile();
        ANTLRInputStream input = new ANTLRInputStream(inputString);
        Java8Lexer lexer = new Java8Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        Java8Parser parser = new Java8Parser(tokens);
        ParserRuleContext ctx = parser.classDeclaration();

        printAST(ctx, false, 0);
    }

    private static void printAST(RuleContext ctx, boolean verbose, int indentation) {
        boolean toBeIgnored = !verbose && ctx.getChildCount() == 1 && ctx.getChild(0) instanceof ParserRuleContext;

        if (!toBeIgnored) {
            String ruleName = Java8Parser.ruleNames[ctx.getRuleIndex()];
            for (int i = 0; i < indentation; i++) {
                System.out.print("  ");
            }
            System.out.println(ruleName + " -> " + ctx.getText());
        }
        for (int i = 0; i < ctx.getChildCount(); i++) {
            ParseTree element = ctx.getChild(i);
            if (element instanceof RuleContext) {
                printAST((RuleContext) element, verbose, indentation + (toBeIgnored ? 0 : 1));
            }
        }
    }
}

完成编码后,您可以使用 gradle 来构建您的项目,或者您可以在您的项目目录中下载antlr-4.7.1-complete.jar 并开始编译。

如果你想要一个 DOT 文件中的输出以便你可以可视化 AST,那么你可以参考this QnA 帖子或直接参考我使用 gradle 构建项目的repository

希望这会有所帮助。 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 2012-12-21
    相关资源
    最近更新 更多