解析器不知道该做什么时的默认行为是将消息打印到终端,例如:
第 1:23 行在 '}' 处缺少 DECIMAL
这是一个好消息,但在错误的地方。我宁愿将此作为例外。
我试过使用BailErrorStrategy,但这会抛出ParseCancellationException没有消息的 a (由 a 引起InputMismatchException,也没有消息)。
有没有办法让它通过异常报告错误,同时保留消息中的有用信息?
这就是我真正想要的——我通常在规则中使用动作来构建一个对象:
dataspec returns [DataExtractor extractor]
    @init {
        DataExtractorBuilder builder = new DataExtractorBuilder(layout);
    }
    @after {
        $extractor = builder.create();
    }
    : first=expr { builder.addAll($first.values); } (COMMA next=expr { builder.addAll($next.values); })* EOF
    ;
expr returns [List<ValueExtractor> values]
    : a=atom { $values = Arrays.asList($a.val); }
    | fields=fieldrange { $values = values($fields.fields); }
    | '%' { $values = null; }
    | ASTERISK { $values = values(layout); }
    ;
然后,当我调用解析器时,我会执行以下操作:
public static DataExtractor create(String dataspec) {
    CharStream stream = new ANTLRInputStream(dataspec);
    DataSpecificationLexer lexer = new DataSpecificationLexer(stream);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    DataSpecificationParser parser = new DataSpecificationParser(tokens);
    return parser.dataspec().extractor;
}
我真正想要的是
- 用于在dataspec()无法解析输入时引发异常(理想情况下是已检查异常)的调用
- 使该异常具有有用的消息并提供对发现问题的行号和位置的访问
然后我会让这个异常在调用堆栈中冒泡到最适合向用户呈现有用消息的地方——就像我处理断开的网络连接、读取损坏的文件等一样。
我确实看到动作现在在 ANTLR4 中被认为是“高级”的,所以也许我会以一种奇怪的方式处理事情,但我还没有研究过这样做的“非高级”方式是什么,因为这种方式一直很好地满足我们的需求。