Antlr 4.6.1处理含特殊字符输入时未生成ErrorNode且不报错
问题分析与解决方案
你的问题核心有两个:一是解析时未强制执行完整输入校验,二是错误监听机制未正确配置,导致非法字符输入时没有触发预期的错误提示。
关键问题点
- 规则调用错误:如果你的代码中调用的是
parser.expr()而非parser.equation(),解析器只会匹配到第一个合法表达式(比如123)就停止,不会检查后续的@abc字符——因为expr规则没有要求输入必须结束(缺少EOF约束)。 - 错误监听未正确配置:默认的ANTLR错误监听器不会主动抛出异常,需要你自定义并注册错误监听器来捕获语法/词法错误。
- ERRORCHAR规则的影响:当前的
ERRORCHAR : . ;会将所有未识别字符转为合法的词法符号,导致词法阶段不会报错,需要在解析阶段处理这些非法符号,或者移除该规则让词法阶段直接报错。
具体修复步骤
1. 确保调用正确的入口规则
在你的代码中,必须调用equation()作为解析入口,而非expr(),这样才能触发EOF校验,确保整个输入都符合表达式规则:
// 正确写法 ParseTree tree = parser.equation(); // 错误写法(会忽略后续非法字符) // ParseTree tree = parser.expr();
2. 配置自定义错误监听器
移除ANTLR默认的错误监听器,添加自定义监听器来捕获错误并抛出异常:
CellMathLexer lexer = new CellMathLexer(CharStreams.fromString(input)); CommonTokenStream tokenStream = new CommonTokenStream(lexer); CellMathParser parser = new CellMathParser(tokenStream); // 移除默认错误监听器,避免默认的静默处理 parser.removeErrorListeners(); // 添加自定义错误监听器,遇到错误直接抛出异常 parser.addErrorListener(new BaseErrorListener() { @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { throw new RuntimeException(String.format("解析错误:%s,位置:行%d,列%d", msg, line, charPositionInLine), e); } });
3. 处理ErrorNode(Listener模式)
如果你使用Listener模式,需要重写visitErrorNode方法来处理解析过程中生成的错误节点:
class CustomCellMathListener extends CellMathBaseListener { @Override public void visitErrorNode(ErrorNode node) { throw new RuntimeException("发现非法字符:" + node.getText()); } } // 使用自定义监听器 CustomCellMathListener listener = new CustomCellMathListener(); ParseTreeWalker.DEFAULT.walk(listener, parser.equation());
4. 可选:移除ERRORCHAR规则(词法阶段报错)
如果你希望在词法阶段就拦截非法字符(而不是生成ERRORCHAR符号),可以删除语法中的ERRORCHAR : . ;规则。这样当遇到@、&这类未定义的字符时,词法分析器会直接触发错误,被你的自定义ErrorListener捕获。
验证效果
当输入123@abc时,调用parser.equation()会触发语法错误,提示“mismatched input '@' expecting
内容的提问来源于stack exchange,提问作者Hemanth Desu
相关产品推荐
相关产品推荐

