Поведение по умолчанию, когда парсер не знает, что делать, - это печатать сообщения на терминале, например:
строка 1:23 отсутствует DECIMAL at '}'
Это хорошее сообщение, но не в том месте. Я предпочел бы получить это как исключение.
Я пробовал использовать BailErrorStrategy
, но это вызывает ParseCancellationException
без сообщения (вызванного 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 теперь считается "продвинутым", так что, возможно, я странствую, но я не изучил, что "непереработанный" способ сделать это будет так как этот способ хорошо работает для наших нужд.