是什么导致Antlr创建一个导致内存不足的大型令牌流

时间:2013-05-02 07:53:41

标签: java antlr3

我们的一个Web应用程序常常因为内存不足而死亡。我们从内存转储中收集的稀疏数据表明我们的antlr解析实现存在问题。我们看到的是一个包含超过一百万个项目的antlr令牌流。导致这种情况的输入文本尚未找到。

这是否有可能与零宽度项目相匹配? 语法中是否会出现另一个导致内存使用过多的问题?

以下是我们使用的当前语法:

grammar AdvancedQueries;

options {
  language = Java;
  output = AST;
  ASTLabelType=CommonTree;
}

tokens {
FOR;
END;
FIELDSEARCH;
TARGETFIELD;
RELATION;
NOTNODE;
ANDNODE;
NEARDISTANCE;
OUTOFPLACE;
}

@header {
package de.bsmo.fast.parsing;
}

@lexer::header {
package de.bsmo.fast.parsing;
}

startExpression  : orEx;

expressionLevel4    
: LPARENTHESIS! orEx RPARENTHESIS! | atomicExpression | outofplace;

expressionLevel3    
: (fieldExpression) | expressionLevel4 ;

expressionLevel2    
: (nearExpression) | expressionLevel3 ;

expressionLevel1    
: (countExpression) | expressionLevel2 ;


notEx   : NOT^? a=expressionLevel1 ;

andEx   : (notEx        -> notEx)
(AND? a=notEx -> ^(ANDNODE $andEx $a))*;

orEx    : andEx (OR^  andEx)*;

countExpression  : COUNT LPARENTHESIS countSub RPARENTHESIS RELATION NUMBERS -> ^(COUNT countSub RELATION NUMBERS);

countSub 
    :   orEx;

nearExpression  : NEAR LPARENTHESIS (WORD|PHRASE) MULTIPLESEPERATOR (WORD|PHRASE) MULTIPLESEPERATOR NUMBERS RPARENTHESIS -> ^(NEAR WORD* PHRASE* ^(NEARDISTANCE NUMBERS));

fieldExpression : WORD PROPERTYSEPERATOR fieldSub  -> ^(FIELDSEARCH ^(TARGETFIELD WORD) fieldSub );

fieldSub 
    :   WORD | PHRASE | LPARENTHESIS! orEx RPARENTHESIS!;  

atomicExpression 
: WORD
| PHRASE
| NUMBERS
;

//Out of place are elements captured that may be in the parseable input but need to be ommited from output later
//Those unwanted elements are captured here.
//MULTIPLESEPERATOR capture unwanted "," 
outofplace
: MULTIPLESEPERATOR -> ^(OUTOFPLACE ^(MULTIPLESEPERATOR));

fragment NUMBER : ('0'..'9');
fragment CHARACTER : ('a'..'z'|'A'..'Z'|'0'..'9'|'*'|'?');
fragment QUOTE     : ('"');
fragment LESSTHEN : '<';
fragment MORETHEN: '>';
fragment EQUAL: '=';
fragment SPACE     : ('\u0009'|'\u0020'|'\u000C'|'\u00A0');

fragment WORDMATTER:  ('!'|'0'..'9'|'\u0023'..'\u0027'|'*'|'+'|'\u002D'..'\u0039'|'\u003F'..'\u007E'|'\u00A1'..'\uFFFE');

LPARENTHESIS : '(';
RPARENTHESIS : ')';

AND    : ('A'|'a')('N'|'n')('D'|'d');
OR     : ('O'|'o')('R'|'r');
ANDNOT : ('A'|'a')('N'|'n')('D'|'d')('N'|'n')('O'|'o')('T'|'t');
NOT    : ('N'|'n')('O'|'o')('T'|'t');
COUNT:('C'|'c')('O'|'o')('U'|'u')('N'|'n')('T'|'t');
NEAR:('N'|'n')('E'|'e')('A'|'a')('R'|'r');
PROPERTYSEPERATOR : ':';
MULTIPLESEPERATOR : ',';

WS     : (SPACE) { $channel=HIDDEN; };
NUMBERS : (NUMBER)+;
RELATION : (LESSTHEN | MORETHEN)? EQUAL // '<=', '>=', or '='
 | (LESSTHEN | MORETHEN);        // '<' or '>'
PHRASE : (QUOTE)(.)*(QUOTE);
WORD   : WORDMATTER* ;

1 个答案:

答案 0 :(得分:1)

最常见的原因是令牌长度为0.令牌中任何两个其他令牌之间可能存在无限数量的此类令牌。现在定义这样的令牌会导致ANTLR 4中的编译器警告。

以下规则可以匹配空字符串:

WORD : WORDMATTER*;

也许您打算使用以下内容?

WORD : WORDMATTER+;