【问题标题】:Forcing a syntax error in Antlr4在 Antlr4 中强制出现语法错误
【发布时间】:2018-06-17 21:41:57
【问题描述】:

我已经搜索了好几个小时,试图弄清楚如何在 Antlr4 侦听器中手动创建语法错误。有可能吗?

我创建了一个运行良好的语法,它的一部分看起来像:

variableExp returns [ BigDecimal value ]
  : VARIABLE_PREFIX n = VARIABLE_NAME 
  ;

其中 VARIABLE_PREFIX 是类似“$”的字符。

我正在使用侦听器,在 exitVariableExp() 上,我根据解析器外部的信息设置值(并且它是用户输入的,因此我无法将其放入解析器):

  @Override 
  public void exitVariableExp(ExpressionsParser.VariableExpContext ctx) 
  { 
    System.out.println("In exitVariableExp()");
    ctx.value = lookupVariable(ctx.getText());
  }

我遇到的问题是用户几乎可以键入任何不是变量的内容(例如 $jfjhfjfj),并且解析器会接受。我想在此侦听器成员中创建语法错误,因为我有一个错误侦听器,它存储语法错误位置以向用户显示:

@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object   offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) throws ParseCancellationException 
  {
    System.out.println("Got syntax error.");
    errorLine = line;
    errorColumn = charPositionInLine;
    errorMessage = msg;
  }

但我不知道该怎么做。也许这是错误的方法?

【问题讨论】:

  • 如果一个变量必须以$ 开头,你就不能使用你知道的东西吗?
  • 严格来说,这不是语法错误。语法由您的语法定义。所以只要代码遵守语法,就不会有语法错误。这可能是让您在搜索中望而却步的原因,因为实际上您想要实现运行时或域错误,具体取决于您正在构建的内容。
  • 我同意这对解析器来说不是语法错误,但在一般意义上它是给用户的。这是否意味着您无法从侦听器中生成语法错误?
  • @ScottHunter 我不确定你在问什么。我正在解析用户输入的输入,它会有错误(错误的变量名),我想捕捉它——最好使用我已经拥有的错误处理机制。
  • 为什么$jfjhfjfj不是变量名?英文字母部分不是单词,但是很多变量名不是单词。是什么导致了这个错误?

标签: java antlr4


【解决方案1】:

尝试解析器在遇到语法错误时正在执行的操作:它会抛出 RecognitionException。您可以在侦听器中执行此操作,异常处理会小心并报告错误(并尝试恢复)。如果您不喜欢恢复机制并想完全停止解析,则需要做更多的工作。在这种情况下,您应该抛出与RecognitionException 不同的异常(因为它在所有解析器函数中都被捕获)。 BailErrorStrategy 使用这种方法尽快停止解析(这有利于快速语法检查)。看看那里如何覆盖一些标准行为。

【讨论】:

  • 我试图这样做,但我不知道如何为第一个参数(识别器,?>)传递异常。我正在使用 BallErrorStrategy。
  • 只需传入你的解析器实例。
【解决方案2】:

在执行tree-walker时,解析器已经运行完成,所以解析器的语法错误报告机制不可用。

更好的是,只依赖解析树节点,因为它将包含报告错误所需的所有信息。

private static final String msg = "Syntax error: '%s' is not a valid var (at %s:%s).";

@Override 
public void exitVariableExp(VariableExpContext ctx) { 
    String value = lookupVariable(ctx.getText());
    if (value == null || value.isEmpty()) {
        Token tok = ctx.VARIABLE_NAME.getSymbol();
        int line = tok.getLine();              // 1..n
        int col = tok.getCharPositionInLine(); // 0..n
        System.out.println(String.format(msg, tok.getText(), line, col));            
    }
}

【讨论】:

  • 谢谢,这是有道理的。如何阻止树行走?我尝试了解析取消异常,但无济于事。
  • 再次,解析器已运行,因此解析取消将不起作用。只需将ParseTreeWalker#walk 调用包装在try..catch 中,然后在您想停止的地方抛出Exception。不过最好不要停止,同时报告所有错误。
  • 有趣,我没有调用 ParseTreeWalker#walk。我确实得到了大约六次查找,因此单个错误出现异常(例如解析“@jfjfjfjfj”)。这就是为什么我想停下脚步。我会假设它被解析器调用...
  • 尝试解析两个字符 ($h) 也很有趣(令人沮丧),我的侦听器方法 exitVariableExp() 被调用了六次。为什么两个令牌会被调用六次?我每次都会引发 RuntimeException。
  • 我将不得不开发和示例,现在它有很多很多行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-15
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
相关资源
最近更新 更多