Ошибка стекового потока во время синтаксического анализа ANTLR4

#antlr4

#antlr4

Вопрос:

Ввод: toAccount = 'Electricity/Water' грамматика:

 grammar FQL;

/*
 * Parser rules
 */

query
                :       (orExpression | orderByExpression EOF)* ;
orExpression
                :       andExpression (OR andExpression)* ;
andExpression
                :       expression (AND expression)* ;
expression
                :       (regularExpression | betweenExpression | periodExpression)
                        | parenthesisExpression ;
parenthesisExpression
                :       L_PAREN expr=orExpression R_PAREN ;

orderByExpression
                :       ORDER_BY field=IDENTIFIER order=(DESC | ASC ) ;

// regular expressions - NOT regex
regularExpression
                :       (stringExpression | intExpression | booleanExpression | dateExpression) ;
stringExpression
                :       field=IDENTIFIER operator=STRING_OPERATOR value=STRING_VALUE ;
intExpression
                :       field=IDENTIFIER operator=(INT_OPERATOR | STRING_OPERATOR) value=INT_VALUE ;

booleanExpression
                :       field=IDENTIFIER operator=STRING_OPERATOR value=(TRUE | FALSE) ;
dateExpression
                :       field=IDENTIFIER operator=STRING_OPERATOR value=DATE_VALUE ;

// BETWEEN expressions
betweenExpression
                :       (betweenStringExpression | betweenIntExpression ) ;
betweenStringExpression
                :       field=IDENTIFIER BETWEEN left=STRING_VALUE AND right=STRING_VALUE ;
betweenIntExpression
                :       field=IDENTIFIER BETWEEN left=INT_VALUE AND right=INT_VALUE ;

// period expressions
periodExpression
                :       periodConstExpression ;
periodConstExpression
                :       field=IDENTIFIER operator=STRING_OPERATOR value=(CURRENT |
                                                                         LAST |
                                                                         CURRENT_YEAR |
                                                                         LAST_YEAR |
                                                                         GRAND_TOTAL) ;

/*
 * Lexer rules
 */

fragment B      :       ('B' | 'b') ;
fragment E      :       ('E' | 'e') ;
fragment T      :       ('T' | 't') ;
fragment W      :       ('W' | 'w') ;
fragment N      :       ('N' | 'n') ;
fragment A      :       ('A' | 'a') ;
fragment D      :       ('D' | 'd') ;
fragment C      :       ('C' | 'c') ;
fragment U      :       ('U' | 'u') ;
fragment R      :       ('R' | 'r') ;
fragment L      :       ('L' | 'l') ;
fragment S      :       ('S' | 's') ;
fragment Y      :       ('Y' | 'y') ;
fragment G      :       ('G' | 'g') ;
fragment O      :       ('O' | 'o') ;
fragment F      :       ('F' | 'f') ;
fragment SPACE  :       ' ' ;

// Keywords
BETWEEN         :       B E T W E E N ;
AND             :       A N D ;
OR              :       O R ;
ORDER_BY        :       O R D E R SPACE B Y ;
DESC            :       D E S C ;
ASC             :       A S C ;
TRUE            :       T R U E ;
FALSE           :       F A L S E ;

// Constant values
CURRENT         :       C U R R E N T ;
LAST            :       L A S T ;
YEAR            :       Y E A R ;
GRAND_TOTAL     :       G R A N D '_' T O T A L ;
CURRENT_YEAR    :       CURRENT '_' YEAR ;
LAST_YEAR       :       LAST '_' YEAR ;

STRING_OPERATOR :       '=' ;
INT_OPERATOR    :       '>' | '<' | '>=' | '<=' | '!=' ;
L_PAREN         :       '(' ;
R_PAREN         :       ')' ;
IDENTIFIER      :       [a-zA-Z]  ;
INT_VALUE       :       [0-9]  ;
STRING_VALUE    :       ''' [a-zA-Z0-9-/ ]  ''' ;
DATE_VALUE      :       [0-9-]  ;

NEWLINE         :       ('r'? 'n' | 'r')  ;
WHITESPACE      :       ' ' -> skip;
  

Выдает исключение:

 java.lang.StackOverflowError: null
    at org.antlr.v4.runtime.misc.Array2DHashSet.getBucket(Array2DHashSet.java:108) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
    at org.antlr.v4.runtime.misc.Array2DHashSet.getOrAddImpl(Array2DHashSet.java:63) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
    at org.antlr.v4.runtime.misc.Array2DHashSet.getOrAdd(Array2DHashSet.java:59) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
    at org.antlr.v4.runtime.atn.ATNConfigSet.add(ATNConfigSet.java:146) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
    at org.antlr.v4.runtime.atn.ATNConfigSet.add(ATNConfigSet.java:122) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
    at org.antlr.v4.runtime.atn.LexerATNSimulator.closure(LexerATNSimulator.java:446) ~[antlr4-runtime-4.8-1.jar!/:4.8-1]
  

Я предполагаю, что это как-то связано с / в STRING_VALUE , поскольку без него выражение может быть успешно проанализировано. Я пытался отладить его, но я не понимаю, что происходит под капотом в ANTLR. Я также искал в Google экранирование в ANTLR, но, насколько я понимаю, нет необходимости экранировать косую черту.

Также приветствуются общие замечания относительно грамматики, это мой первый.

Есть идеи?

Ответ №1:

Проблема связана с оператором set range, он же ‘dash’. Чтобы включить оператор диапазона в качестве литерала, вы должны либо экранировать его

 STRING_VALUE: ''' [a-zA-Z0-9-/ ]  ''' ;
  

или укажите его как последний элемент элемента в наборе.

 DATE_VALUE  :  [0-9-]  ;