ANTLR 4 - 树模式匹配

ANTLR 4 - Tree pattern matching

我正在尝试了解 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 文档中获得有关如何构造模式字符串及其相应规则的太多信息。所以我尝试了几种组合来获得匹配,但其中 none 似乎 work.For 例如:

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

这给出:

Match failed; found 0 labels

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

A part of parse tree for this code

我想你想要的在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

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

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

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().[=26= 检索]

输出为:

Match
 - IDENTIFIER: i
 - INITIALIZER: 0