The macro tech-tips in this issue are dedicated to the compound macro commands. Since their introduction in Release 6, these commands have become very popular with many macro writers. Today, we will look at some of their more interesting uses and by doing so, shed some light on their internal workings.
Using compound macro command to implement error tests
The compound macro commands (``~+
XlineX...Xline'') are a very
convenient way to pack several macro commands into a single line in
the macro file. This command is often used to render the macro
files more compact, but it is also particularly useful when a
condition (``~?
...'') is to be applied to more than
a single macro command. A typical example for this is the processing
needed when an error condition has been detected.
The following excerpt from macro demadjt.mac
shows how compound statements can be used to catch foreseeable errors
efficiently, using an error test followed by a single
compound command:
... 2.42 /##### create extra attribute @stmpx 2 /create attribute 4 /at segment level ~?e ~+|~/No space for extra segment attribute!|q|~$STOP @stmpx ~?e ~+|~/Extra attribute @stmpx exists already!||q|~$STOP temporary attr. used by macro DEMADJT 0 q ...The compound command combines in a single line the display of an explanatory error message, any cleaning work needed to return to the main menu, and finally a goto command branching to the end of the macro.
Substitutions in compound macro commands
Compound statements are not limited to simple dialog answers, but can
contain any combination of macro commands, except for label commands
and other compound commands.
Thus, it is possible to combine several short lines of a macro file
not containing ``~+
'' and ``~:
'' commands into a single
compound command line. The character immediately following the ``~+
''
defines the separator, which can be any character not appearing in the
lines to be combined.
However, care must be taken when combining commands which
change the value of a register values and then use it in
a substitution. All ``%
...%
'' substitutions
in a compound command are processed before its individual
commands are executed. Hence, combining the sequence
~x+1 ~/Value of X is %x%into the compound command
~+|~x+1|~/Value of X is %x%will not work as expected, since ``
%x%
'' is
substituted before the command ``~x+1
'' is executed.
In order to have the compound statement work correctly, we have
to make sure that the substitution of ``%x%
'' will not be
done at the level of the compound command, but only when the
corresponding subcommand (here ``~/Value of X is %x%
'') is
executed. This can be done by replacing the ``%
'' characters
by the substitution ``%%%
'', which will be transformed into a single
``%
'' by the substitution mechanism.
This way, the string ``%%%x%%%
''
will be replaced by ``%x%
'' when the substitutions are processed
at the level of the compound command, and the actual substitution by
the value of register x
is carried out before the corresponding
subcommand is executed. Thus, in the above example, the command
~+|~x+1|~/Value of X is %%%x%%%gives the desired result.
Implementing fast loops with compound statements
Loops can be implemented in the EMME/2 macro language by
combining conditional (``~?
...''), branching (``~$
label'')
and label (``~:
label'') commands.
Since each branching command ``~$
label''causes the
macro file to be scanned from the beginning until the
specified label is found, this kind of loop implementation is
rather expensive in terms of execution time. Especially when
a loop is positioned toward the end of a long macro file,
and is repeated many times, branching overhead can become an issue.
Of course, for loops involving heavy computations (such as
assignments, matrix operations or network computations) the
CPU time spent always exceeds the loop overhead by far.
However, for short loops, as often used for ``housekeeping'' or formatting
tasks within a larger macro, the branching overhead may become noticeable.
Compound statements can be used to implement small loops very efficiently,
avoiding the time consuming file searching for a given label. This is
done using a ``label-less'' branch command ``~$
'', which causes
a branch back to the beginning of the current compound command, i.e.
the entire compound command is started over. As this type of branching
does not imply any file access at all, it is always very fast, regardless
of its position within the macro file.
The following example uses this kind of loop for shifting the contents of
text register t1
to the right until it lines up with column 72:
~+|~t1= %%%t1.72%%%|~?t1=%%%t1.72%%%|~$The execution of the above loop is almost instantaneous. If the same loop is implemented with the standard labeled branching and appears at the end of a macro with 500 lines, it can well take several seconds to complete. (Note again the need for the
%%%
's, as explained
in the point above.)