有可能用ANTLR解析大文件吗?



是否可以指示ANTLR不将整个文件加载到内存中?它是否可以逐个应用规则并依次生成最顶层的节点列表,以及读取文件?也可能是有可能以某种方式删除分析节点?

是的,你可以使用:

  • UnbufferedCharStream为您的字符流(传递给lexer)
  • UnbufferedTokenStream用于令牌流(传递给解析器)
    • 这个令牌流实现在令牌通道上没有区别,所以确保使用->skip而不是->channel(HIDDEN)作为不应该发送到解析器的词法分析器规则中的命令。
  • 确保在解析器上调用setBuildParseTree(false),否则将为整个文件创建一个巨大的解析树。

编辑一些额外的注释:

  • 我投入了相当多的工作来确保UnbufferedCharStreamUnbufferedTokenStream以最"理智"的方式操作,特别是与mark, release, seekgetText方法有关。我的目标是在不影响流释放未使用内存的能力的情况下尽可能保留这些方法的功能。
  • ANTLR 4允许真正无限的前瞻性。如果您的语法需要提前查看EOF来做出决定,那么您将无法避免将整个输入加载到内存中。在编写语法时,你必须非常小心地避免这种情况。

在Antlr.org的某个地方有一个维基页面可以回答你的问题;刚才好像找不到。

实际上,词法分析器使用标准的InputStream接口读取数据,特别是ANTLRInputStream.java。典型的实现是ANTLRFileStream.java,它抢占式地将整个输入数据文件读入内存。您需要做的是编写自己的缓冲版本——"ANTLRBufferedFileStream.java"——根据需要从源文件中读取。或者,将标准的BufferedInputStream/FileInputStream设置为AntlrInputStream的数据源。

需要注意的是,Antlr4有可能实现无界向前看。对于大小合理的缓冲区,在正常操作中不太可能出现问题。当解析器尝试错误恢复时更有可能。Antlr4允许调整错误恢复策略,因此问题是可管理的。

额外的细节:

实际上,Antlr实现了一个pull-parser。当调用第一个解析器规则时,解析器从词法分析器请求令牌,词法分析器从输入流请求字符数据。解析器/词法分析器接口由一个缓冲的令牌流(名义上为BufferedTokenStream)实现。

解析树只不过是一个令牌的树形数据结构。好吧,更多,但不是在数据大小方面。每个令牌都是一个INT值,通常由与令牌定义匹配的输入数据流片段支持。词法分析器本身不需要在内存中保存词法输入字符流的完整副本。并且,标记文本片段可以被归零。对于词法分析器来说,关键的内存需求是输入字符流前瞻扫描,给定一个缓冲的文件输入流。

根据您的需要,即使给定100GB以上的输入文件,内存中的解析树也可以很小。

为了进一步提供帮助,您需要更多地解释您在Antlr中尝试做什么以及如何定义最小临界内存需求。这将指导可以推荐哪些其他战略。例如,如果源数据是可处理的,则可以运行多个词法分析器/解析器,每次在词法分析器中选择要处理的源数据的不同部分。与文件读取和数据库写入相比,即使使用快速磁盘,Antlr的执行也可能几乎不引人注意。

相关内容

  • 没有找到相关文章

最新更新