5 MACROS
5.0 The Macro Facility
The macro facility in GIN can prove confusing to the newcomer,
since it has a superficial similarity to the macro facility in
PLAN which conceals a considerable difference in the usefulness
of the two kinds of macro.
In a GIN macro the source lines which may be present are almost unrestricted. The exceptions are all, as far as possible, present because there is no reasonably convenient way of avoiding them. A macro can produce:
- Several source lines generated from one
- A part or the whole of a segment
- A part or the whole of a mend
- An interlude
- Any combination of the above.
For example, in GEORGE source the BXE macro simulates the PLAN
macro of the same name, and is perhaps the kind of thing a
new user expects a macro to be. Many macros are used to
provide a simple way of causing the compiled program to
execute some function, simple or complicated, and these can
expand in situ or contain a call of an appropriate subroutine.
The user need not know how the macro works, he need only write
down its name and parameters in the appropriate place.
Moreover, if the definition of the macro requires editing this
can be done once leading to the same changes occurring
throughout the program, without any need for the people using
the facility concerned to know what is happening.
At a further level we can consider the RESET macro which is listed in Section 10.6.1. This expands to an interlude which GIN compiles and then enters; the interlude will at various times call GIN routines to perform various functions, and alters the information stored by the compiler. The DUMP macro likewise consists mainly of an interlude, but it also allows an output tape to be opened and positioned appropriately, and a #DUMP directive is included to dump GIN and its program file and workfile. A group of macros such as NOJUGG and HLSOFF exist which make predetermined changes to the compiled program by mending known places in known segments. Only a brief idea can be given of the variety of uses that can be made of macros, and the user should use his imagination to produce efficient macro coding.
5.1 Macro Definitions
Macro definitions are stored by GIN in the workfile, and they
may be presented at any time after the #CORE directive has been
read.
A macro definition consists of a series of source records
enclosed between the directives #MACRO and #NORMAL, It may
contain anything except the directives: #GO, #MACRO and
#READ. Each macro has a name, consisting of a letter followed
by 0 to 7 alphanumeric characters. A macro name must be unique,
and its first four characters must be different from the first
four characters of any instruction mnemonic. Thus LD, LDX2, BXU
are permissible; LDXC, NULLRING, SUSBAT are wrong. The macro
name is given as the parameter to #MACRO.
Except for checking for the directives mentioned above, a
macro definition is not validated while it is being stored.
The reason why #GO is not permitted has been forgotten. #MACRO
is not allowed because it is thought more likely to be present
through the accidental omission of #NORMAL than by design. #READ is prohibited because the internal alterations to
GIN to cope with placing it in the right position
in the macro hierarchy were considered too complicated.
At any point in a macro definition a formal parameter may be
included. A formal parameter consists of the character %
followed by a letter. (It is not possible to use % for any
other purpose within a macro definition). When the macro is called,
%A will be replaced by the first actual parameter in the call
line, %B by the second, and so on.
The absence of restrictions on what may appear on a line allows directives, macro calls, labels, or even erroneous lines to be stored. See especially the #SKIP group of directives in Section 3.7. Storing erroneous lines can be useful for parameter validation. Suppose for example that %B is expected to be an expression whose value does not exceed that of the identifier AMAX: then the following coding would cause the parameter to be checked:
#SKI %B>AMAX$AMAX ! PARAMETER OUT OF RANGE: %B #SKI %B>AMAX$AMAX<1$1 ( body of macro )
It is beneficial to the efficiency of compilation that macro definitions should be so arranged as to occupy the minimum space in the workfile, and to be easily accessible. GIN will do this to a certain extent; any comment beginning with [ will be discarded before storage, and wherever two or more spaces occur adjacent to one another only one space will be stored. These alterations make no difference to the compiled code except that character texts containing repeated spaces will be compressed. The following rules should be followed:
- The facility to start comments with “# ” should not be used in macro definitions, as such comments will be stored.
- Free-standing labels should not be used except to label the line following the macro - remember that there is no need for the instruction (or whatever it may be) that is labelled to start in any particular column of the source record.
- Wherever possible, use multi-stored-word line formats, e.g. label data, data, data
GIN keeps macros on a number of lists or chains, a randomising algorithm being
used to choose the chain each macro belongs to. The more chains are used
the faster compilation will be, until the point is reached where waste of
space cuts down the core available for other uses. It is recommended
that the number of chains (adjusted by the #CHAINS directive) should be roughly
one-third of the number of macros.
It is important to remember that no directives inside a macro will take
effect while it is being stored. Thus, for example, it is not possible
to skip a part of a definition, although it is possible to skip the whole
of one. Similarly, such directives as #PAGE or #LIST will take effect
when the macro is called and not when it is stored.
5.2 Macro Expansion
A macro is called by writing its name, preceded by a space which may (in a segment) be preceded by a label, on any source line. Macro calls are not permitted before the #CORE directive has been read. Whenever a character string starting with a letter is found in such a position, an attempt is first made to match its first four characters with an instruction mnemonic. If this attempt is successful the instruction will be compiled provided that it is within a segment, mend or interlude. If the name is not recognised as a mnemonic, GIN attempts to match the first eight characters of the string with a macro name. If this is impossible the line is in error; otherwise, GIN goes on to store the actual parameters (if any) following the macro name. Subsequent source records will be extracted from the stored macro definition until the end of it is reached, actual parameters will be substituted for any formal parameters, and the resulting records will be compiled in the normal way.
PARAMETERS
The first actual parameter of a macro call (which will
replace the formal parameter %A) is separated from the
macro name by one or more spaces. Other actual parameters
may follow, consecutive parameters being separated by
commas. The last parameter is terminated by the end of
the line or by “[” introducing a comment.
An actual parameter may be null; this will be the case if
there are no non-space characters between the macro name
and the first comma for %A, or between consecutive commas,
or between the last comma and the end of the line (or “[”).
It will also be null if it is the n'th parameter and there
were less than n parameters on the source line. Wherever
the actual parameter corresponding to a formal parameter
is null, the formal parameter is removed whenever it
occurs in a macro source line, and nothing is inserted in
its place. This is a special case of the rules about spaces
given below.
Any leading or trailing spaces in an actual parameter are
removed before it is stored, and will not be inserted in
the source line.
The treatment of internal spaces in parameters depends on the version of GIN in use:
GIN 503, GIN504 | Any series of consecutive spaces is stored as one space. |
GIN 502 and earlier versions | All internal spaces are stored. |
GIN 510 and later versions | All internal spaces are stored. |
GIN does not give any indication if an actual parameter is used which does not correspond to a formal parameter in the macro definition. Some examples of macro parameters follow:
MACRO | In each case all the MACRO ,, | parameters are null MACRO , ,, | | MACRO FRED | FRED replaces %A | MACRO ,FRED | In each case FRED (with no spaces) MACRO ,FRED, | replaces %B, and %A and %C MACRO , FRED , | are null | FSFILE 3,6,FILESTORE 1 | In GIN 503 and 504, %C is replaced | by FILESTORE 1. In other versions, | %C is replaced by FILESTORE 1
The macro defined by
#MACRO PAIR +K%A #HAL L%A,K%B%A #NORMAL
could be called by
PAIR CHAPTER,2
and will expand to
+KCHAPTER #HAL LCHAPTER,K2CHAPTER
LOCAL IDENTIFIERS WITHIN MACROS
As mentioned in the description of identifiers, it is possible to use
local identifiers as labels within macros. Any label set up in this
way will be available within the macro and any other macros within
it, but not otherwise. Thus it is possible to use a local label within
a macro without any clash with other uses of the same macro in the same
segment. It is also possible to refer within a macro to locals defined
outside it.
To avoid clashes with other labels in segments, it is recommended that
local labels in macros should start with M followed by the name of the
macro, and that no local label outside a macro should start with M.
A local identifier which is used as a label within a macro will be freed at the end of the macro. Universal identifiers, and local identifiers defined by #DEFINE and #OPTIONAL, are not freed; they can be used anywhere in the compilation or in the segment respectively. This can be made use of: see particularly the fourth example in Section 10.3.
RECURSION AND NESTING
It is possible for source lines produced during the expansion of a macro to be calls of the same or any other macro. GIN imposes no strict limit on the extent to which this may be done. However, each level of macro nesting causes more space within GIN to be taken up by the parameter stack, and it is possible to run out of space. The amount of space available is 2500 words (unless changed by the #LOCAL directive) less whatever is used for local identifiers; each macro nesting level takes anything from 5 to 40 words, depending on the number of parameters and their total length. If GIN runs out of space because of excessive macro nesting or the use of a very large number of local identifiers, it will display “CI” print a postmortem of itself and delete “AB”. Whenever this happens, the person who wrote the macro being compiled should check
- whether the macro is in an endless loop, and
- whether it can be rewritten to use less space.
If neither of these apply, the #LOCAL directive can be used to provide
more room.
In estimating the amount of room required it should be remembered that versions up to GIN510 do not re-use the space occupied by local identifiers which are freed by #FREE or at the end of a macro. GIN511 will be much more economical in this respect.
ODD NOTES
The following assortment of notes and suggestions may help to produce more efficient macros:
- Further macro examples are given in Section 10.3.
- It is sometimes more convenient to have two small macros rather than one large one.
- When nesting #SKIP, #STRING and so on, the first skip should be that most likely to take effect, with unusual combinations being dealt with by the inner skips.
- Programmers do not like counting long strings of commas; if some parameters are more likely to occur than others, %A should be the most frequent (possibly a mandatory parameter), %B the next most frequent, and so on.
- It is not possible to have commas or “[” characters in parameters.
- No line resulting from parameter substitution may exceed 72 characters. GIN will truncate any such line, and in some versions it will not be error-flagged.
- Remember that when a recursive macro uses an expression like %A+1 you may end up with %A+1+1+1+…..+1 and fall off the end of the line. GIN can only call parameters by name, never by value.
THE #EXIT DIRECTIVE
This subsection describes a new directive which is included in GIN 511.
The #EXIT directive allows the expansion of a macro to be terminated
prematurely. It may be used with a parameter which is an expression
containing no forward references, in which case it will be ignored
if the expression is non-zero. Alternatively, it may be without a
parameter, in which case it is implemented unconditionally.
When #EXIT is implemented, all local labels defined earlier in the
macro than the #EXIT are freed, and the next line to be compiled is
the one following the macro call (which can be in a higher-level
macro).
Thus, the following pairs of macros are equivalent:
#MAC - #MAC - #SKI esxpression #EXI expression ( other source lines other source lines ) #NOR #NOR
but the version using #EXIT will compile more efficiently, as there will be no scanning of the rest of the macro for a right-hand parenthesis.
5.3 GIN's macro facility compared with PLAN
The rules in PLAN which concern macros are very much more restrictive than those in GIN, and the following comparative list may prove helpful.
GIN | PLAN |
---|---|
A macro name is up to 8 characters long. | A macro name is up to 5 characters long. |
Any directive (with 4 exceptions) may be used in a macro definition. The definition is terminated by #NORMAL. | The macro definition is terminated by any directive. |
Labels may be defined within a macro (local labels so defined are unavailable outside the macro). | Labels may not be defined in a macro. |
There is no need to specify in the definition which parameters must be present. | The “alphabetic parameters” must be given in the macro definition. |
In the definition a parameter identifier may be placed adjacent to other characters, and the parameter will be so placed when the macro is expanded. | There is no provision for parameter concatenation; a parameter must (apparently) represent the whole of a field of a source line. |
It is possible to nest macros to a substantial depth. | Macros may only be nested to depth 1. |
There is no provision for double-accumulator macros. | A macro may use one or two accumulators. |
The following examples may be helpful:
GIN does not have the BXU macro, exactly by but it can be simulated by
#MAC BXU TXU %A BCS %B #NOR
Here %A represents the accumulator and operand of TXU. corresponding PLAN definition would be
#MACRO BXU A C,B TXU A C BCS B (any major directive)
where A is the accumulator of TXU and C its operand.
The following are good GIN macro definitions:
#MAC PAIR +K%A #HAL +L%A,+K%B%A #NOR #MAC LASTREKA M2LASTREKA SMO %B LDEX 0 0(%A) BZE 0 M1LASTREKA ADS 0 %B BRN M2LASTREKA M1LASTREKA #NOR
The latter in PLAN would be:
#MACRO LSTKA A,B SMO B LDEX 0 0(A) BZE 0 *+3 ADS 0 B BRN *-4
where if more instructions needed to be inserted the branch instructions would also have to be altered.
#MAC CHTEND #SKI 34?+0?+M+0]+1 ( #DEF 0?=0?+1 CHTEND ) #NOR
This contains nothing which would be possible in PLAN. in this macro M has already been set up by another macro, such that 34?+0?+M+0] is the contents of the word which is next to be written to; #DEF 0?=0?+1 causes the following word to be stepped to; and the whole macro searches for a word containing -1 and stops recursing when it reaches one.