簡體   English   中英

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 文檔中獲得有關如何構建模式字符串及其相應規則的太多信息。 所以我嘗試了幾種組合來獲得匹配,但它們似乎都不起作用。例如:

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

這給出:

匹配失敗; 找到 0 個標簽

我知道我的字符串模式肯定做錯了。 任何人都可以幫我解釋這個模式匹配函數,並告訴我在這種情況下應該使用什么正確的參數。 此外,提供指向一些有用資源的鏈接將非常有幫助,我可以在這些資源中了解更多信息並處理復雜模式。(我在 ANTLR4 參考中找不到它)

此代碼的解析樹的一部分

我認為你想要的在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所有節點(通過覆蓋BaseListenerenterVariableDeclarator()方法),然后嘗試匹配每個節點上的模式。 例如

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM