Parsing 可以用ANTLR解析大文件吗?

Parsing 可以用ANTLR解析大文件吗?,parsing,antlr,grammar,antlr4,Parsing,Antlr,Grammar,Antlr4,是否可以指示ANTLR不要将整个文件加载到内存中?它能否一个接一个地应用规则,并在读取文件的同时按顺序生成最顶层的节点列表?也可能会以某种方式删除分析的节点?在Antlr.org的某个地方有一个维基页面,可以回答您的问题;刚才似乎找不到 实际上,lexer使用标准的InputStream接口读取数据,特别是antlInputStream.java。典型的实现是抢占式地将整个输入数据文件读入内存。您需要做的是编写自己的缓冲版本-“ANTLRBufferedFileStream.java”-根据需要

是否可以指示ANTLR不要将整个文件加载到内存中?它能否一个接一个地应用规则,并在读取文件的同时按顺序生成最顶层的节点列表?也可能会以某种方式删除分析的节点?

在Antlr.org的某个地方有一个维基页面,可以回答您的问题;刚才似乎找不到

实际上,lexer使用标准的InputStream接口读取数据,特别是antlInputStream.java。典型的实现是抢占式地将整个输入数据文件读入内存。您需要做的是编写自己的缓冲版本-“ANTLRBufferedFileStream.java”-根据需要从源文件读取。或者,只需将标准BufferedInputStream/FileInputStream设置为AntlInputStream的数据源

需要注意的一点是,Antlr4具有无限前瞻性的潜力。在正常操作中,大小合理的缓冲区不太可能出现问题。更可能是在解析器尝试错误恢复时。Antlr4允许定制错误恢复策略,因此问题是可控的

其他细节:

实际上,Antlr实现了一个pull解析器。当您调用第一个解析器规则时,解析器从lexer请求令牌,lexer从输入流请求字符数据。解析器/lexer接口名义上由缓冲令牌流实现

解析树只不过是令牌的树数据结构。嗯,还有很多,但不是在数据大小方面。每个令牌都是一个INT值,通常由与令牌定义匹配的输入数据流片段支持。lexer本身不需要将lex的输入字符流的完整副本保存在内存中。而且,令牌文本片段可能被归零。lexer的关键内存需求是给定缓冲文件输入流的输入字符流前瞻扫描

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

为了进一步提供帮助,您需要更多地解释您在Antlr中尝试做什么,以及什么定义了您的最低关键内存需求。这将指导可以推荐哪些附加策略。例如,如果源数据是可修改的,则可以使用多个lexer/解析器运行,每次在lexer中选择源数据的不同部分进行处理。与文件读取和数据库写入相比,即使使用快速磁盘,Antlr执行也可能不太明显。

是的,您可以使用:

  • 用于字符流(传递给lexer)
  • 用于令牌流(传递给解析器)
    • 此令牌流实现在令牌通道上没有区别,因此请确保使用
      ->skip
      而不是
      ->channel(HIDDEN)
      作为lexer规则中不应发送到解析器的命令
  • 确保调用解析器,否则将为整个文件创建一个巨大的解析树
编辑并添加一些注释:

  • 我投入了大量的工作来确保
    无缓冲Harstream
    无缓冲TokenStream
    以最“理智”的方式运行,特别是在
    标记
    释放
    搜索
    获取文本
    方法方面。我的目标是在不影响流释放未使用内存的能力的情况下,尽可能多地保留这些方法的功能
  • ANTLR 4允许真正的无限制前瞻。如果您的语法需要对EOF进行前瞻以做出决定,那么您将无法避免将整个输入加载到内存中。在写语法时,你必须非常小心避免这种情况

您为什么需要这个?可以说,为了获得足够的内存,你可以在内存中构建一棵大树。显然,我的文件比内存大。我的文件是100GB。我需要扫描它并将结果输入数据库。不管怎么说,你把讨论从这个话题上移开了。如果你知道答案,请回答。我不知道具体如何使用ANTLR。通常,您可以将文件上打开的单个流视为一个真正大的小文件序列,方法是使用ANTLR解析器解析一条记录,并有效地声明它已找到EOF,然后将流的其余部分传递给新的ANTLR实例。事实上,这个想法没有什么特别的地方需要ANTLR;基本上,您可以使用任何解析引擎来实现这一点。您的文件中有哪些内容需要解析?“通常”是?我没说我不相信你有大档案。我问它有多大。(您可以获得具有100Gb RAM的计算机。您甚至不需要太多来处理100Gb文件;我们在只有16Gb RAM的计算机上运行的进程使用了90Gb)。我不明白,重新实现stream有什么帮助。ANTLR不是在内存中创建整个树吗?这就是我想的问题。你能确认一下吗,你的方法只能从字符流中释放内存,而整个树仍然在内存中?在一般情况下,是的,它会有帮助。在您的特殊情况下,由于您没有提供额外的信息,所以无法确定是否会或数量。我的文件是一个非常大的XML文件。我已经实现了另一个解析器读取顶级部分时的方法。我的问题仍然存在:是否可以从内存中清除树节点?如果您的文件确实是XML,那么它的大部分空间都浪费在空白处、长的重复标记名以及记录的值的文本版本(例如数字和字符串)中。一个定义良好的AST表示您的文件,并将标记和textifed值表示为合理的二进制数据,它的内存占用可能比原始XML文本小得多。因此,您的100 GB XML文件可能会占用10 GB的虚拟机空间。内存为4-8GB的机器实际上可以添加10GB的内存