Antlr4如何从大文件中提取有趣的部分

时间:2019-04-28 19:05:01

标签: antlr4

我有以下Antlr4语法。

grammar Paradox;

paradox:
  kvPair+;

kvPair
  : atom '=' atom
  | atom '=' scope
  | scope
  ;

scope
  : '{' (paradox|atom+)? '}'
  ;

atom
  : STRING
  | NUMBER
  | ID (':' ID)?
  ;

STRING
  : '"' (~'"')*? '"'  ;

ID : [0-9a-zA-Z_]+ ;

NUMBER
    : '-'?[0-9]+ ('.' [0-9]+)?
    ;

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

文件为20 MB,看起来像这样

version="Boulle v1.9.1"
version_control_revision=31493
name="泰布理同胞体"
date="2269.02.09"
planet= { ... }
...
country = {
    0 = {
        ...
        name="USA"
        ...
        food_surplus=3.598
        ...
    }
    1 = {
        ...
        name="ENG"
        ...
        food_surplus=2.001
        ...
    }
    ...
}
...

...表示我省略了行。实际文件在那里具有有效的语法。

说,我只需要知道国家/地区的数目,并为每个国家/地区记录名称和food_surplus。

当前我要做的是

ICharStream cstream = CharStreams.fromstring(input);
ITokenSource lexer = new ParadoxLexer(cstream);
ITokenStream tokens = new CommonTokenStream(lexer);
var parser = new ParadoxParser(tokens);
// find kvPair with key "country".
// Then .ChildCount is the number of country,
// find kvPair with key "name" to get the name of the country.

此方法有效,但缺点是运行时会消耗多达1GB的内存。请注意,我没有使用,也不知道如何使用访客模式或听众模式。

我了解大的内存消耗是由于...,我省略的行可能是数百万行。 Antlr正在为这些无关紧要的事物构建解析树。

如何减少内存消耗?

1 个答案:

答案 0 :(得分:2)

解析器不是用于此类处理的正确工具,因为它应该验证它获得的所有输入。这本身就是解析器的主要/主要目标。如果您只对输入的一部分感兴趣,则可以先通过其他方式将其分割(例如,搜索某些定界符),然后仅将感兴趣的部分提供给解析器。

更新:

根据请求:用于侦听器/访问者的ANTLR4文档have a short description,与解析器运行生成的解析树一起使用。为了在解析过程中使用侦听器,您只需要register your listener(与解析后使用的监听器完全一样):

JavaLexer lexer = new JavaLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaParser parser = new JavaParser(tokens);
MyListener extractor = new MyListener(parser);
parser.addParseListener(extractor);
JavaParser.CompilationUnitContext tree = parser.compilationUnit(); // parse a compilationUnit