4.3.6. `%rotate': Rotating Macro Parameters
-------------------------------------------
Unix shell programmers will be familiar with the `shift' shell
command, which allows the arguments passed to a shell script
(referenced as `$1', `$2' and so on) to be moved left by one place, so
that the argument previously referenced as `$2' becomes available as
`$1', and the argument previously referenced as `$1' is no longer
available at all.
NASM provides a similar mechanism, in the form of `%rotate'. As its
name suggests, it differs from the Unix `shift' in that no parameters
are lost: parameters rotated off the left end of the argument list
reappear on the right, and vice versa.
`%rotate' is invoked with a single numeric argument (which may be an
expression). The macro parameters are rotated to the left by that many
places. If the argument to `%rotate' is negative, the macro parameters
are rotated to the right.
So a pair of macros to save and restore a set of registers might
work as follows:
%macro multipush 1-*
%rep %0
push %1
%rotate 1
%endrep
%endmacro
This macro invokes the `PUSH' instruction on each of its arguments in
turn, from left to right. It begins by pushing its first argument,
`%1', then invokes `%rotate' to move all the arguments one place to the
left, so that the original second argument is now available as `%1'.
Repeating this procedure as many times as there were arguments
(achieved by supplying `%0' as the argument to `%rep') causes each
argument in turn to be pushed.
Note also the use of `*' as the maximum parameter count, indicating
that there is no upper limit on the number of parameters you may supply
to the `multipush' macro.
It would be convenient, when using this macro, to have a `POP'
equivalent, which _didn't_ require the arguments to be given in reverse
order. Ideally, you would write the `multipush' macro call, then
cut-and-paste the line to where the pop needed to be done, and change
the name of the called macro to `multipop', and the macro would take
care of popping the registers in the opposite order from the one in
which they were pushed.
This can be done by the following definition:
%macro multipop 1-*
%rep %0
%rotate -1
pop %1
%endrep
%endmacro
This macro begins by rotating its arguments one place to the _right_,
so that the original _last_ argument appears as `%1'. This is then
popped, and the arguments are rotated right again, so the second-to-
last argument becomes `%1'. Thus the arguments are iterated through in
reverse order.