comp.py: A preprocessor for HAL modules

OVERVIEW
========

When writing HAL modules, a large amount of boilerplate code is required
to register the pins, parameters, and functions.  "comp" (working name)
is a tool to automatically generate that code.

Here is one of the simplest useful components that can be created with
"comp":

    component charge_pump;
    option singleton yes;
    pin out bit w;
    function update nofp;
    ;;
    MODULE_LICENSE("GPL");
    FUNCTION(update) { out = !out; }

it simply creates a bit which is toggled each time its 'update' function
is called, and can be connected to the 'charge pump' watchdog pin of the
PDMX-121 and similar breakout boards.

A ".comp" file is processed with "comp.py" to produce a ".c" file:
python comp.py charge_pump.comp > charge_pump.c which must then be
compiled into a kernel module (charge_pump.ko).  With the CVS version of
emc2, this is fairly easy when using Makefile.modinc.

"comp" does not decrease the efficiency of your realtime modules: it
does not change anything about the code you write in the component's
realtime functions, it only generates the code which is run once at
startup to register the pins, parameters, and functions with emc2's HAL.


INSTALLATION
============
"comp" uses the parser module 'yapps2'.  On Ubuntu systems, the required
package can be installed with 'sudo apt-get install yapps2-runtime'.
'yapps2' is only required to process a .comp file into a .c file.

To rebuild 'comp.py', the 'yapps2' package must also be installed.


SYNTAX
======
A ".comp" file consists of a number of Declarations, followed by ";;" on
a line of its own, followed by C code implementing the module's functions.

Declarations include:
    component NAME;
    pin NAME TYPE DIRECTION;
    param NAME TYPE DIRECTION;
    function NAME [fp | nofp];
    option NAME [yes | no];

NAME is a C identifier.  When it is used to create a HAL identifier, any
underscores are replaced with dashes, so the watchdog example creates a
pin called 'charge-pump.out'

TYPE is one of the HAL types: bit, s8, u8, s16, u16, s32, u32, or float.

DIRECTION is one of 'r', 'w', or 'rw', corresponding to HAL_RD, HAL_WR,
or HAL_RD_WR.

'fp' indicates that the function performs floating-point calculations.
'nofp' indicates that it only performs integer calculations.

The currently defined options are:
    singleton (default: no)
        Do not create a 'count' module parameter, and always create a
        single object.  With 'singleton', items are named
        'component-name.item-name' and without 'singleton', items are
        named 'component-name.num.item-name' where 'num' goes from 0 to
        the module parameter 'count' (which defaults to 1)

    rtapi_app (default: yes)
        Normally, the functions 'rtapi_app_main' and 'rtapi_app_exit'
        are automatically defined.  with 'option rtapi_app no', they are
        not, and must be provided in the C code.

        When implementing your own 'rtapi_app_main', call the function
            export(char *prefix, struct state *arg)
        to register the pins, parameters, and functions for 'prefix'
        using the buffer 'arg' which was allocated with 'hal_malloc'

The result of using any other option is undefined.

C++-style one-line comments ("// ...") and C-style multiline comments
("/* ... */") are both supported in the declaration section.

CONVENIENCE MACROS
==================
In the "C" code, some convenience macros are available.

The macro
    #define FUNCTION(name) ...
properly defines the function 'name' including its return type and
argument types and names.

For each pin 'pi' or param 'pa' there is a macro
    #define pi ...
    #define pa ...
which allows the name to be used on its own to refer to the pin or
parameter.

Any of these macros may be undefined with '#undef' if desired.

EXAMPLES
========
'charge_pump.comp' (also shown above) implements a simple toggling bit
output.

'maj3.comp' implements a majority-of-3 block with optional output
inversion.

If you are using a recent CVS version of emc2, then they can be built by
changing the first line of Makefile to indicate the correct location of
'Makefile.modinc', and typing 'make modules install'.

To test 'maj3', first compile and install it.  Then, run
    .../realtime start; .../halcmd -kf test-maj3.hal
(specifying the correct path to 'realtime' and 'halcmd').  The test
creates two 'maj3' blocks, with the first one's output inverted.  Click
the "X" buttons to see the maj3 block work.  When you're done, run
    .../halcmd unloadusr all; .../halcmd unloadrt all; .../realtime stop


OPEN PROBLEMS
=============
There is nothing to help with detecting hardware and registering I/O
ports

There is no privision for per-block data that is not a HAL pin or
parameter (e.g., the 'float old' of the ddt block)
