当前位置: 首页 > 面试题库 >

处理ANTLR4中的错误

索瀚海
2023-03-14
问题内容

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

第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书引用了一个多模式示例 https://github.com/stfairy/learn-antlr4/blob/master/tpantlr2-code/lexmagic/ModeTagsLexer.g4 https://github.com/stfairy/learn-antlr4/blob/master/tpantlr2-code/lexmagic/ModeTagsParser.

  • 问题内容: 我有一系列要解决的承诺 我继续继续诺言链。看起来像这样 我想添加一个catch语句来处理单个promise,以防万一出错,但是当我尝试时,返回它发现的第一个错误(忽略其余的),然后我无法从其余的promise中获取数据数组(没有错误)。 我尝试做类似.. 但这并不能解决。 谢谢! - 编辑: 下面的答案完全正确,但代码由于其他原因而中断。如果有人感兴趣,这就是我最终得到的解决方案… 节

  • 问题内容: 有没有一种方法来处理错误,比如,你可以在使用块,等等? 我已经在网上搜索过,发现的唯一选择是global变量,但是它没有按我预期的那样工作,例如,以下代码: 确实会以某种方式回滚,因为我在table1上更改的名称保留了我在此处进行测试时的旧值,但是它不会打印消息,也不会执行我在导致错误的指令之后放置的任何指令 有人可以帮我吗?您知道Sybase错误处理是如何工作的吗? 问题答案: 第一

  • 问题内容: jQuery的getScript函数似乎不支持错误回调函数。我不能在这里使用全局ajax错误处理代码,局部错误功能将是理想的选择。 回调获取data / textStatus的文档似乎不正确-回调均不获取。 关于如何检测到对getScript的调用失败的任何建议(例如,服务器不可用)? 编辑:仅查看源代码,似乎回调仅在成功时才调用,数据始终设置为null且未定义textStatus(因

  • Ansible 通常默认会确保检测模块和命令的返回码并且会快速失败 – 专注于一个错误除非你另作打算. 有时一条命令会返回 0 但那不是报错.有时命令不会总是报告它 ‘改变’ 了远程系统.本章节描述了 如何将 Ansible 处理输出结果和错误处理的默认行为改变成你想要的. 忽略错误的命令 New in version 0.6. 通常情况下, 当出现失败时 Ansible 会停止在宿主机上执行.有

  • 问题内容: 我正在使用Restify和Mongoose创建一个API ,而这两个都是我的新手。我似乎无法找出正确的方法来处理Mongoose / Node中的错误。 到目前为止,我正在尝试执行以下操作: 我正在尝试为此调用GET(针对不存在的用户)。而不是发送回简单的错误消息,而是导致整个节点应用程序失败。我对return next(err)的用户以及应该怎么做感到困惑。 任何帮助是极大的赞赏。