ANTLR4解析期间发生StackOverflowError

问题描述

输入: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的转义符,但据我了解,没有必要逃脱斜线。

关于语法的一般评论也值得赞赏,这是我的第一个

有什么想法吗?

解决方法

问题出在设置范围运算符(又名“破折号”)上。要将范围运算符包括为文字,您必须对其进行转义

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

或将其指定为集合中的最后一个成员项。

DATE_VALUE  :  [0-9-]+ ;