Preprocessor
============

This is a very primitive line based preprocessor, for times when using
a C preprocessor isn't an option.


Instructions
------------

Any line starting with a hash # and a letter is considered to be a
preprocessor instruction. Other lines starting with a hash are ignored
as comments.

The following preprocessor instructions are recognised.

   #define VARIABLE
   #define VARIABLE STRING
   #undef VARIABLE
   #ifdef VARIABLE
   #ifndef VARIABLE
   #if VARIABLE
   #if !VARIABLE
   #if VARIABLE==STRING
   #if VARIABLE!=STRING
   #else
   #elifdef VARIABLE
   #elifndef VARIABLE
   #elif VARIABLE
   #elif !VARIABLE
   #elif VARIABLE==STRING
   #elif VARIABLE!=STRING
   #endif
   #error STRING
   #include FILENAME
   #includesubst @VAR@FILENAME
   #expand STRING
   #literal STRING
   #filter FILTER1 FILTER2 ... FILTERn
   #unfilter FILTER1 FILTER2 ... FILTERn

Whitespace is significant -- for instance, '#define TEST foo' is not
the same as '#define TEST foo '. The first defines TEST to be a three
character string, the second defines it to be four characters long.

The conditionals (#ifdef, #ifndef, #if, #else, #elifdef, #elifndef,
#elif, #endif) can be nested to arbitrary depth.

An #else section can be followed by an #else section, as in:

   #if 1
      used
   #else
      not used
   #else
      used again
   #endif

Whether this is wise or not is left up to the reader to decide.

The #elifdef, #elifndef, and #elif instructions are equivalent to
#else instructions combined with the relevant conditional. For
example,

   #ifdef foo
      block 1
   #elifdef bar
      block 2
   #endif

...could be written as:

   #ifdef foo
      block 1
   #else
   #ifdef bar
      block 2
   #endif
   #endif

#else blocks need not come last, which can lead to some odd
constructs.

   #ifdef foo
      included if foo is defined
   #else
      included if foo is not defined
   #elifdef bar
      included if foo is defined and bar is defined
   #else
      included if either foo or bar are not defined
   #endif

Note in particular the following holds:

   #if 1
      always included
   #elif 1
      never included
   #else
      always included
   #endif

That is to say, #else is relative to whether the previous conditional
was included _only_. It isn't an "and" relationship with previous
conditionals. This is arguably a bug.

The #error instruction stops execution at this point with a fatal
error. The error message will include the given STRING.

The #include instruction causes the specified file FILENAME to be
recursively processed, as if it was inserted at the current position
in the file. This means conditionals can be started in one file and
ended in another, although this practice is strongly discouraged.
There is no predefined limit to the depth of #includes, and there is
no restriction on self-inclusion, so care should be taken to avoid
infinite loops.

The #includesubst instruction behaves like #include, except that any
variables in @ATSIGNS@ are expanded, like the substitution filter.

The #expand instruction will print the given STRING with variable
substitutions. See the substitution section below.

The #literal instruction will print the given STRING with a newline,
with absolutely no other fixups, guaranteed. This can be used to
output lines starting with a #, which would otherwise be stripped out
as comments.

The #filter instruction enables the specified filters. You can turn
off filters using #unfilter. See the Filters section below.


Variables
---------

Variables consist of any alphanumeric string. They are defined using
the -D command line argument and the #define instruction.

To define all environment variables, so that you can use __HOME__,
etc, with #expand, use the -E argument. Note that arguments that use
non-word characters (like "!") are not included. (In particular,
cygwin is known to include all kinds of weird characters in its
environment variables.)

Two special variables are predefined, FILE and LINE. They can be
passed to #define and #undef, but FILE is automatically redefined at
the top of each file, and LINE is increased by one at the start of
each line.

The variable '1' is predefined with value 1. The variable '0' is not
defined. This allows constructs such as

   #if 0
   ...
   #endif

...to be used to quickly comment out large sections. Note, however,
that these are simply variables, and can be redefined. This is
strongly discouraged.


Substitution
------------

In any line starting with the instruction #expand, variable names
contained between double underscores, like __THIS__, are expanded to
their string values, or the empty string if they are not defined.

For example to print the current filename:

   #expand <!-- This file is automatically generated from __FILE__ -->

Normal lines are not affected.

See also the substitution filter below.


Filters
-------

The following filters are supported:

   emptyLines
     Strips blank lines from the output.

   slashslash
     Strips everything from the first two consecutive slash (/)
     characters until the end of the line.

   spaces
     Collapses sequences of spaces into a single space.

   substitution
     Replaces occurances of "@foo@" by the value of the variable
     "foo". If @foo@ is not defined, the preprocessor will terminate
     with a fatal error.

   attemptSubstitution
     Replaces occurances of "@foo@" by the value of the variable
     "foo". If @foo@ is not defined, the empty string is used instead.

Filters are run in alphabetical order, on a per-line basis.


Command Line Arguments
----------------------

Syntax:
   preprocessor.pl [-Dvariable[=value]] [-E] [-Ffilter]
                   [-Ifilename] [-d] [--] filenames...

-Dvariable
   Set variable to 1 before processing the files.

-Dvariable=value
   Set variable to value before processing the files.

-E
   Define all environment variables.

-Ffilter
   Enables the specified filter.

-Ifilename
   Include filename before any other files.

-d
   Run through the files on the command line, listing the files they
   depend on given the specified environment variables and filters.
   Doesn't recurse into those files. The output is given as one
   dependency per line, and filenames are given relative to the
   current directory.

--line-endings=type
   Set the type of line endings to use. "type" can be either "cr",
   "lf", or "crlf". The default is whatever your platform uses for
   perl's "\n" character.

--
   Indicates the end of non-filename arguments.

-
   Indicates that input should come from standard input.

If no filenames are provided, standard input is used instead. If many
files are provided, they are processed sequentially, as if they were
one big file. -I files are handled before the other files, in the
order specified, but after handling any -D, -E, -F, and -d arguments.


Contact Details
---------------

Feel free to e-mail me if you have any questions:
Ian Hickson <preprocessor@software.hixie.ch>
