4

我正在为使用 ANTLR4 的某些语言开发一个小型 IDE,当词法分析器无法匹配错误字符时,我需要在错误字符下划线。在这种情况下,内置org.antlr.v4.runtime.ANTLRErrorListener实现会向 stderr 输出一条消息,类似于:

line 35:25 token recognition error at: 'foo\n'

我理解如何获取有关错误的行和列的信息(作为参数传递给syntaxError回调)没有问题,但是如何'foo\n'在回调中获取字符串?

当解析器是错误的来源时,它将违规标记作为syntaxError回调的第二个参数传递,因此提取有关错误输入的开始和停止偏移量的信息变得微不足道,这在参考书中也有说明。但是当源是词法分析器的情况下呢?在这种情况下,回调中的第二个参数为 null,可能是因为词法分析器未能形成标记。

我需要不匹配字符的长度来知道要下划线多少,但是在调试我的侦听器实现时,我无法在提供的回调参数中的任何地方找到此信息(除了通过字符串操作从提供的错误消息中提取它之外,这将只是错误的)。该'foo\n'字符串可能以某种方式清楚地获得,所以我错过了什么?

我怀疑我可能看错了地方,我应该考虑扩展DefaultErrorStrategy形成错误消息的地方。

4

1 回答 1

17

你应该编写你的词法分析器,使得语法错误是不可能的。在 ANTLR 4 中,只需添加以下内容作为词法分析器的最后一条规则,就很容易做到这一点:

ErrorChar : . ;

通过这样做,您的错误会从词法分析器转移到解析器。

在某些情况下,您可以采取其他步骤来帮助用户在您的 IDE 中编辑代码。例如,假设您的语言支持以下形式的双引号字符串,它不能跨越多行:

StringLiteral : '"' ~[\r\n"]* '"';

您可以使用以下规则对改进 IDE 中的错误报告:

StringLiteral : '"' ~[\r\n"]* '"';
UnterminatedStringLiteral : '"' ~[\r\n"]*;

然后,您可以覆盖该emit()方法以UnterminatedStringLiteral以特殊方式处理 。结果,用户看到了一个很大的错误消息,而解析器看到了StringLiteral它通常可以很好地处理的单个标记。

@Override
public Token emit() {
    switch (getType()) {
    case UnterminatedStringLiteral:
        setType(StringLiteral);
        Token result = super.emit();
        // you'll need to define this method
        reportError(result, "Unterminated string literal");
        return result;
    default:
        return super.emit();
    }
}
于 2013-09-14T02:43:52.600 回答