Utworzyłem tę przykładową gramatykę przy użyciu ANTLR4 plugin w IntelliJ i kiedy używam jej łańcucha narzędzi do generowania wizualnej reprezentacji dla niektórych nieprawidłowych treści (w tym przypadku pustego ciągu), ta reprezentacja wydaje się różnić od mojej można uzyskać podczas wykonywania rzeczywistego przejścia drzewa parse za pomocą przykładowej implementacji gościa/detektora dla tego samego wejścia.Dlaczego istnieje taka różnica między wizualizacją drzewa analiz i moją wizytą użytkownika/słuchacza?
Jest to gramatyka:
grammar TestParser;
THIS : 'this';
Identifier
: [a-zA-Z0-9]+
;
WS : [ \t\r\n\u000C]+ -> skip;
parseExpression:
expression EOF
;
expression
: expression bop='.' (Identifier | THIS) #DottedExpression
| primary #PrimaryExpression
;
primary
: THIS #This
| Identifier #PrimaryIdentifier
;
Na pustym ciągiem znaków, pojawia się następujący drzewa:
To drzewo wskazuje, że parser zbudowali drzewo składniowy, który zawiera „DottedExpression "i" primary: This "(zakładając, że używa do tego własnej implementacji visitor/listener). Jednak gdy próbuję to samo za pomocą następującego kodu:
package org.example.so;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class TestParser {
public static void main(String[] args) {
String input = "";
TestParserLexer lexer = new TestParserLexer(CharStreams.fromString(input));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
TestParserParser parser = new TestParserParser(tokenStream);
TestParserParser.ParseExpressionContext parseExpressionContext = parser.parseExpression();
MyVisitor visitor = new MyVisitor();
visitor.visit(parseExpressionContext);
System.out.println("----------------");
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new MyListener(), parseExpressionContext);
System.out.println("----------------");
}
private static class MyVisitor extends TestParserBaseVisitor {
@Override
public Object visitParseExpression(TestParserParser.ParseExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
return super.visitParseExpression(ctx);
}
@Override
public Object visitDottedExpression(TestParserParser.DottedExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()] + ":DottedExpression");
return super.visitDottedExpression(ctx);
}
@Override
public Object visitPrimaryExpression(TestParserParser.PrimaryExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()] + ":PrimaryExpression");
return super.visitPrimaryExpression(ctx);
}
@Override
public Object visitThis(TestParserParser.ThisContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
return super.visitThis(ctx);
}
@Override
public Object visitPrimaryIdentifier(TestParserParser.PrimaryIdentifierContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
return super.visitPrimaryIdentifier(ctx);
}
}
private static class MyListener extends TestParserBaseListener {
@Override
public void enterParseExpression(TestParserParser.ParseExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
}
@Override
public void enterDottedExpression(TestParserParser.DottedExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()] + ":DottedExpression");
}
@Override
public void enterPrimaryExpression(TestParserParser.PrimaryExpressionContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()] + ":PrimaryExpression");
}
@Override
public void enterThis(TestParserParser.ThisContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
}
@Override
public void enterPrimaryIdentifier(TestParserParser.PrimaryIdentifierContext ctx) {
System.out.println(TestParserParser.ruleNames[ctx.getRuleIndex()]);
}
}
}
pojawia się następujący komunikat:
line 1:0 mismatched input '<EOF>' expecting {'this', Identifier}
parseExpression
expression:PrimaryExpression
----------------
parseExpression
expression:PrimaryExpression
----------------
Tak więc, nie tylko głębie drzewo nie pasują, wyjście nawet wskazuje inna reguła została dopasowana druga ("Ekspresja podstawowa" zamiast "Przekreślona ekspresja").
Dlaczego istnieje taka różnica między tym, co pokazałem, a tym, co próbuję pokazać? Jak utworzyć tę samą reprezentację drzewa, jak pokazuje wtyczka?
Korzystanie z ANTLR w wersji 4.7. Wersja wtyczki to 1.8.4.
Szybko przyjrzano się źródłu ANTLR. Domyślam się, że drzewo analizowania graficznego jest tworzone przy użyciu analizatora składni w innym trybie przewidywania niż w przypadku samodzielnego uruchamiania analizatora składni. – Gene
Nawiasem mówiąc, wygląda na to, że kod generuje drzewo analizy, które jest renderowane graficznie. Być może możesz znaleźć wskazówki dotyczące konfiguracji parsera: https://github.com/antlr/antlr4/blob/46b3aa98cc8d8b6908c2cabb64a9587b6b973e6c/tool/src/org/antlr/v4/gui/TestRig.java#L170 – Gene