在F#中是否有已知的解析器组合库,可以解析二进制文件(而不是文本)?

13

我熟悉fparsec的一些基础知识,但它似乎更适用于文本文件或流。

是否有其他能够高效解析二进制文件的F#库?或者是否可以轻松修改fparsec以便有效地处理二进制流?


2
我想提一下,虽然已经过去了2年,但我一直在开发一个可以实现这个功能的项目。我使用fparsec风格的组合器编写了一个示例mp4容器二进制解析器。https://github.com/devshorts/ParsecClone - devshorts
2个回答

12
您可能会对"pickler组合器"感兴趣。这类似于解析器组合器,但更专注于简单的二进制格式(picklers可以生成二进制数据,而unpicklers则对其进行解析)。 Andrew Kennedy(度量单位的作者)撰写了一篇关于该想法的相当易懂的文章(PDF),您可以在这里阅读。
我本人没有太多使用经验,但我意识到这可能与您相关。该思想用于F#编译器生成一些二进制资源(如存储在资源中的引号)。虽然我不确定F#编译器实现是否好(它是F#编译器早期版本的东西)。

我记得在Expert F# Book中看到过“pickler”这个术语...谢谢Tomas,我也会去查一下。这提醒我还要去查一下你在F#编译器中提到的恢复操作。 - 7sharp9
@Tomas,通过查看您提交的链接中的文档,您已经回答了您问我的关于worker/wrapper transformations实用性的问题。请参见链接末尾有关在ML中实现picklers的讨论。 - user29439
我要去尝试单子泡菜 :-) - 7sharp9
@Ryan 嗯,这听起来非常有趣,看起来工人/包装器转换实际上可能非常有用。我希望我有更多时间来尝试一下这个 :-). - Tomas Petricek
链接到PDF已经失效了。它应该指向这个链接吗? - Julian
@Julian 是的!谢谢 - 我已经修复了答案中的链接。 - Tomas Petricek

6
使用二进制流的问题不是解析器本身的问题,而是词法分析器的问题。词法分析器将原始数据转换为解析器可以处理的元素。
大多数解析系统都能让您提供自己的词法分析器,如果是这种情况,您可以很容易地编写符合规范的词法分析器以处理二进制流。
然而,问题在于,今天大多数解析和词法分析系统本身都是从更高级别的工具创建的。而那个工具很可能不能用于处理二进制流。也就是说,您无法指定可用于创建后续解析器和词法分析器的二进制流的标记和语法。此外,您可能根本没有任何支持高级多字节二进制数字(shorts、longs、floats等)的支持,这些数字可能会在二进制流中遇到,并且如果您实际上需要处理它们的实际值,则生成的解析器可能无法很好地处理它们,因为这些系统大多设计用于基于文本的标记,底层运行时处理将该文本转换为机器可用的内容的详细信息(例如将ASCII数字序列转换为实际的二进制整数序列)。
尽管如此,您仍然可以使用工具的解析部分,因为解析器更多地处理由词法分析器提供的抽象标记。一旦您在符号级别上创建了语法,您需要重新编写词法分析器以从二进制流中创建问题标记以馈送到解析器中。
这实际上很好,因为解析器往往比基本词法分析器复杂得多,因此工具包将为您处理大部分“难点”。但是,您仍然需要处理创建自己的词法分析器并正确接口到生成的解析器的问题。这不是一个不可逾越的任务,如果语法具有任何真正的复杂性,则长期来看可能值得您的努力。
如果一切都很简单,那么您可能最好自己动手完成。就我而言,很难想象一个困难的二进制语法,因为二进制格式的主要卖点是它更接近于机器,这与大多数解析器设计用于处理文本相矛盾。但我不知道您的用例。
但考虑反汇编器的情况。这是一个简单的词法分析器,可以在高级别上理解不同的指令类型(例如没有参数的操作数、以一个字节作为参数或字),并将其馈送给解析器,然后可以用于将指令转换为其助记符和操作数的正常汇编器语法,以及处理标签引用等。
这是一个人为的情况,因为反汇编器通常不会将词法分析和解析阶段分开,它通常不够复杂以值得费心,但这是解决问题的一种方式。
附加说明:
如果您有足够的信息将二进制流转换为文本以馈送到引擎,则您有足够的信息来创建解析器从词法分析器中希望看到的实际标记。

尽管如此,您可以采用文本格式作为解析工具和语法的基础,并创建词法分析器和语法分析器机器,然后手动使用“文本测试”来测试解析器及其处理功能。

但是,当您开始阅读二进制文件时,不必创建要进行词法分析和语法分析的文本,而是直接创建词法分析器生成的标记(应该是简单对象),并将其推送到解析器中。这将节省词法分析步骤并节省一些处理时间。


首先感谢您提供详细的答案。我打算使用低级语法的子集,并将其组合成可以由类似fparsec的东西处理的块。例如 (pbyte 0x45) >>= fun x -> (pbyte 0x78) 等等。然后使用这些块来生成可能的文本,然后再由fparsec处理。 - 7sharp9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接