Antlr4如何从一个大文件中提取感兴趣的部分

Antlr4如何从一个大文件中提取感兴趣的部分,antlr4,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_]

我有下面的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 ;
文件大小为20MB,如下所示

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
        ...
    }
    ...
}
...
表示我省略的行。实际文件在那里具有有效语法

比如说,我只需要知道国家的数量,并记录每个国家的名称和粮食盈余

目前我做的是

ICharStream cstream=CharStreams.fromstring(输入);
ITokenSource lexer=新的ParadoxLexer(cstream);
ITokenStream令牌=新的CommonTokenStream(lexer);
var parser=新的ParadoxParser(令牌);
//查找密钥为“country”的kvPair。
//那么,ChildCount是国家的数量,
//查找密钥为“name”的kvPair以获取国家名称。
这种方法是可行的,但缺点是它在运行时会消耗1GB的内存。注意,我没有使用,也不知道如何使用访问者模式或侦听器模式

我知道大内存消耗是因为…,我省略的行,可能是数百万行。Antlr正在为这些不感兴趣的事情构建解析树


如何减少内存消耗

解析器不是这种处理的合适工具,因为它应该验证它得到的所有输入。这是解析器本身的主要目标。如果您只对输入的一部分感兴趣,那么首先通过其他方式(例如,搜索某些分隔符)将其拆分,并仅将感兴趣的部分提供给解析器

更新: 按请求:用于侦听器/访问者的ANTLR4文档,与解析器运行生成的解析树一起使用。为了在解析过程中使用侦听器,您只需要(与解析后使用的侦听器完全相同):


字符串可以包含括号,并且\“用于转义字符串分隔符。如果我需要编写自己的代码,这些极端情况会使它变得复杂。你对处理这些情况有什么建议吗?是的,我的想法只有在你有一个可以在输入流中很容易找到的分隔符的情况下才有效。如果不是这样,您可能必须应用更复杂的解决方案(例如,首先标记化输入,然后从生成的标记中为解析器选择输入范围)。但是,这要求您的输入是完全可标记化的,也就是说,所有输入都可以由不重叠的标记表示(例如,可跳过内容中的值组合不会出现在重要内容中)。我是否可以将build parse tree默认设置为false,同时对感兴趣的节点重新启用?我不知道怎么做。当然,启用/禁用解析树生成可以根据需要切换,方法是设置
parser.buildParseTree=false(确切的调用取决于运行时平台)。您能举个例子吗?我的实验似乎表明,如果buildParseTree=false,访问者和侦听器模式就不起作用。
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