ANTLR 4 - 树模式匹配

时间:2018-03-28 06:52:12

标签: java pattern-matching antlr antlr4

我试图理解ANTLR 4中的解析树匹配,所以为此 我有以下java代码:

package sampleCodes;

public class fruits {
  public static void main(String[] args){
    int a = 10;
    System.out.println(a);
  }
}

我正在使用ANTLR 4来创建此代码的解析树。现在,我想使用树模式匹配函数来查找" int a = 10;"。 GitHub上有一个文档:https://github.com/antlr/antlr4/blob/master/doc/tree-matching.md通过一个例子解释了这个(类似的东西):

ParseTree t = ...; // assume t is a statement
ParseTreePattern p = parser.compileParseTreePattern("<ID> = <expr>;", MyParser.RULE_statement);
ParseTreeMatch m = p.match(t);
if ( m.succeeded() ) {...}

通过阅读本文档和其他一些资源,我理解的是:

ParseTreePattern p = parser.compileParseTreePattern("<ID> = <expr>;", MyParser.RULE_statement);

作为第二个参数传递的规则必须能够正确地解析作为第一个参数提供的模式。 现在我使用的语法是java给出的: https://github.com/antlr/grammars-v4/tree/master/java

  

JavaLexer.g4,   JavaParser.g4

我无法从上面的GitHub文档中获得有关如何构建模式字符串及其相应规则的大量信息。所以我尝试了几种组合来获得匹配,但它们似乎都没有用。例如:

ParseTreePattern p = parser.compileParseTreePattern("<variableDeclaratorId> = <variableInitializer>", parser.RULE_variableDeclarator);
ParseTreeMatch m = p.match(tree);
System.out.println(m);

这给出了:

  

比赛失败;找到0个标签

我知道我在字符串模式中肯定做错了。任何人都可以帮我解释这个模式匹配函数,并告诉在这种情况下应该使用什么正确的参数。此外,提供一些有用资源的链接将非常有帮助,我可以在这些资源中了解更多相关信息并处理复杂模式。(我在ANTLR4参考资料中找不到它)

A part of parse tree for this code

2 个答案:

答案 0 :(得分:1)

我认为您想要的内容在Combining XPath and tree pattern matching中有描述。

或许这样的事情:

import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.pattern.ParseTreeMatch;
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;

import java.util.List;

public class Main {

  public static void main(String[] args) {

    String source = "package sampleCodes;\n" +
            "\n" +
            "public class fruits {\n" +
            "\n" +
            "  static { int q = 42; }\n" +
            "\n" +
            "  public static void main(String[] args){\n" +
            "    int a = 10;\n" +
            "    System.out.println(a);\n" +
            "  }\n" +
            "}\n";

    JavaLexer lexer = new JavaLexer(CharStreams.fromString(source));
    JavaParser parser = new JavaParser(new CommonTokenStream(lexer));
    ParseTree tree = parser.compilationUnit();

    ParseTreePattern p = parser.compileParseTreePattern("<IDENTIFIER> = <expression>", JavaParser.RULE_variableDeclarator);
    List<ParseTreeMatch> matches = p.findAll(tree, "//variableDeclarator");

    for (ParseTreeMatch match : matches) {
      System.out.println("\nMATCH:");
      System.out.printf(" - IDENTIFIER: %s\n", match.get("IDENTIFIER").getText());
      System.out.printf(" - expression: %s\n", match.get("expression").getText());
    }
  }
}

产生以下输出:

MATCH:
 - IDENTIFIER: q
 - expression: 42

MATCH:
 - IDENTIFIER: a
 - expression: 10

答案 1 :(得分:0)

关于您使用的语法,您的字符串模式是正确的。

match()找不到任何内容的原因,可能是您将整棵树传递给了它(即根中规则为compilationUnit的树) 并且您可能期望它搜索整个树,而match()仅尝试将模式与给定的ParseTree对象进行匹配。 match()不会尝试在给定ParseTree的子树中找到给定模式。为了使它起作用,您首先需要找到VariableDeclaratorContext的所有节点(通过覆盖enterVariableDeclarator()中的BaseListener方法),然后尝试在每个节点上匹配模式。例如

import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.pattern.ParseTreeMatch;
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;

public class Main {
    public static void main(String[] args) {
        String javaCode = "public class Main {\n" +
                "            public static void main() {\n" +
                "                    int i =0;\n" +
                "            }\n" +
                "}";


        JavaGLexer javaGLexer = new JavaGLexer(CharStreams.fromString(javaCode));
        CommonTokenStream tokens = new CommonTokenStream(javaGLexer);
        JavaGParser javaGParser = new JavaGParser(tokens);
        ParseTree tree = javaGParser.compilationUnit();
        ParseTreePattern p = javaGParser.compileParseTreePattern("<variableDeclaratorId> = <variableInitializer>", javaGParser.RULE_variableDeclarator);
        ParseTreeWalker walker = new ParseTreeWalker();
        IDListener idListener = new IDListener();
        walker.walk(idListener, tree);
        ParseTreeMatch match;
        for (JavaGParser.VariableDeclaratorContext ctx: idListener.getVarCTXs())
        {
            match  = p.match(ctx);
            if (match.succeeded()) {
                System.out.println("Match \n" + " - IDENTIFIER: " +
                        match.get("variableDeclaratorId").getText() +
                        "\n - INITIALIZER: " + match.get("variableInitializer").getText());
            }
        }
    }
}

IDListener扩展了JavaGBaseListener并覆盖了enterVariableDeclarator(),并将variableDeclator个节点放在列表中,getVarCTXs()可对其进行检索。

输出为:

Match
 - IDENTIFIER: i
 - INITIALIZER: 0