ANTLR4 Lexer错误报告(违规字符长度)

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

您应该编写词法分析器,以便无法进行语法错误。 在ANTLR 4中,只需添加以下作为词法分析器的最后一条规则即可轻松完成此操作:

 ErrorChar : . ; 

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

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

 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(); } }