Разбор фрагментов строки в ANTLR4 - PullRequest
2 голосов
/ 14 февраля 2020

У меня есть грамматика, которая выражает инструкции для создания структур данных, включая текст, которые вложены в другие инструкции, выражающие, при каких обстоятельствах структуры данных должны быть созданы. Он обрабатывается с использованием посетителя, а не слушателя. Иногда текст может быть очень длинным, и для форматирования разделение его на строки облегчит чтение.

Например:

store(martin-luther-king,
      "The ultimate measure of a man is not where he stands in moments of comfort"
      " and convenience, but where he stands at times of challenge and controversy.")

легче читать, чем

   store(martin-luther-king,"The ultimate measure of a man is not
where he stands in moments of comfort and convenience, but where he
stands at times of challenge and controversy.")

Этот стиль разделения строк знаком Python кодировщикам. Для этого sh моя грамматика содержит:

quotedString : STRING+ ;
STRING : DOUBLEQUOTE (~["\\\r\n] | ('\\' .))+ DOUBLEQUOTE ;
WS : [ \t\r\n] -> skip;
fragment DOUBLEQUOTE : '"' ;

и в целом работает хорошо.

При синтаксическом анализе грамматики, которая случайно содержит что-то вроде:

"I did not" "" "speak out"

там, где ожидалось правило quotedString , лексирование / синтаксический анализ завершились с java .lang.ClassCastException сообщением «DocGenLexer не может быть приведен к org.antlr.v4.runtime.Parser». Я полагаю, что было бы более уместно, чтобы это не сработало, за исключением того, что сообщает «нет жизнеспособной альтернативы».

Мой код (после встраивания метода, для краткости) выглядит так:

    String docGen = "store(martin-luther-king,\"I did not\" \"\" \"speak out\")";
    DocGenLexer lexer = new DocGenLexer(CharStreams.fromString(docGen));
    lexer.removeErrorListeners();
    lexer.addErrorListener(DocGenErrorListener.INSTANCE);

    TokenStream tokenStream = new CommonTokenStream(lexer);

    DocGenParser parser = new DocGenParser(tokenStream);
    parser.removeErrorListeners();
    parser.addErrorListener(DocGenErrorListener.INSTANCE);

    ParseTree parseTree = parser.docGen();

Я хотел бы исправить это, и я изначально предполагал, что это представляет собой недостаток моей грамматики (а не ошибку в ANTLR4), но обнаружил, что проблема в классе слушателя ошибок.

Код для прослушивателя ошибок:

public class DocGenErrorListener extends BaseErrorListener {

    public static final DocGenErrorListener INSTANCE = new DocGenErrorListener();

    @Override
    public void syntaxError(Recognizer<?, ?> recognizer,
                            Object offendingSymbol,
                            int line, int charPositionInLine,
                            String msg,
                            RecognitionException e) throws ParseCancellationException {
        // the following line is the origin of the problem
        List<String> stack = ((Parser) recognizer).getRuleInvocationStack();
        Collections.reverse(stack);
        throw new DocGenParseException(
        String.format("rule stack: %s\nline %d:%d at %s: %s",
                stack, line, charPositionInLine, offendingSymbol, msg));
    }
}

Должен ли я заключить, что мне нужны другие классы прослушивателей ошибок для ошибок, генерируемых лексером и анализатором?

1 Ответ

0 голосов
/ 14 февраля 2020

Я вижу проблему. Ваша грамматика не допускает пустых строк.

"I did not" "" "speak out"

содержит строку с надписью "Я не сделал", пустую строку и строку с надписью "высказаться", вы должны изменить правило лексера на:

STRING : DOUBLEQUOTE (~["\\\r\n] | ('\\' .))* DOUBLEQUOTE ;
...