For implementing complex procedures, it is sometimes useful to encapsulate
individual subtasks into separate macros, which can be developed
and tested independently, and which might sometimes be used as stand-alone
macros for performing just the corresponding subtask. The macro which performs
the complete procedure can now perform these subtasks by
using ``call macro'' commands of the form ~<
subtask p1 p2 p3 ... .
When a ``call macro'' command is encountered, the processing of the current macro is temporarily suspended and the called macro is executed as a subroutine of the calling macro. Once the execution of the called macro is terminated, the calling macro resumes operation at the line following the ``call macro'' command. The calling of sub-macros is not restricted to a single level, but it can be applied to as many levels as are required, thus allowing the implementation of an arbitrary hierarchy of macro calls. Even recursive invocations of the same macro are allowed.
While the principle of hierarchical macro invocation is straight forward, it is important to look at what exactly happens to the register and parameter values when one macro calls another macro. Since each macro uses the registers differently, it is important to avoid conflicts, e.g. as would result if a called macro would modify register values that the calling macro still needs for its continuation. Also a calling macro needs to pass argument values to the called macro, and, upon termination, the latter may need to pass back return values. In the remaining part of this section, we will look at these questions in detail.
In the implementation of hierarchical macro calls, registers are implemented in such a way that each macro is provided with its own, private set of registers. This implies that a macro does not need to worry about the register usage of the macros that it calls. Even if an invoked macro uses the same registers for storing its own information, the calling macro will still find its own register values unchanged upon the return of the called macro. This way, conflicting register usage between different macros is impossible.
When a macro is called by another macro, its (private) register values are initialized to the current register values of the calling macro. This allows that parameters can be passed from the calling to the called macro via the registers (in addition to the parameters that are specified on the call macro command itself). On the other hand, this also implies that a macro should never assume that the registers are initialized to zero (or blank for text registers), but always initialize the used registers explicitly.
When macro needs to pass a return value back to the calling macro, it can
do so by storing the return value into the text register t9
. As
an exception to the rule explained above, the t9
register is implemented
as a global register. Therefore, all macros share the same value of t9
,
and a change to this register made in a lower level macro, is visible to
the macros at the upper levels. If more than one return value are to be passed
back, these can be assembled into the text register (which can hold up to
124 characters) and be disassembled back into its parts in the calling macro.
t9
.