我们继承了一个非常卷积的项目(500kloc)和一个很多的预处理器条件逻辑,其中大部分不再相关,我想要清理它。
我是否可以使用预处理器¹仅扩展条件逻辑的某些,并将所有其他预处理器宏,定义和包含单独保留在输出中?
¹这里,通过“预处理器”,我的意思是“任何工具”,既可以是标准的C预处理器,也可以是我可以安装的东西,甚至可以是一个黑客攻击的Perl或Python脚本。
例如,假设我们有这组代码:
#include <foo>
#define baz
#define bar(a) do{(a)+1} \
while(0)
#ifdef X
#if Y > 20
#if Z > 5
so_far_so_good = true;
#endif
#ifdef baz
something();
#endif
#else
otherthing();
#endif
#else
#if Z > 10
wow().this.is.bad;
#endif
#endif
我想要的工具(如果它不存在则可能需要编写)将是CPP的一个版本,它不仅接受特定调用的定义列表,而且还接受在扩展期间要遵守的定义列表。任何不在第二个列表中的预处理程序符号都是完全不管的。一个例子是按顺序:
cpptreadlight -DY=22 --only=Y
会产生:
#include <foo>
#define baz
#define bar(a) do{(a)+1} \
while(0)
#ifdef X
#if Z > 5
so_far_so_good = true;
#endif
#ifdef baz
something();
#endif
#else
#if Z > 10
wow().this.is.bad;
#endif
#endif
和
cpptreadlight -DY=22 -DZ=8 -DX --only=Y,baz,Z
会给我:
#include <foo>
#define bar(a) do{(a)+1} \
while(0)
#ifdef X
so_far_so_good = true;
something();
#else
#endif
请注意,即使定义了X
,它也会被遗忘,因为它没有出现在--only
列表中。另请注意,baz
列表中的--only
,因此在源中定义后会进行扩展。
我尝试了一个黑客解决方案:使用如下管道逃避无趣的东西(使用我自己的gsub工具,但它可以达到您的预期效果):
function escape_tr() {
gsub "#(define|include)" '@@@\1' < $1 |
(echo '#include "simple.h"' && gsub '\\$' "%%%") |
cpp -C -P -DY=301 -DZ > $1.new
}
现在我可以过滤掉很多东西,然后将我想要的预处理器放在simple.h
中。评论是单独的,并且遗漏了#line
指令。
这个几乎可以解决这个问题,其中包括未包含的内容,#define
块未定义,因此未扩展到正文中。但是当然它不允许我指定我想要保留在输出中的条件逻辑集。那很糟。保持有条件的一些很重要。
#if
嵌套,#else
和#endif
标记在词法上不匹配,将问题置于正则表达式管道之外。我需要一个完整的解析器,它实际上与cpp本身完全相同,但是对扩展的内容进行了更精细的控制。
因此,在深入研究预处理器实现这一点之前,我想我会问以前有没有人解决过这个问题。我不可能是唯一一个继承了一个充满死枝的预处理器意大利面窝的人。
答案 0 :(得分:9)
有一个名为“unifdef”的工具会做你想做的事。
答案 1 :(得分:0)
你一定要看看boost.wave
来自boost.wave前言:
所以Wave项目的主要目标是: