【问题标题】:ANTLR4 Lexer error reporting (length of offending characters)ANTLR4 Lexer 错误报告(违规字符的长度)
【发布时间】:2013-09-13 09:05:31
【问题描述】:

我正在使用 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 以形成错误消息。

【问题讨论】:

    标签: java error-handling antlr4


    【解决方案1】:

    你应该编写你的词法分析器,使得语法错误是不可能的。在 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();
        }
    }
    

    【讨论】:

    • 我实际上从其他解析器生成器中知道您的 ErrorChar 技巧,但出于某种原因,我的印象是 ANTLR4 Lexers 隐式执行此操作。哦,好吧.. 很好的答案,谢谢。
    • 我可能过早地将这个答案标记为对我的具体问题是正确的。虽然在我的词法分析器语法中添加ErrorChar 模式后的错误消息绝对是对前一个的改进,但我仍然无法在整个有问题的字符串下划线。只有它的第一个字符被制成一个令牌 - 让我遇到和以前一样的问题。我尝试将定义更改为ErrorChar : .+? ;,但没有成功。
    • 您需要遵循答案的“采取额外步骤”部分,该部分高度特定于特定的词法分析器。
    • 这需要我预测来自用户的非法输入的语法,不是吗?无论如何,除了你的建议之外,做this 可能会回答我关于如何获取违规字符串长度的问题,而不仅仅是它们开始出现的位置。只需确认即可。
    • 我能够使用基于此答案(以及我链接的答案)的解决方案来解决我的问题。谢谢。
    猜你喜欢
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 2019-10-29
    相关资源
    最近更新 更多