问题
We have inherited a very convolved project (500kloc) with a lot of preprocessor conditional logic, most of which is no longer relevant, and I want to clean it up.
Can I use the preprocessor¹ to expand only some of the conditional logic, and leave all other preprocessor macros, defines, and includes alone in the output?
¹ Here, by "the preprocessor", I really mean "any tool", either a standard C preprocessor, something I can install, or even a hacked-together Perl or Python script.
For instance, suppose we have this set of code:
#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
The tool I want (and might need to write if it doesn't exist) would be a version of CPP that accepts not only the list of definitions for a particular invocation, but also a list of defines to respect during expansion. Any preprocessor symbol not in the second list is completely left alone. An example is in order:
cpptreadlight -DY=22 --only=Y
would produce:
#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
and:
cpptreadlight -DY=22 -DZ=8 -DX --only=Y,baz,Z
would give me:
#include <foo>
#define bar(a) do{(a)+1} \
while(0)
#ifdef X
so_far_so_good = true;
something();
#else
#endif
Notice that even though X
is defined, it was left behind, because it didn't appear in the --only
list. Also note that baz
was in the --only
list, and so was expanded once it was defined in the source.
I tried a hack-solution: escaping uninteresting stuff using a pipeline like the following (my own gsub tool is used, but it does what you might expect):
function escape_tr() {
gsub "#(define|include)" '@@@\1' < $1 |
(echo '#include "simple.h"' && gsub '\\$' "%%%") |
cpp -C -P -DY=301 -DZ > $1.new
}
Now I can filter out a lot of stuff, and then put the things I want the preprocessor to expand in simple.h
. Comments are left alone, and #line
directives are left out.
This almost does the trick, in that includes are not pulled in, #define
blocks are not defined, and so not expanded into the body. But of course it doesn't let me specify the set of conditional logic that I'd like to keep in the output. That's bad. Some of it is important to keep conditional.
#if
nests, and the #else
and #endif
tokens don't lexically match, putting the problem beyond a regex pipeline. I need a full-blown parser, something practically identical to cpp itself, but with finer grained control of what is expanded.
Hence, before digging into a preprocessor to implement this, I thought I'd ask if anyone has solved this problem before. I can't be the only one to have inherited a preprocessor spaghetti nest full of dead branches.
回答1:
There is a tool called "unifdef" that will do what you want.
回答2:
You should definitely take a look at boost.wave
from the boost.wave preface:
So the main goals for the Wave project are:
- full conformance with the C++ standard (ISO/IEC 14882:1998) 1 and with the C99 standard (INCITS/ISO/IEC 9899:1999)
- usage of Spirit[4] for the parsing parts of the game (certainly :-)
- maximal usage of STL and/or Boost libraries (for compactness and maintainability)
- straightforward extendability for the implementation of additional features building a flexible library for different C++ lexing and preprocessing needs
来源:https://stackoverflow.com/questions/4147967/partially-processing-a-file-with-the-preprocessor