是否可以指示ANTLR不将整个文件加载到内存中?它可以逐个应用规则并按顺序生成最顶层的节点列表以及读取文件吗?也可能以某种方式丢弃分析的节点?
答案 0 :(得分:13)
是的,您可以使用:
UnbufferedCharStream
用于您的角色流(传递给词法分析器)UnbufferedTokenStream
用于您的令牌流(传递给解析器)
->skip
而不是->channel(HIDDEN)
作为lexer规则中不应发送给解析器的命令。< / LI>
setBuildParseTree(false)
,否则将为整个文件创建一个巨大的解析树。使用其他评论进行编辑:
UnbufferedCharStream
和UnbufferedTokenStream
尽可能以最“健全”的方式运作,特别是与mark
,release
相关,seek
和getText
方法。我的目标是在不影响流释放未使用内存的能力的情况下尽可能多地保留这些方法的功能。答案 1 :(得分:3)
在Antlr.org的某个地方有一个维基页面可以解释你的问题;似乎在刚才找不到。
实质上,词法分析器使用标准的InputStream接口读取数据,特别是ANTLRInputStream.java。典型的实现是ANTLRFileStream.java,它抢先将整个输入数据文件读入内存。您需要做的是编写自己的缓冲版本 - “ANTLRBufferedFileStream.java” - 根据需要从源文件中读取。或者,只需将标准BufferedInputStream / FileInputStream设置为AntlrInputStream的数据源。
有一点需要注意的是,Antlr4有可能做出无限的前瞻。在正常操作中对于合理大小的缓冲区来说不太可能是问题。解析器尝试错误恢复时更有可能。 Antlr4允许定制错误恢复策略,因此问题是可管理的。
其他细节:
实际上,Antlr实现了一个pull-parser。当您调用第一个解析器规则时,解析器从词法分析器请求令牌,词法分析器从输入流请求字符数据。解析器/词法分析器接口由缓冲的令牌流实现,名义上为BufferedTokenStream。
解析树只不过是令牌的树数据结构。好吧,还有更多,但不是数据大小。每个标记都是一个INT值,通常由与标记定义匹配的输入数据流的片段支持。词法分析器本身不需要将lex'd输入字符流的完整副本保存在内存中。并且,令牌文本片段可以为零。在给定缓冲文件输入流的情况下,词法分析器的关键内存要求是输入字符流预测扫描。
根据您的需要,即使给出100GB +输入文件,内存中的解析树也可以很小。
为了进一步提供帮助,您需要更详细地解释您在Antlr中尝试做什么以及定义最低关键内存要求的内容。这将指导可以推荐哪些额外的策略。例如,如果源数据是可服务的,则可以使用多个词法分析器/解析器运行,每次在词法分析器中选择要处理的源数据的不同部分。与文件读取和数据库写入相比,即使使用快速磁盘,Antlr执行也可能几乎不会引起注意。