The Preprocessor

The pre-processor is the first stage of the compilation process.  It works almost exactly like the C pre-processor for those C programmers out there.  It provides definitions and macros which ease both programming tasks and maintenance.

A pre-processor directive is denoted by a # being the first non-whitespace character on a line, followed immediately by the directive on the line.  A backslash (‘\’) can be used as the last character on a line to continue the definition on the next line (allowing “multi-line macros”).

Constants are defined by the the #define directive (usage: #define <symbol> <text>) and once a constant has been defined, every instance of that symbol will be replaced with whatever the body text is.  For instance, using the directive:

#define HAT_SIZE 10

will cause all instances of “HAT_SIZE” as a complete word (no partial matches) to be replaced with the text “10”.  This is useful, for instance, if for some reason in the future, you wished to change HAT_SIZE to be 12 instead of 10.  By using a #define, you can only change it in one place, not every place you might have had the number 10.

Macros are just like constants (they use the same directive even) except they may take some parameters.  Each parameter in the name, is substituted in the macro body before the entire text as a whole is replaced for the macro call.  Let’s see an example.

#define OVERJOYED          10
#define IS_HAPPY(feeling) ( (feeling) > 100 or feeling = OVERJOYED)

Now let’s use the macro.

if( IS_HAPPY(happiness) )then
debugout("I'm happy!\n");
else
debugout("I'm sad...\n");

In the above IF statement, the IS_HAPPY will actually be replaced with the following text.  Note how even the constant in the macro body is expanded and replaced properly.

if( ( (happiness) > 100 or happiness = 10 ) )then
debugout("I'm happy!\n'');
else
debugout("I'm sad...\n'');

Although, it’s not really necessary to see what the expanded text is (Indeed.  Often it’s quite ugly.) it’s shown here as an example.

A Caveat

There is one caveat when using macros however: choose your parameter names wisely.  Take the following for example.

#define WEIGHT(replica) replica[replica].byte[5]
if( WEIGHT(1234) > 10 )then
debugout("Man that's heavy.\n");

It looks fine and is syntactically correct, however, when used it expands to the following.

if( 1234[1234].byte[5] )then
debugout("Man that's heavy.\n");

Note how both instances of “replica” (the parameter name) were replaced in the macro body.  This is correct behavior of the pre-processor but not likely the intended usage (1234[1234].byte[5] makes no sense).

Summary
The pre-processor is the first stage of the compilation process.
Here’s a rundown of the directives available to the pre-processor.
This recursively includes the entire file specified as if it was actually inserted at the given location.
Define a constant.
Define a macro.
Delete the definition of this constant or macro.
Process the following code only if the specified symbol is defined.
Just like #ifdef but only process if the symbol is not defined.
If inside a conditional directive (#ifdef or #ifndef) and processing, then cease processing until an #endif is encountered.
This terminates a conditional directive (or chain of directives).

Pre-Processor Directives

Here’s a rundown of the directives available to the pre-processor.

#include “<filename>”

This recursively includes the entire file specified as if it was actually inserted at the given location.  Use with #ifdef and #ifndef to do conditional compilation.

#define <symbol> [<text>]

Define a constant.  The text is optional and is assigned the empty string if not provided.

#define <symbol>([<arg>[,<arg>...]]) [<text>]

Define a macro.  You can have 0 ore more parameters.  Note, often for longer macros it is more readable to extend them onto more than one line.  You can simply leave a backslash (‘\’) as the last character on the line to continue onto the next.

#undef <symbol>

Delete the definition of this constant or macro.  Substitutions will no longer occur.

#ifdef <symbol>

Process the following code only if the specified symbol is defined.  Be sure to end this with an #endif (with perhaps an optional #else directive).  Note that these can be nested, and each needs its corresponding #endif.

#ifndef <symbol>

Just like #ifdef but only process if the symbol is not defined.

#else

If inside a conditional directive (#ifdef or #ifndef) and processing, then cease processing until an #endif is encountered.  (Or if not processing then begin doing so.)

#endif

This terminates a conditional directive (or chain of directives).