如何使用 flex 和 bison 解析非常大的缓冲区

How to parse very large buffer with flex and bison

本文关键字:非常 缓冲区 何使用 flex bison      更新时间:2023-10-16

我写了一个json库,它使用flex和bison来解析序列化的json(即字符串),并将它们反序列化为json对象。它非常适合小字符串。

但是,它无法处理非常大的字符串(我尝试了几乎 3 GB 的字符串),并出现此错误:

‘fatal flex scanner internal error--end of buffer missed’

我想知道我可以传递给此函数的缓冲区的最大大小是多少:

//js: serialized json stored in std::string 
yy_scan_bytes(js.data(), js.size()); 

如何使 Flex/Bison 与大型缓冲区一起工作?

在我看来

,您使用的是旧版本的 flex 骨架(因此也是 flex),其中假定字符串长度适合 int s。您观察到的错误消息可能是int溢出到负值的结果。

我相信,如果您切换到 2.5.37 或更高版本,您会发现这些int中的大多数都已变得size_t,使用大小超过 2 GB 的输入缓冲区调用 yy_scan_bytes 应该没有问题。(例如,该函数的原型现在采用size_t而不是int

然而,我很难相信这样做是个好主意。首先,yy_scan_bytes复制整个字符串,因为词法扫描程序想要一个允许修改的字符串,并且因为它希望确保字符串末尾有两个 NUL 字节。制作该副本将不必要地消耗大量内存,如果您无论如何都要复制缓冲区,您不妨将其复制为可管理的片段(例如,64Kib 甚至 1MiB)。只有当你的单个代币明显大于块大小时,这才会有问题,因为flex绝对没有针对大型单个代币进行优化。但是对于所有正常的用例,它可能会做得更好。

Flex 不提供将巨大的输入缓冲区拆分为块的接口,但您可以通过重新定义YY_INPUT宏来非常轻松地做到这一点。(如果这样做,最终可能会使用 yyin 作为指向您自己的缓冲区结构的指针,该结构理论上是不可移植的。但是,它将适用于任何 Posix 体系结构,其中所有对象指针都具有相同的表示形式。

当然,您通常不想等待内存中累积了 3GB 的数据才开始解析它。您可以在读取数据时以增量方式进行分析。(您可能仍需要重新定义YY_INPUT,具体取决于您读取数据的方式。