Since the last blog post, I have been investigating on how to teach elsa about the C preprocessor. Overall, I am really happy that MCPP exists and is actively maintained. Preprocessed source code may not be invertible into the original form, but at least it can be undone enough for refactoring purposes.
Looks like I should be able to preprocess the source code, and while at it record macro expansion information and then have elsa fed with a somewhat xml-escue data structure.
The way I see it, a line of code like
foo = PR_MAX(boo(), nsnull)
which expands into
foo = boo() > 0 ? boo() : 0;
will get fed to elsa as something like
<fragment>foo = <macro id=somemacro_instance>PR_MAX(boo(), nsnull)</macro>;</fragment>
where somemacro_instance is defined as
<fragment><fragment ref=some_fragment/> > 0 ? <fragment ref=some_fragment/> : <macro id=some_staticmacro>0</macro></fragment>
where some_staticmacro is defined as
I think this is a cute scheme because fragments are basically regions of source-code. This is exciting because once a macro is used in the code, the text fragment that defines the macro can be parsed as C++ and rewritten accordingly. Obviously, this wouldn’t be the default behavior.
If you see a fatal flow in the above model, let me know.
My main reason for adding preprocessor support to elsa is to obtain precise source locations from elsa. Ironically, MCPP “compresses” whitespace, so column information is basically thrown out of the window. Means I’ll have to do some extensive culling of the compression code (which is everywhere).
Another fun issue is that the general structure of MCPP encourages the “lots of global variables and defines” mode of programming. It also uses strings-as-a-data-structure pattern which may make me give up on the fancy onion-peel model I described above and instead have mcpp generate preprocessed code along with an “undo” type log.
MCPP is also a bit on the slow side compared to GCC, but I’ll trade a second or two slowdown per file for never having to cry due to CPP again.