使用 Boost/Wave C/C++ 预处理器的选择性宏扩展
Posted
技术标签:
【中文标题】使用 Boost/Wave C/C++ 预处理器的选择性宏扩展【英文标题】:Selective macro expansion using the Boost/Wave C/C++ preprocessor 【发布时间】:2020-01-01 14:22:33 【问题描述】:对于 C99 代码库,我非常依赖宏来代替适当的 C++ 模板。对于我的用例,宏最严重的缺点是很难/不可能调试生成的代码,这很多。如果我可以创建一个自定义预处理器,该预处理器仅将一组白名单宏扩展为中间构建步骤,那就太好了。我想知道是否可以使用 Boost 库中的 Wave 预处理器来做到这一点。我正在浏览文档,但老实说,我还不清楚这是否可能。
1) 从概念上讲,我想实现以下目标:
foo.c => selective_wave_preprocessor(MACRO_BAR, MACRO_BAZ) => foo.c_preprocessed
所以在这种情况下,foo.c_preprocessed
将是 ONLY 在foo.c
中扩展(类似函数)宏的MACRO_BAR
和MACRO_BAZ
的结果。如果我在foo.c
和foo.c_preprocessed
上运行普通的预处理器,那么输出必须是相同的。
2) 我希望看到标记为白名单的多行宏实际上是用换行符格式化的,这样它仍然是人类可读的。
我希望有人能告诉我 Wave 预处理器是否是执行此操作的正确工具。如果是这样,我会很高兴看到一个关于如何执行此类操作的示例,或者为我指出完成此操作所需的正确 Wave 原语。
【问题讨论】:
请注意,§5.1.1.2 Translation phases 将反斜杠换行符删除列为第 2 阶段,因此预处理器本身不会在宏定义中的反斜杠之后看到嵌入的换行符。这使得“保留换行符”变得困难。这也是为什么 X11imake
程序使用 @@
来标记换行符的原因;它对来自 C 预处理器的输出进行后处理,以将 @@
转换回换行符。我不知道其余问题的答案;我没有玩过 Wave。
我也不知道 Wave,但是通过它的一些文档的简短浏览表明,它提供的独立 C++ 预处理器没有运行时配置选项,可以避免执行宏扩展符合标准的预处理器将执行。但是,可以使用 Wave 类来构建您自己的自定义预处理器。
@JonathanLeffler 啊,请原谅我对精确编译步骤的了解不足。因此,如果我的评论正确,我的问题需要一个专门的词法分析器来执行例如 @@
替换技巧,以便我的预处理器应该忽略 do 标记,并且“后预处理器”可以将这些 @@
替换回换行符?
或多或少 — 这意味着您使用的任何预处理器技术都可能需要非标准的词法分析。请记住,预处理器的行为“好像”遵循标准中概述的阶段。标准本身说这些步骤通常是结合在一起的。诸如 GCC 之类的编译器确实会报告导致问题的代码;它将指向一个语句中的一个源代码行,该语句是用反斜杠换行符延续的多行编写的。您想要的可能可以完成,但可能需要对标准预处理器技术进行相当大的调整。 Wave 可能是一个好的开始。
【参考方案1】:
您可以使用 Boost.Wave 实现第一个,并且至少部分实现第二个。关键功能是context policy hooks,尤其是expanding_function_like_macro
、expanding_object_like_macro
和rescanned_macro
。前两个使您能够有条件地抑制宏扩展,最后一个为您提供宏扩展的结果。
Jonathan Leffler 指出了您的第二个要求可能无法完全满足的一个原因;我要补充一点,我不确定“换行保留”是否是 Wave 具有测试覆盖率或旨在实现的东西。无论如何,rescanned_macro
会给你扩展的结果。
【讨论】:
通过使用宏定义和包含指令的智能组合来模仿模板引擎,我现在已经以更优雅和通用的方式解决了我的问题,除了 C 预处理器之外不需要任何东西。这包括新线路问题的解决方案。但是,如果您可以在此处提供有关您所描述内容的工作示例。我会投票并接受你的回答。 听起来您有一个满足您需求的解决方案,那么!如果其他人对此方法感兴趣,Wave 附带了一组示例程序; “advanced_hooks”展示了其中的一些功能。 boost.org/doc/libs/1_74_0/libs/wave/doc/samples.html以上是关于使用 Boost/Wave C/C++ 预处理器的选择性宏扩展的主要内容,如果未能解决你的问题,请参考以下文章