处理ANTLR4中的错误

解析器不知道要做什么时的默认行为是将消息打印到终端,例如:

第1:23行在“}”处缺少DECIMAL

这是一个很好的信息,但是在错误的位置。我宁愿将此作为例外。

我尝试使用BailErrorStrategy,但是会抛出一个ParseCancellationException没有消息的消息(由引起InputMismatchException,也没有消息)。

有什么办法可以让我通过异常报告错误,同时又保留消息中的有用信息?


这就是我真正想要的—我通常在规则中使用动作来构建对象:

dataspec returns [DataExtractor extractor]

@init {

DataExtractorBuilder builder = new DataExtractorBuilder(layout);

}

@after {

$extractor = builder.create();

}

: first=expr { builder.addAll($first.values); } (COMMA next=expr { builder.addAll($next.values); })* EOF

;

expr returns [List<ValueExtractor> values]

: a=atom { $values = Arrays.asList($a.val); }

| fields=fieldrange { $values = values($fields.fields); }

| '%' { $values = null; }

| ASTERISK { $values = values(layout); }

;

然后,当我调用解析器时,我将执行以下操作:

public static DataExtractor create(String dataspec) {

CharStream stream = new ANTLRInputStream(dataspec);

DataSpecificationLexer lexer = new DataSpecificationLexer(stream);

CommonTokenStream tokens = new CommonTokenStream(lexer);

DataSpecificationParser parser = new DataSpecificationParser(tokens);

return parser.dataspec().extractor;

}

我真正想要的是

  • dataspec()当无法解析输入时调用引发异常(理想情况下为已检查的异常)的调用
  • 使该异常具有有用的消息并提供对发现问题所在的行号和位置的访问

然后,我将让该异常在调用堆栈中冒泡,使其到达最适合向用户呈现有用消息的位置,就像我处理断开的网络连接,读取损坏的文件等的方法一样。

我确实看到ANTLR4中的动作现在被认为是“高级”的,所以也许我正在以一种奇怪的方式来处理事情,但是自从这种方式以来,我没有研究过“非高级”方式是什么。一直很好地满足我们的需求。

回答:

由于我对现有的两个答案有些挣扎,所以我想分享一下最终得到的解决方案。

首先,我像SamHarwell建议的那样创建了自己的ErrorListener版本:

public class ThrowingErrorListener extends BaseErrorListener {

public static final ThrowingErrorListener INSTANCE = new ThrowingErrorListener();

@Override

public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e)

throws ParseCancellationException {

throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg);

}

}

请注意使用aParseCancellationException而不是a,RecognitionException因为DefaultErrorStrategy会捕获后者,并且永远不会到达您自己的代码。

建议不要像BradMace一样创建一个全新的ErrorStrategy,因为DefaultErrorStrategy默认情况下会产生非常好的错误消息。

然后,我在解析函数中使用自定义的ErrorListener:

public static String parse(String text) throws ParseCancellationException {

MyLexer lexer = new MyLexer(new ANTLRInputStream(text));

lexer.removeErrorListeners();

lexer.addErrorListener(ThrowingErrorListener.INSTANCE);

CommonTokenStream tokens = new CommonTokenStream(lexer);

MyParser parser = new MyParser(tokens);

parser.removeErrorListeners();

parser.addErrorListener(ThrowingErrorListener.INSTANCE);

ParserRuleContext tree = parser.expr();

MyParseRules extractor = new MyParseRules();

return extractor.visit(tree);

}

这将为您提供与默认情况下打印到控制台相同的错误消息,只是形式为适当的异常。

以上是 处理ANTLR4中的错误 的全部内容, 来源链接: utcz.com/qa/429580.html

回到顶部