Fudging Conditionals

fudgingconditionals

As a macro preprocessor, the facility that FunnelWeb most obviously lacks is a conditional facility (such as C's #ifdef). It might, therefore, come as a surprise to know that the first version of FunnelWeb actually had a built in conditional facility. The facility allowed the programmer to specify a construct that would select from one of a number of macro expressions depending on the value of a controlling macro expression.

In three years the construct was never used.

The reason was that conditional constructs could be fudged nearly as easily as they could be used. Because of this, the inbuilt conditional feature was removed in the current version of FunnelWeb. Not only did this simplify the program, but is also allowed recursive macros to be detected through static analysis rather than during macro expansion.

There are two basic ways to fudge a conditional. First, the comment facility of the target programming language may be employed. For example, in Ada,Ada comments commence with – and terminate at the end of the line. Using this fact, it is easy to construct macros that can be called at the start of each target line and which turn on and off the lines so marked by defining the macro to be the empty string (ON) or the comment symbol (–) (OFF). For example:

@A@<Debug Macro@>

The following macro determines whether debug code will be included in the
program. All lines of debug code commence with a call to this macro and so
we can turn all that code on or off here by defining this macro to be either
empty or the single-line comment symbol (\p{--}). Note the use of a
quick macro name.

@$@#D@M==@{@}     @! Turns the debug code ON.
@! Use this definition to turn the debug code OFF: @$@#D==@{--@}

... then later in the file...

@$@<Sloth incrementing loop@>==@{@-
while sloth<walrus loop
   @#D assert(sloth<walrus,"AWK! sloth>=walrus!!!!!!!");
   @#D assert(timer<timermax,"AWK! timer>=timermax!!!");
   inc(sloth);
end loop@}

The other way to fudge a conditional is to define a macro with a single parameter. A call to the macro is then wrapped around all the conditional code in the program. The macro can then be defined to present or ignore the code of its argument. For example:

@A@<Debug Macro@>

The following macro determines whether debug code will be included in the
program. All debug code is wrapped by a call to this macro and so
we can turn all the debug code on or off here by defining this macro to be
either empty or its parameter.

@$@#D@(@1@)@M==@{@1@}     @! Turns the debug code ON.
@! Use this definition to turn the debug code OFF: @$@#D@(@1@)==@{@}

... then later in the file...

@$@<Sloth incrementing loop@>==@{@-
while sloth<walrus loop
   @#D@(assert(sloth<walrus,"AWK! sloth>=walrus!!!!!!!");
        assert(timer<timermax,"AWK! timer>=timermax!!!");@)
   inc(sloth);
end loop@}

In languages that allow multi-line comments (C with /* and */), comments can be used to eliminate the conditioned code rather than absence. For example:

@$@#D@(@1@)@M==@{/* @1 */@}    @! Comments out the debug code

(Note: If this example were ever actually used, the programmer would have to be careful not to place comments in the argument code. Nested comments in C are non-portable.)

The parameterized macro idea can be generalized to support the choice of more than one mutually exclusive alternative. For example:

@A This module contains non-portable code that must execute on Hewlett
Packard, Sun, and DEC workstations. The following FunnelWeb macro is
defined to choose between these three. The first parameter is the HP code,
the second is the Sun code, and the third is the DEC code. Whichever
parameter constitutes the body of this macro determines which
machine the code is being targeted\note{Dictionary says only one t
in targeted.} for.

@$@<Machine specific code@>@(@3@)@M==@{@1@}  @! Configure for HP.

...then later in the file...

@<Machine specific code@>@(
@"get_command_line(comline)@"           @, @! HP.
@"scan_command_line(128,comline);@"     @, @! Sun.
@"dcl_get_command_line(comline,256);@"  @) @! DEC.

Of course, this could also be performed using three separate macros. The main advantage of using a single macro is that the mutual exclusivity is enforced. Also, because FunnelWeb ensures that the number of formal and actual parameters are the same, this method lessens the chance that a machine will be forgotten in some places.