Search                        Top                                  Index
HELP MACRO                                     Steven Hardy, January 78
                                         Updated Aaron Sloman, Sept 1990


The word "macro" is used to define macros, i.e. pieces of text that are
rearranged by the compiler. It can be used in two ways:
    1) in macro definitions and
    2) in variable declarations.

         CONTENTS - (Use <ENTER> g to access required sections)

 -- Macro definitions
 -- Variable declarations
 -- Non-procedure values for macro identifiers
 -- A macro with a list as value
 -- Formal parameters in macro definitions
 -- Tracing macros
 -- Defining syntax words
 -- WARNING: macros can be confusing
 -- Related documentation

-- Macro definitions --------------------------------------------------

A macro definition looks just like a normal procedure definition, except
that the word MACRO occurs after the *DEFINE. For example:

    define macro swap;
        vars x y;
        itemread() -> x;
        itemread() -> y;
        x, ",", y, "->", x, "->", y;
    enddefine;

The name of the macro (in this case SWAP) is specially marked (see HELP
*IDENTPROPS) as a macro rather than an ordinary procedure.  When the
compiler reads the name of a macro it immediately calls the procedure.
This procedure may read things from the input stream (perhaps using
*ITEMREAD) and the results of the macro call are inserted into the input
stream in place of the macro name and items read.
Thus:

    swap a b;

is equivalent to

    a, b -> a -> b;

Any POP-11 word may be used as a macro name provided it has not already
been declared as an ordinary variable or procedure name.  Once used as a
macro a word cannot later be used as an ordinary variable without being
explicitly reintroduced by a vars statement or being cancelled (see HELP
*VARIABLES, *CANCEL).


-- Variable declarations ----------------------------------------------------

A word can be declared as a macro name without a value being immediately
assigned to it. This is achieved by using the word MACRO in the *VARS
statement. So the piece of program:

    define macro x;
    .........
    enddefine;

is roughly equivalent to:

    vars macro x;
    procedure <.....> endprocedure -> nonmac x;

Note the use here of a procedure introduced without a name (see HELP
*PROCEDURE) and the use of *NONMAC to indicate that in the second line
the word X is not to trigger off the operation of a macro.


-- Non-procedure values for macro identifiers -------------------------

If a word declared as a macro name turns out not to have a procedure as
its associated value, it is treated just like a procedure that always
produces that value as its result. That is, when the compiler hits the
word, it just adds the value to the front of the input stream. For
instance, supposing that "pi" were not already a built in Pop-11
identifier, you could do:

    vars macro pi = 3.141593;

is a slightly more concise way of getting the effect of:

    define macro pi;
        3.1416
    enddefine;

This is different from:

    vars pi; 3.1416 -> pi;

The difference is that if you have a program with *PI defined as this macro,
the compiler will effectively substitute the number 3.1416 for every
occurrence of the word PI in the program. So the procedure:

    define circle_area(radius);
        pi * radius * radius
    enddefine;

would be saying "to find the area of a circle, multiply 3.1416 with the
square of the radius". If PI was an ordinary variable, it would say
instead "to find ..., multiply the value of the variable PI with the
square of the radius" (and there would be nothing to stop the value of
PI changing between calls of CIRCLE_AREA). So the difference is that in
the macro case the looking-up of the value is done while the program is
being loaded, and not while the program is being run.

I.e. macros are substituted at "compile time" not at "run time".


-- A macro with a list as value ---------------------------------------

If the value associated with a macro is a list, the compiler puts all
the elements of the list individually on the front of the input stream,
rather than just considering the list as a single item. For instance,
each time the macro

    vars macro debug;
    [if debugging then database ==> endif;] -> nonmac debug;

is used, a conditional statement will be inserted into the program. This
statement has the effect that, when the program is running, if the
variable DEBUGGING has a non-FALSE value then the *DATABASE will be
printed out at this point.


-- Formal parameters in macro definitions -----------------------------
Macros created with DEFINE can have formal parameters. These are set by
calling *ITEMREAD the appropriate number of times before invoking the
macro. Thus

    define macro swap x y;
    .............
    enddefine;

is equivalent to:

    define macro swap;
        vars x y;
        itemread() -> x;
        itemread() -> y;
        .............
    enddefine;

So the parameter mechanism  should not be used for macros which may
themselves read in macros, but don't want to 'expand' them. Instead, use
*READITEM, which just reads text items off PROGLIST without expanding
macro items. (See HELP *PROGLIST, *ITEMREAD and *READITEM).


-- Tracing macros -----------------------------------------------------

POP11 MACROS can be traced. If the macro foo is traced, it will change
foo so that when it runs it shows the text is is creating.
    (See HELP *TRACE)


-- Defining syntax words ----------------------------------------------

In POP11, the format DEFINE SYNTAX can be used more effectively for some
purposes than defining a macro. (See HELP *SYNTAX, *DEFINE)

For examples of the use of SYNTAX and MACRO to extend the POP11
language, look at the following library files, using SHOWLIB:

        SHOWLIB *SYNONYM
        SHOWLIB *FOREACH
        SHOWLIB *FOREVERY
        SHOWLIB *SWITCHON


-- WARNING: macros can be confusing ------------------------------------

Macros can be defined to create new constructs that are misleading
because they look like procedure calls but are not really. For example
a macro "foo" could be defined that used syntax like

    foo(x)

to produce some instructions that depend on x. For example it might
translate into something like

    x + 1 -> x;

This would make it look as if -foo- is a procedure. However using it as
a procedure could cause problems, for example if you tried to give it as
an argument to -applist-.

For this reason, it is important to take care when defining new macros
(or syntax words) that the resulting constructs do not lead to confusion
and programs that are hard to maintain, especially when programs are
written as part of a large project that where code may have to be
maintained and debugged by someone other than the author.

There are several ways of doing this. One is to make it clear that a
special syntactic construct is involved by having separate opening and
closing brackets, as in

    foo <exprssion> endfoo

Another is to define the macro (or syntax word) to use a form that would
not normally be legal Pop-11, as in

    foo x

(which would normally produce a "MISSING SEPARATOR" error, unless "foo"
was defined as an infix operator.)

Another is to use upper case to indicate that something special is going
on, as in

    FOO(x)

Use of upper case to draw attention to macros is common among C
programmers, for this reason.


-- Related documentation ----------------------------------------------

HELP *IDENTIFIERS - introduction to identifiers
HELP *IO          - overview of I/O related documentation
HELP *WORDS       - an overview of how words are formed in POP-11
REF  *IDENT       - details of POP-11 identifiers
REF  *POPSYNTAX   - details of the syntax of POP-11
REF  *PROGLIST    - details of proglist
REF  *WORDS       - details of word construction and related items

REF  *GENSYM      - generating words, e.g. for variable names
REF  *sysNEW_LVAR - generate temporary working local variables.
REF  *VMCODE      - facilities available for syntax procedures
                    (For experts only!)

HELP * INLINE     - define form for creating macros that perform textual
                    rewrites using parameters - much like the C
                    pre-processor directive #define.

HELP * FORM       - a library for conveniently defining new syntax
                    forms

HELP * DEFINE_FORM - Syntax for defining new define ... enddefine syntax
                    constructs.

--- C.all/help/macro -----------------------------------------------------
--- Copyright University of Sussex 1991. All rights reserved. ----------