#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-] ;