如何配置ANTLR4跳过SQL解析错误,继续解析后续有效语句?
解决ANTLR4解析SQL时跳过错误语句的方案
要解决错误SQL导致后续语句无法解析的问题,需结合自定义错误监听器和语法文件容错修改,两者缺一不可,具体操作如下:
一、自定义错误监听器,避免解析终止
ANTLR4默认的错误监听器遇到语法错误时会抛出异常或终止解析流程,因此需要自定义监听器捕获错误并触发错误恢复:
- 实现
BaseErrorListener,覆盖syntaxError方法:
public class SkipErrorListener extends BaseErrorListener { @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { // 记录错误信息,可根据需求调整日志输出 System.err.printf("语法错误:第%d行第%d列 - %s%n", line, charPositionInLine, msg); // 触发解析器的错误恢复机制,避免终止 if (recognizer instanceof Parser parser) { parser.getErrorHandler().recovery(parser, e); // 强制同步到下一个合法语句的起始点 parser.getErrorHandler().sync(parser); } } }
- 在解析流程中替换默认监听器:
// 假设已生成SQLLexer和SQLParser SQLLexer lexer = new SQLLexer(CharStreams.fromString(sqlContent)); CommonTokenStream tokens = new CommonTokenStream(lexer); SQLParser parser = new SQLParser(tokens); // 移除默认错误监听器,添加自定义实现 parser.removeErrorListeners(); parser.addErrorListener(new SkipErrorListener()); // 执行解析 parser.sqlStatements();
二、修改语法文件,添加错误同步规则
仅靠错误监听器无法让解析器准确定位后续有效语句的起始点,需在语法文件中添加同步规则,明确跳过错误内容的边界(比如SQL语句常用的分号、语句起始关键字)。
以MySQL语法为例,修改顶层规则和添加错误恢复规则:
grammar MySQL; // 顶层规则:允许合法语句或错误恢复语句重复 sqlStatements : (sqlStatement | errorRecovery)* EOF ; // 合法SQL语句规则(示例) sqlStatement : selectStatement | setStatement | otherStatements... ; // 错误恢复规则:跳过错误内容直到分号或下一个语句起始关键字 errorRecovery : UNEXPECTED_TOKEN+ (SEMI | SELECT | SET | EOF)? ; // 定义通配符Token,需放在所有规则最后 UNEXPECTED_TOKEN : . ; // 其他原有规则(示例) selectStatement : 'SELECT' .*? SEMI ; setStatement : 'SET' .*? SEMI ; SEMI : ';' ; SELECT : 'SELECT' ; SET : 'SET' ; // ... 其他关键字和Token规则
关键说明:
UNEXPECTED_TOKEN通配符必须放在语法文件的最后,避免匹配到合法Token;errorRecovery规则指定跳过错误内容直到分号(SEMI)、特定语句起始关键字(SELECT/SET)或文件结束(EOF),确保解析器能快速定位到下一个有效语句;- 若原有语法中已定义语句规则,需确保每个语句规则前隐含同步逻辑(比如先跳过多余分号)。
三、效果验证
针对你提供的示例SQL:
SELECT SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;
解析流程会:
- 捕获第一条不完整
SELECT的语法错误并记录; - 触发错误恢复,跳过错误内容直到遇到
SET关键字; - 正常解析后续两条
SET语句。
内容的提问来源于stack exchange,提问作者star
相关产品推荐
相关产品推荐

