Perl for #defines

Did you ever see a declaration or #define in the middle of a header file riddled with #if‘s … and when you compile with file, the desired lines don’t get included? Should you have specified -D_USE_BSD? -DPOSIX? Both? For example, here’s one definition of __WCHAR_TYPE in gcc 4.4.5’s <stddef.h>:

...
#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
#ifndef __WCHAR_TYPE__
#define __WCHAR_TYPE__ int
#endif
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif /* _WCHAR_T_DECLARED */
#endif /* _BSD_RUNE_T_DEFINED_ */
#endif
#endif
#endif
#endif
#endif
#endif
#endif

Yes, all those #endif‘s belong to conditions that affect the line of interest! You can start the tedious job of matching #if‘s and #endif‘s, trying to find what #if‘s caused that declaration to be in(/ex)cluded; OR you can use a trivial perl script to find the culprits for you. The script prefixes each source line with the #if/#elif line number and a + or to indicate whether it falls in the #if or #else part of the conditional.

#!/usr/bin/perl -w
use strict;
my $prefix = '';
while (<>) {
    if    (m{^#\s*if})    { $prefix .= "+$."; }
    elsif (m{^#\s*elif})  { $prefix =~ s{\d+$}{$.}; }
    elsif (m{^#\s*else})  { $prefix =~ s{\+(\d+)$}{-$1}; }
    elsif (m{^#\s*endif}) { $prefix =~ s{.\d+$}{}; }
    print "$prefix:$_";
}

For a header file that looks like:

#if one
one
#elif two
two
#if three
three
#elif four
four
#else five
five
#endif
#endif

… the script output is:

+1:#if one
+1:one
+3:#elif two
+3:two
+3+5:#if three
+3+5:three
+3+7:#elif four
+3+7:four
+3-7:#else
+3-7:five
+3:#endif
:#endif

From this it’s easy to tell that “five” will pop out if line 3’s condition is true and line 7’s condition is false.

And if you’re wondering what the original fragment looked like:

+28+48+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+261+319:#ifndef __WCHAR_TYPE__
+28+48+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+261+319:#define __WCHAR_TYPE__ int
+28+48+244+245+246+247+248+249+250+251+252+253+254+255+256+257+258+259+260+261:#endif
Advertisements

About mischasan

I've had the privilege to work in a field where abstract thinking has concrete value. That applies at the macro level --- optimizing actions on terabyte database --- or the micro level --- fast parallel string searches in memory. You can find my documents on production-system radix sort (NOT just for academics!) and some neat little tricks for developers, on my blog https://mischasan.wordpress.com My e-mail sig (since 1976): Engineers think equations approximate reality. Physicists think reality approximates the equations. Mathematicians never make the connection.
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

2 Responses to Perl for #defines

  1. mischasan says:

    Can’t help providing the “line noise” equivalent. Here’s the most compact possible equivalent of the above. 🙂
    #!/usr/bin/perl -ln
    $prefix=~/^#\s*if/?s/$/{+$./:/^#\s*elif/?s/\d+$/{$./:/^#\s*else/?s/\+(\d+)$/{-$1/:/^#\s*endif/?s/.\d+$/{/://;
    print”$prefix:$_”

  2. Pingback: The “C” preprocessor: not as cryptic as you’d think | Coding on the edges

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s