Wednesday, February 25, 2009

Preprocessor directives for ruby (not!:)

At first I thought to do some more link-whoring - as I found precisely the search terms that are in the title of this post to lead to this blog... But then I though I will limit the on-topic information on the matter:

1) You don't need a preprocessor for Ruby
2) If you think you do, read up on metaprogramming - _Why's article will be a good start to spend a good time thinking.

But, this lead me back to the CPP - the preprocessor. Of course, beyond the Obfuscated C contest entries that are of parlor entertainment value only, there is some more to that.

Take a look at this one.

Then get it for infinite fun:


cvs -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp login
cvs -z3 -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp co -P chaos-pp
cvs -z3 -d:pserver:anonymous@chaos-pp.cvs.sourceforge.net:/cvsroot/chaos-pp co -P order-pp


And then go check out and mess with the examples:

the .c file looks like:


.....
int main(void) {
printf
("The 500th Fibonacci number is "
ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
".\n");
return 0;
}

//>
// Unless you are already convinced, you should check, by
// preprocessing this example, that the actual parameter to
// `printf' in the above code is just a single string that
// contains the 500th Fibonacci number in base 10.
//
// If you know the order of growth of Fibonacci numbers, you
// probably realized that the result isn't exactly small.
.....



Now, let's try it (stderr forwarded to the null for brevity, as it seems to spit some errors):


:~/tmp/order-pp/example$ cpp -I../inc fibonacci.c 2>/dev/null | tail
return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
printf
("The 500th Fibonacci number is "
"139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
".\n");
return 0;
}


Now, let's look at another example - average.c

you define the macro AVERAGE as:


#define AVERAGE(...) \
((ORDER_PP(8seq_for_each_with_delimiter \
(8put, \
8emit(8quote(+)), \
8tuple_to_seq(8quote((__VA_ARGS__)))))) / \
ORDER_PP(8to_lit(8tuple_size(8quote((__VA_ARGS__))))))


and use it in your C code like:


int main(void) {
printf(AVERAGE(3, 1, 4, 1, 5, 9, 2, 6, 5) == 4
? "OK.\n"
: "ERROR!\n");

return 0;
}


The code post-cpp looks like:


int main(void) {
printf(((3 + 1 + 4 + 1 + 5 + 9 + 2 + 6 + 5) / 9) == 4
? "OK.\n"
: "ERROR!\n");

return 0;
}


Of course, it's only simple things like this that are so nice looking... Any nontrivial definitions cause giant single-liners - the worst nightmare for the debuggers and maintainers - so I would personally torture anyone who used this in the production code.. :)

Nonetheless - pretty impressive stuff.

No comments: