You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ANTLR解析不匹配输入无报错,如何触发异常或校验解析完整性?

问题描述

我正在使用ANTLR定义一门简单编程语言,目前仅支持在根级别定义方法,大幅简化后的语法如下:

grammar MyLang;
root: declaration* ;
declaration: Def ..<snip/snap>.. End;
Def: 'def';
End: 'end';
...

我的解析代码如下:

var charStream = CharStreams.fromString(s)
var lexer = new MyLangLexer(charStream);
var tokenStream = new CommonTokenStream(lexer);
var parser = new MyLangParser(tokenStream);
var rootContext = parser.root();
var astFactory = new Parser();
var declarations = astFactory.visitRoot(rootContext);

合法输入(如下方代码)可正常解析:

def foobar()
   command1
end
def bazz()
   command2
   command3
end

但提供非法输入时(例如省略def):

foobar()
   command1
end

程序无异常抛出,也无解析结果;若非法输入前有合法声明,解析会提前静默终止。请问如何让ANTLR在无法匹配解析规则时抛出异常,或获取最后成功解析的token以验证是否为EOF?

解决方案

1. 开启错误抛出机制

ANTLR默认会静默跳过无法匹配的输入,可通过设置解析器的错误策略,让它遇到语法错误直接抛出异常:

var parser = new MyLangParser(tokenStream);
// 替换默认错误处理,遇到错误立即终止并抛出异常
parser.setErrorHandler(new BailErrorStrategy());

此时解析过程中只要出现无法匹配的语法,就会抛出ParseCancellationException,你可以在代码中捕获该异常进行错误处理。

2. 验证解析是否到达输入末尾

若要确认解析是否完整处理了所有输入,可在解析完成后检查token流的当前位置:

var rootContext = parser.root();
// 检查解析结束后,token流是否指向EOF
if (tokenStream.LA(1) != Token.EOF) {
    Token unparsedToken = tokenStream.get(tokenStream.index());
    throw new RuntimeException("解析终止于非法输入:行" + unparsedToken.getLine() + ", 列" + unparsedToken.getCharPositionInLine());
}

这种方式能识别出解析提前终止、存在未处理输入的情况。

3. 自定义错误监听器

如果需要更精细的错误控制,可自定义ANTLRErrorListener捕获语法错误:

// 移除默认的控制台错误输出监听器
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("语法错误:行" + line + ", 列" + charPositionInLine + " - " + msg, e);
    }
});

该监听器会在每次语法错误发生时抛出异常,你可以根据需求自定义错误信息格式或处理逻辑。

内容的提问来源于stack exchange,提问作者Thomas S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 09:07:38