Using macros

Macros are used by calling them, just like Algol 68 procedures. The only restriction on the actual parameters of a macro is that any parentheses should be balanced. Furthermore, if you want to include a comma in an actual parameter, it should be surrounded by parentheses because the actual parameters, if there are more than one, are themselves separated by commas. The actual parameters can include or consist of calls to other macros.

If a declarative macro is called more than once, the second and subsequent calls are replaced by SKIP instead of the macro body.

Because each token is considered in turn, the following definitions and call will produce an error message:-

@m arg = (p)
@m identity(p1) = p1
@a identity ## arg

The ## between identity and arg serve to separate the two words into two lexical entities because otherwise they would be regarded as part of a single identifier. The error is caused by identity being expanded first: identity requires a parameter pack, but the next token is not (, but arg which has not yet been expanded. Only when the macro call has been expanded will arg be expanded. This will produce the error message

! Error: call of identity not followed by "(".

This brings us to a useful wrinkle associated with macro definitions and calls.

In the next macro, the body of the macro contains two identifiers which are split into two lexical tokens by ## enabling the actual parameters, provided that they are just identifiers, to be used to construct two identifiers.

@m mcheck col(col1,col2) =@/
   IF NOT q##col1 OR NOT q##col2
   THEN@/
      []CHAR s="fl set object color";
      put(outf,
          ("   ",s,"(",obj ident,",",
           CA mov(gen##col1),",",CA mov(gen##col2),");",
			  newline));
      add mac(s)
   FI

Sian Mountbatten 2012-01-05