ANTLR4从4.6升级至4.9.2后Lexer对非法输入未抛出运行时异常
ANTLR 4.6升级到4.7+版本后,词法和语法解析的默认错误恢复策略做了优化,默认会尝试跳过无效字符/自动修复错误继续解析,原有只给Lexer加错误监听器的配置就会失效,按以下步骤修改即可:
第一步:补全语法规则并添加兜底词法错误规则
你当前提供的语法规则存在缺失,包括空白符处理、字符串、数字、标识符及符号的词法规则,simpleFilter用到的value也没有定义,需要先补全规则,同时在所有词法规则的末尾添加兜底错误规则,确保所有无法匹配的字符都会触发错误:
grammar Filter; start : appfilter ; appfilter : LBRACE appfilter RBRACE | negate LBRACE appfilter RBRACE | appfilter logical appfilter | simpleFilter | complexFilter ; complexFilter : key LSQBRACE appfilter RSQBRACE | key LSQBRACE appfilter RSQBRACE DOT_SEPARATOR simpleFilter ; simpleFilter : key binary value | key unary ; key : PATH | ATTRIBUTE ; // 补充value规则 value : STRING | NUMBER; binary : EQ; unary : PR; logical : AND | OR; negate : NOT; // 原有词法规则 EQ : 'eq' | 'EQ' | 'Eq' | 'eQ'; PR : 'pr' | 'PR' | 'Pr' | 'pR'; NOT : 'not'; AND : 'and'; OR : 'or'; LBRACE : '('; RBRACE : ')'; LSQBRACE : '['; RSQBRACE : ']'; DOT_SEPARATOR : '.'; // 新增必备词法规则,可根据业务需求调整 WS : [ \t\r\n]+ -> skip; // 跳过空白符 STRING : '"' (~["\\] | '\\' .)* '"'; NUMBER : [0-9]+; PATH : [a-z]+ ('.' [a-z]+)*; ATTRIBUTE : '@' [a-z]+; // 兜底错误规则,必须放在所有词法规则最后,优先级最低,匹配所有未被前面规则匹配的字符 ERROR_TOKEN : . ;
第二步:统一配置Lexer和Parser的错误处理逻辑
默认ANTLR的Lexer和Parser都会自带一个仅打印日志的ConsoleErrorListener,你需要先移除默认监听器,再添加自定义的抛异常监听器,同时替换Parser的默认错误恢复策略,禁止自动修复错误:
// 1. 配置Lexer错误处理 lexer.removeErrorListeners(); // 移除默认的控制台打印监听器 lexer.addErrorListener(new BaseErrorListener() { @Override public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { throw new RuntimeException(String.format("词法错误,位置%d:%d,错误信息:%s", line, charPositionInLine, msg), e); } }); CommonTokenStream tokens = new CommonTokenStream(lexer); FilterParser parser = new FilterParser(tokens); // 2. 配置Parser错误处理 parser.removeErrorListeners(); // 同样移除Parser的默认监听器 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("语法错误,位置%d:%d,错误信息:%s", line, charPositionInLine, msg), e); } }); // 替换错误恢复策略,遇到错误直接终止,不尝试自动修复 parser.setErrorHandler(new BailErrorStrategy()); // 执行解析 parser.start();
修改完成后再测试输入title eq "Emplyee" 1234,会直接抛出对应的运行时异常,不会再被自动恢复跳过。
内容的提问来源于stack exchange,提问作者user2986469
相关产品推荐
相关产品推荐

