Java 为什么解析树可视化和我的访问者/侦听器遍历之间存在如此大的差异?
我使用IntelliJ中的ANTLR4创建了这个示例语法,当我使用它的工具链为一些无效内容(在本例中是一个空字符串)生成可视化表示时,这种表示形式似乎与我在使用同一输入的示例访问者/侦听器实现进行实际的解析树遍历时所能得到的不同 这是语法:Java 为什么解析树可视化和我的访问者/侦听器遍历之间存在如此大的差异?,java,intellij-idea,antlr4,Java,Intellij Idea,Antlr4,我使用IntelliJ中的ANTLR4创建了这个示例语法,当我使用它的工具链为一些无效内容(在本例中是一个空字符串)生成可视化表示时,这种表示形式似乎与我在使用同一输入的示例访问者/侦听器实现进行实际的解析树遍历时所能得到的不同 这是语法: grammar TestParser; THIS : 'this'; Identifier : [a-zA-Z0-9]+ ; WS : [ \t\r\n\u000C]+ -> skip; parseEx
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
;
对于空字符串,我得到以下树:
此树表示解析器构建了一个包含“DottedExpression”和“primary:This”的解析树(假设它使用自己的访问者/侦听器实现来完成此操作)。但是,当我尝试使用以下代码执行相同操作时:
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()]);
}
}
}
我得到以下输出:
line 1:0 mismatched input '<EOF>' expecting {'this', Identifier}
parseExpression
expression:PrimaryExpression
----------------
parseExpression
expression:PrimaryExpression
----------------
行1:0不匹配的输入“”,应为{this',标识符}
解析表达式
表达式:PrimaryExpression
----------------
解析表达式
表达式:PrimaryExpression
----------------
因此,不仅树深度不匹配,输出还表明第二次匹配了不同的规则(“PrimaryExpression”而不是“DottedExpression”)
为什么我所展示的和我试图展示的之间有如此大的差异?如何创建与插件所示相同的树表示
使用ANTLR版本4.7。插件版本为1.8.4。此问题已在插件版本1.8.2中修复。如果您有版本1.8.2或更高版本,那么您可能会发现该问题的其他未知子类别
然而(基于我所指的问题),只有当解析导致错误时,树才会不同。因此,如果您对使用错误信息不感兴趣,您应该可以 快速查看了ANTLR源。我的猜测是,图形解析树是以与您自己运行解析器时不同的预测模式使用解析器创建的。顺便说一句,这似乎是生成以图形方式呈现的解析树的代码。也许您可以在这里寻找解析器设置的线索:我正在使用一个更新的版本(1.8.4)。你有你提到的问题的链接吗?我确实需要知道解析器在错误输入时的行为。我没有链接,但它可能在github页面的某个地方。我认为这不是同一个问题(如果有)。他们提到了TestRig树和插件显示的树之间的差异。当我在TestRig中尝试此语法时,树似乎与插件的匹配,但并不完全匹配,因为它不显示错误节点(
(parseExpression(expression primary))
)。所以我现在显然有两个工具告诉我我的解析树应该是不同的。