Путаница в грамматике Antlr: не сообщать об ошибках, когда выдается явная ошибка - PullRequest
0 голосов
/ 29 мая 2020

Я пытаюсь создать простой язык запросов, как показано ниже

grammar FilterExpression;


// Lexer rules

AND : 'AND' ;
OR  : 'OR' ;
NOT : 'NOT';

GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
EQ : '=' ;

DECIMAL    : '-'?[0-9]+('.'[0-9]+)? ;
KEY       : ~[ \t\r\n\\"~=<>:(),]+ ;
QUOTED_WORD: ["] ('\\"' | ~["])* ["] ;
NEWLINE    : '\r'? '\n';
WS         : [ \t\r\n]+ -> skip ;



StringFilter   : KEY ':' QUOTED_WORD;
NumericalFilter  : KEY (GT | GE | LT | LE | EQ) DECIMAL;

condition      : StringFilter                                # stringCondition
               | NumericalFilter                             # numericalCondition
               | StringFilter op=(AND|OR) StringFilter       # combinedStringCondition
               | NumericalFilter op=(AND|OR) NumericalFilter # combinedNumericalCondition
               | condition AND condition                     # combinedCondition
               | '(' condition ')'                           # parens
               ;

Я добавил несколько тестов и хотел бы проверить, работают ли они должным образом. К моему удивлению, некоторые случаи, которые должны быть явно неправильными, прошли

Например, когда я набираю

(brand:"apple" AND t>3) 1>3

, где 1>3 намеренно помещается как ошибка. Однако кажется, что Antlr по-прежнему успешно генерирует дерево, которое выглядит так: enter image description here

Это потому, что моя грамматика имеет некоторые проблемы, которых я не осознавал?

Я также пробовал использовать плагин IntelliJ (потому что думал, что grun может вести себя не так, как ожидалось), но он дает

Тестовый код, который я использую. Обратите внимание: я также пытался использовать BailErrorStrategy, но это, похоже, не помогает

public class ParserTest {
  private class BailLexer extends FilterExpressionLexer {
    public BailLexer(CharStream input) {
      super(input);
    }
    public void recover(LexerNoViableAltException e) {
      throw new RuntimeException(e);
    }
  }


  private FilterExpressionParser createParser(String filterString) {
    //FilterExpressionLexer lexer = new FilterExpressionLexer(CharStreams.fromString(filterString));
    FilterExpressionLexer lexer = new BailLexer(CharStreams.fromString(filterString));
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    FilterExpressionParser parser = new FilterExpressionParser(tokens);

    parser.setErrorHandler(new BailErrorStrategy());
    parser.addErrorListener(new ANTLRErrorListener() {
      @Override
      public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
        System.out.print("here1");
      }

      @Override
      public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
        System.out.print("here2");

      }

      @Override
      public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
        System.out.print("here3");

      }

      @Override
      public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {

        System.out.print("here4");
      }
    });

    return parser;
  }

  @Test
  public void test() {
    FilterExpressionParser parser = createParser("(brand:\"apple\" AND t>3) 1>3");
    parser.condition();
  }

}

1 Ответ

1 голос
/ 29 мая 2020

Похоже, я наконец нашел ответ.

Причина в грамматике, которую я не предоставил EOF. И, очевидно, в ANTLR совершенно нормально разбирать синтаксис prefix os. поэтому остальная часть тестовой строки

(brand:"apple" AND t>3) 1>3 т.е. 1>3 разрешена.

См. Обсуждение здесь: https://github.com/antlr/antlr4/issues/351

Затем я немного изменил грамматику, чтобы добавить EOF в конце синтаксиса condition EOF все работает

...