2006-07-08

Excessive Macros

Recently I've been working on a project that made an excessive use of Macros. Such usage is usually discouraged. Yet it was a must -or at least it seemed so-. We needed a component to be highly configurable in order to be able to exploit different implementation techniques or even more, different programming paradigms, we also needed that at minimum maintenance cost . To be clearer "function or procedure" was considered a high level abstraction that might be under investigation !!.
The implementation language was C++ as a multi paradigm language. The component was deeply studied and it's operations were extensively annotated. It was decomposed into fine grained operations, the core logic of each was attached to a macro, with which we play, reorder or discard depending on the technique or paradigm under investigation.

Macros
Debugging macros is poorly supported in the output of most C/C++ compilers -or at least ones that came to my notice -cl6,7,7.1 gcc4.01-, which is inherent from the nature of macros being repeatedly defined or redefined across a single source file or even across the project, added to that the possibility of containing other macros which adds recursion to it's forementioned nature. So debuggers have no clue about which definition to attach to the encountered macro. gdb for example the only macro support it provides is to expand -just expand- the encountered macro with no digging into it.

We made use of a level of indirection in the compilation process as follows from the following steps
  1. Editing and coding is done in a file excluded from build with only includes of macros to be expanded and no std includes added to avoid their lengthy expansion.
  2. The file is preprocessed into another files with macros expanded.
  3. Each macro is expanded into single line the matter what how lengthy it is, so to make it readable we made use of a sed script to format it (probably we should have used gnu indent)
  4. The other includes are added to the formatted file
  5. The final file is the one that is included in the build and marked as read only to prevent editing.
  6. Encountered bugs are fixed in the original file not the expanded one (a down side of the indirection)


eclipse
Eclipse provide nice integration/wrapping to GNU tool chain. Adding the pre mentioned indirection in automated fashion to a CDT managed C++ project is described in the following steps

  1. Write the following to a shell script gen.sh and put it in the src root directory
    ## Announcing it to the console
    echo Generating the Interpreter

    ## Stepping up to the src root directory to
    cd ..

    ## Removing the old file
    rm ExecutionEng.cpp

    ## Preprocessing
    gcc -E -P -CC -ointerpreter-1.cpp interpreter.cpp

    ## formatting: replacing each ; by ;\n
    ## ps: you can use gnu indent instead
    sed -e 's/;/;\n/g' interpreter-1.cpp > interpreter-2.cpp

    ## Adding other includes to the final output
    echo \#include\"ejvm.h\" > ExecutionEng.cpp
    echo \#include\"log.h\" >> ExecutionEng.cpp
    cat interpreter-2.cpp >> ExecutionEng.cpp

    ## Attributing the generated file as Read Only
    chmod u=+r ExecutionEng.cpp

    ## Removing intermediate files
    rm interpreter-1.cpp interpreter-2.cpp

  2. Add the script as a prebuild operation in the project build process


  3. To enforce the generation use Build all or Clean from project menu

0 comments: