cpphs is a liberalised re-implementation of cpp(1), the C pre-processor, in and for Haskell.
Why re-implement cpp? Rightly or wrongly, the C pre-processor is widely used in Haskell source code. It
enables conditional compilation for different compilers, different versions of the same compiler, and
different OS platforms. It is also occasionally used for its macro language, which can enable certain
forms of platform-specific detail-filling, such as the tedious boilerplate generation of instance
definitions and FFI declarations. However, there are two problems with cpp, aside from the obvious
aesthetic ones:
For some Haskell systems, notably Hugs on Windows, a true cpp is not available by default.
Even for the other Haskell systems, the common cpp provided by the gcc 3.x series is changing
subtly in ways that are incompatible with Haskell's syntax. There have always been problems with,
for instance, string gaps, and prime characters in identifiers. These problems are only going to
get worse.
So, it seemed right to attempt to provide an alternative to cpp, both more compatible with Haskell, and
itself written in Haskell so that it can be distributed with compilers.
cpphs is pretty-much feature-complete, and compatible with the -traditional style of cpp. It has two
modes:
conditional compilation only (--nomacro),
and full macro-expansion (default).
In --nomacro mode, cpphs performs only conditional compilation actions, i.e. #include's, #if's, and
#ifdef's are processed according to text-replacement definitions (both command-line and internal), but no
parameterised macro expansion is performed. In full compatibility mode (the default), textual
replacements and macro expansions are also processed in the remaining body of non-cpp text.
Working Features:
#ifdef simple conditional compilation
#if the full boolean language of defined(), &&, ||, ==, etc.
#elif chained conditionals
#define
in-line definitions (text replacements and macros)
#undef in-line revocation of definitions
#include
file inclusion
#line line number directives
\n line continuations within all # directives
/**/ token catenation within a macro definition
## ANSI-style token catenation
# ANSI-style token stringisation
__FILE__
special text replacement for DIY error messages
__LINE__
special text replacement for DIY error messages
__DATE__
special text replacement
__TIME__
special text replacement
Macro expansion is recursive. Redefinition of a macro name does not generate a warning. Macros can be
defined on the command-line with -D just like textual replacements. Macro names are permitted to be
Haskell identifiers e.g. with the prime ` and backtick ´ characters, which is slightly looser than in C,
but they still may not include operator symbols.
Numbering of lines in the output is preserved so that any later processor can give meaningful error
messages. When a file is #include'd, cpphs inserts #line directives for the same reason. Numbering
should be correct even in the presence of line continuations. If you don't want #line directives in the
final output, use the --noline option.
Any syntax errors in cpp directives gives a message to stderr and halts the program. Failure to find a
#include'd file produces a warning to stderr, but processing continues.
You can give any number of filenames on the command-line. The results are catenated on standard output.
-Dsym define a textual replacement (default value is 1)
-Dsym=val
define a textual replacement with a specific value
-Ipath add a directory to the search path for #include's
-Ofile specify a file for output (default is stdout)
--nomacro
only process #ifdef's and #include's,
do not expand macros
--noline
remove #line droppings from the output
--strip
convert C-style comments to whitespace, even outside
cpp directives
--hashes
recognise the ANSI # stringise operator, and ## for
token catenation, within macros
--text treat the input as plain text, not Haskell code
--layout
preserve newlines within macro expansions
--unlit
remove literate-style comments
--version
report version number of cpphs and stop
There are NO textual replacements defined by default. (Normal cpp usually has definitions for machine,
OS, etc. These could easily be added to the cpphs source code if you wish.) The search path is searched
in order of the -I options, except that the directory of the calling file, then the current directory,
are always searched first. Again, there is no default search path (and again, this could easily be
changed).