ANTLR4语法表现很差

时间:2017-04-19 15:32:59

标签: antlr antlr4

鉴于下面的语法,我在解析更长的字符串时看到的性能非常差,大约为秒。 (这在Python和Go实现上都有)这个语法中有什么东西导致了这个吗?

示例输出:

WHILE @@FETCH_STATUS = 0

BEGIN

    SET @DropTemp = 'DROP LOGIN tempIMPLUser' + @RandomChar
    print @droptemp
        --EXEC sp_executesql @DropTemp
    FETCH NEXT FROM RandomChar_Cursor INTO @RandomChar

END

这是关于Python的......尽管我不希望表现出惊人的性能,但我希望任何输入都能达到亚秒级。我做错了什么?

0.000061s LEXING "hello world"
0.014349s PARSING "hello world"
0.000052s LEXING 5 + 10
0.015384s PARSING 5 + 10
0.000061s LEXING FIRST_WORD(WORD_SLICE(contact.blerg, 2, 4))
0.634113s PARSING FIRST_WORD(WORD_SLICE(contact.blerg, 2, 4))
0.000095s LEXING (DATEDIF(DATEVALUE("01-01-1970"), date.now, "D") * 24 * 60 * 60) + ((((HOUR(date.now)+7) * 60) + MINUTE(date.now)) * 60))
1.552758s PARSING (DATEDIF(DATEVALUE("01-01-1970"), date.now, "D") * 24 * 60 * 60) + ((((HOUR(date.now)+7) * 60) + MINUTE(date.now)) * 60))

2 个答案:

答案 0 :(得分:2)

似乎这种性能是由于加法/乘法等运算符中使用的左递归所致。将这些重写为二进制规则会产生即时性能。 (见下文)

grammar Excellent;

COMMA      : ',';
LPAREN     : '(';
RPAREN     : ')';
LBRACK     : '[';
RBRACK     : ']';

DOT        : '.';

PLUS       : '+';
MINUS      : '-';
TIMES      : '*';
DIVIDE     : '/';
EXPONENT   : '^';

EQ         : '=';
NEQ        : '!=';

LTE        : '<=';
LT         : '<';
GTE        : '>=';
GT         : '>';

AMPERSAND  : '&';

DECIMAL    : [0-9]+('.'[0-9]+)?;
STRING     : '"' (~["] | '""')* '"';

TRUE       : [Tt][Rr][Uu][Ee];
FALSE      : [Ff][Aa][Ll][Ss][Ee];

NAME       : [a-zA-Z][a-zA-Z0-9_.]*;    // variable names, e.g. contact.name or function names, e.g. SUM

WS         : [ \t\n\r]+ -> skip;        // ignore whitespace

ERROR      : . ;

parse      : expression EOF;

atom       : fnname LPAREN parameters? RPAREN             # functionCall
           | atom DOT atom                                # dotLookup
           | atom LBRACK expression RBRACK                # arrayLookup
           | NAME                                         # contextReference
           | STRING                                       # stringLiteral
           | DECIMAL                                      # decimalLiteral
           | TRUE                                         # true
           | FALSE                                        # false
           ;

expression : atom                                         # atomReference
           | MINUS expression                             # negation
           | expression EXPONENT expression               # exponentExpression
           | expression (TIMES | DIVIDE) expression       # multiplicationOrDivisionExpression
           | expression (PLUS | MINUS) expression         # additionOrSubtractionExpression
           | expression (LTE | LT | GTE | GT) expression  # comparisonExpression
           | expression (EQ | NEQ) expression             # equalityExpression
           | expression AMPERSAND expression              # concatenation
           | LPAREN expression RPAREN                     # parentheses
           ;

fnname     : NAME
           | TRUE
           | FALSE
           ;

parameters : expression (COMMA expression)*               # functionParameters
           ;

答案 1 :(得分:0)

您可以随时尝试使用SLL(*)进行解析,只有在失败时才需要使用LL(*)进行解析(这是默认设置)。

请参阅ANTLR的GitHub上的this票据以获得进一步的解释,here是使用此策略的实现。

这种方法可以在解析语法正确的输入时节省(大量)时间。