ANTLR 不会在无效输入上引发错误

2022-09-03 06:30:54

我正在使用ANTLR在我正在编写的Java工具中解析逻辑表达式,并且我遇到了问题,因为将无效的输入字符串传递给生成的ANTLR词法分析器和解析器不会导致任何异常。生成的文件不是像我预期的那样抛出RegnitionException,而是将错误消息打印到控制台并返回,就好像没有发生错误一样,导致我的程序在以后遇到空数据时崩溃。

我使用ANTLRWorks版本1.4.3来生成文件,似乎应该有某种选择来让它实际抛出错误而不是打印到控制台,但我没有找到任何东西。有谁知道如何让ANTLR实际抛出错误消息?我看到C#中的同一问题通过使用旧版本的ANTLR解决了,这就是我需要做的吗?

编辑:在巴特向我指出我正在寻找的方向后,我找到了这个页面

https://theantlrguy.atlassian.net/wiki/display/ANTLR3/Migrating+from+ANTLR+2+to+ANTLR+3

其“错误处理”部分的代码可以更准确地完成我想要的操作。要更改 ANTLR 捕获异常的方式,您可以在语法文件中说明:

@rulecatch {
   catch (RecognitionException e) {
    throw e;
   }
}

这会强制 ANTLR 引发异常,而不是处理和恢复异常。该部分中还有一些关于覆盖不匹配和恢复功能的内容,以确保引发所有可能的异常。


答案 1

一个简单的解决方法是覆盖您的词法分析器和解析器,并抛出您自己的异常,而不是让ANTLR尝试从不正确的语法/输入中恢复:reportError(...)

grammar YourGrammar;

// options/header/tokens

@parser::members {
  @Override
  public void reportError(RecognitionException e) {
    throw new RuntimeException("I quit!\n" + e.getMessage()); 
  }
}

@lexer::members {
  @Override
  public void reportError(RecognitionException e) {
    throw new RuntimeException("I quit!\n" + e.getMessage()); 
  }
}

// lexer & parser rules

有关错误报告(和恢复)的更多信息:https://theantlrguy.atlassian.net/wiki/display/ANTLR3/Error+reporting+and+recovery


答案 2

您应该按照此答案中的建议使用错误侦听器

但是,为了快速从 antlr3 迁移到 antlr4 / antlr v4,您可以使用它作为语法:

@parser::members 
{
  private final Logger log = LogManager.getLogger(this.getClass().getName());
  public java.util.HashMap<String, Double> memory = new java.util.HashMap<String, Double>();

  @Override
  public void notifyErrorListeners(Token offendingToken, String msg, RecognitionException ex)
  {
    throw new RuntimeException(msg); 
  }
}

@lexer::members 
{
  @Override
  public void recover(RecognitionException ex) 
  {
    throw new RuntimeException(ex.getMessage()); 
  }
}