I want to remove all comments in a toy.c
file. From Remove comments from C/C++ code I see that I could use
gcc -E -fpreprocessed -P -dD toy.c
But some of my code (say deprecated functions that I don't want to compile) are wrapped up between #if 0
and endif
, as if they were commented out.
-fpreprocessed
prevents;-fpreprocessed
is a bad idea.I see a dilemma here. Is there a way out of this situation? Thanks.
The following toy example "toy.c" is sufficient to illustrate the problem.
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
gcc -E -fpreprocessed -P -dD toy.c
gives
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
while gcc -E -P toy.c
gives
int main (void) {
return 3;
}
There's a pair of programs, sunifdef
("Son of unifdef
", which is available from unifdef) and coan
, that can be used to do what you want. The question Is there a C pre-processor which eliminates #ifdef blocks based on values defined/undefined? has answers which discuss these programs.
For example, given "xyz37.c":
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
}
#endif
Using sunifdef
sunifdef -DDEFINED -ned < xyz37.c
gives
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
and given this file "xyz23.c":
#if 0
This is deleted
#else
This is not deleted
#endif
#if 0
Deleted
#endif
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
#if 1
This is persistent
#else
This is inconsistent
#endif
The program
sunifdef -DDEFINE -ned < xyz23.c
gives
This is not deleted
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
This is persistent
This is, I think, what you're after. The -DDEFINED
options seems to be necessary; choose any name that you do not use in your code. You could use -UNEVER_DEFINE_THIS
instead, if you prefer. The -ned
option evaluates the constant terms and eliminates the relevant code. Without it, the constant terms like 0
and 1
are not eliminated.
I've used sunifdef
happily for a number of years (encroaching on a decade). I've not yet found it to make a mistake, and I've used it to clean up some revoltingly abstruse sets of 'ifdeffery'. The program coan
is a development of sunifdef
with even more capabilities.
The preprocessor doesn't make exceptions. You cannot use it here to do that.
A simple state machine using python can work. It even handles nesting (well, maybe not all cases are covered like nested #if 0
but you can compare the source before & after and manually validate). Also commented code isn't supported (but it seems that you have it covered)
the input (slightly more complex than yours for the demo):
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
#ifdef DDD
printf("%d\n", foo);
#endif
}
#endif
void other_function()
{}
now the code, using regexes to detect #if
& #endif
.
import re
rif0 = re.compile("\s*#if\s+0")
rif = re.compile("\s*#(if|ifn?def)")
endif = re.compile("\s*#endif")
if_nesting = 0
if0_nesting = 0
suppress = False
with open("input.c") as fin, open("output.c","w") as fout:
for l in fin:
if rif.match(l):
if_nesting += 1
if rif0.match(l):
suppress = True
if0_nesting = if_nesting
elif endif.match(l):
if if0_nesting == if_nesting:
suppress = False
if_nesting -= 1
continue # don't write the #endif
if not suppress:
fout.write(l))
the output file contains:
#define foo 3
int main (void) {
return foo;
}
void other_function()
{}
so the nesting worked and the #if 0
part was successfully removed. Not something that sed "/#if 0/,/#endif/d
can achieve.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With