前言

在最近一段时间,我们已经开发了许多新功能作为对Spirit [4] 解析器构造框架的补充,并且我们越来越觉得,有一个“真实世界”的例子非常有帮助,这个例子可以作为测试某些功能可用性的沙箱。此外,最近在 Boost 邮件列表上的一次讨论表明,开发者们普遍有兴趣拥有一个现代的、开源的 C++ 预处理器库来使用。因此,我们有了实现一个 C++ 预处理器的想法,以满足这些需求——Wave就此诞生了。

WaveC++ 预处理器库使用Spirit[4]解析器构造库来实现一个 C++ 词法分析器,具有符合 ISO/ANSI 标准的预处理能力。它暴露了一个迭代器接口,该接口返回输入流中的当前预处理过的标记。这个预处理过的标记是在遍历预处理器迭代器序列时(在 STL 的术语中,这些迭代器是前向迭代器)即时生成的。

C++ 预处理器是一个宏处理器,在正常情况下,它会被你的 C++ 编译器自动调用,在实际编译之前转换你的程序。它被称为宏处理器是因为它允许定义宏,宏是较长构造的简短缩写。C++ 预处理器提供了四种独立的功能,你可以根据需要使用:

 包含头文件
 宏展开
 条件编译
 行控制

这些功能如今被大大低估了,更何况,预处理器长期以来一直被诟病,以至于它的使用直到几年前 Boost 预处理器库 [7] 出现才得到有效推广。直到今天,我们才开始认识到,C++ 中预处理器生成式元编程与模板元编程相结合,是任何语言有史以来支持的最强大的编译时反射/元编程功能之一。

C++ 标准 [2] 于 1998 年通过,但至今(据我所知)没有一款商业 C++ 编译器能无错误地实现其中规定的相当简单的预处理器要求。这可能是由于上述的低估,甚至在过去几年中,预处理器被视为不良编程风格的一部分,或者可能源于描述它的、略显笨拙的标准英文方言。有两个开源项目是例外:gcc 和 Clang(LLVM 的一个子项目),它们都提供了符合标准程度非常高的预处理器。

因此,对于Wave该项目的主要目标是

 完全符合 C++ 标准 (ISO/IEC 14882:1998) [1] 和 C99 标准 (INCITS/ISO/IEC 9899:1999) [2]
 使用Spirit[4]进行游戏中的解析部分(当然 :-)
 最大限度地使用 STL 和/或Boost库(以实现紧凑和可维护性)
 为实现附加功能提供直接的可扩展性
 构建一个灵活的库,以满足不同的 C++ 词法分析和预处理需求

在最初的阶段,我们不计划开发一个性能非常高或非常小的 C++ 预处理器。如果你在寻找这些目标,你可能需要去别处寻找。尽管我们的 C++ 预处理器迭代器按预期工作,并且可用作参考实现,例如用于测试其他面向预处理器的库,如 Boost Preprocessor 库 [7] 等。尽管如此,最近的工作已经带来了令人惊讶的性能提升(与早期版本相比)。与 EDG 驱动的预处理器(Intel, Comeau)在简单输入文件上的性能相比,Wave 仍然稍慢,但是,随着复杂性的增加,EDG 的时间呈指数级增长。Wave 的预处理时间呈线性增长,这使得它在复杂性增加时能够轻松超越 EDG 驱动的预处理器。

正如测试表明,该Wave库非常符合 C++ 标准,因此它能够编译几个严格符合标准的宏定义,这些宏甚至无法在 EDG 驱动的预处理器(如 Comeau 或 Intel)中编译。