|
Table of Content | Chapter Eight (Part 10) |
| CHAPTER EIGHT: MASM: DIRECTIVES & PSEUDO-OPCODES (Part 9) |
| 8.15 -
Repeat Operations 8.16 - The FOR and FORC Macro Operations 8.17 - The WHILE Macro Operation 8.18 - Macro Parameters |
| 8.15 Repeat Operations |
Another macro format (at least by Microsoft's definition)
is the repeat macro. A repeat macro is nothing more than a loop that repeats the
statements within the loop some specified number of times. There are three types of repeat
macros provided by MASM: repeat/rept
for/irp
and forc/irpc. The
repeat/rept macro uses the following syntax:
repeat expression <statements> endm
Expression must be a numeric expression that
evaluates to an unsigned constant. The repeat directive duplicates all the
statements between repeat and endm that many times. The
following code generates a table of 26 bytes containing the 26 uppercase characters:
ASCIICode = 'A' repeat 26 byte ASCIICode ASCIICode = ASCIICode+1 endm
The symbol ASCIICode is assigned the ASCII
code for "A". The loop repeats 26 times
each time emitting a byte with the
value of ASCIICode. Also
the loop increments the ASCIICode
symbol on each repetition so that it contains the ASCII code of the next character in the
ASCII table. This effectively generates the following statements:
byte 'A' byte 'B' . . . byte 'Y' byte 'Z' ASCIICode = 27
Note that the repeat loop executes at assembly
time
not at run time. Repeat is not a mechanism for creating loops within
your program; use it for replicating sections of code within your program. If you want to
create a loop that executes some number of times within your program
use the loop instruction.
Although the following two code sequences produce the same result
they are not the same:
; Code sequence using a run-time loop: mov cx 10 AddLp: add ax [bx] add bx 2 loop AddLp ; Code sequence using an assembly-time loop: repeat 10 add ax [bx] add bx 2 endm
The first code sequence above emits four machine
instructions to the object code file. At assembly time
the 80x86 CPU executes the
statements between AddLp and the loop instruction ten times
under the control of the loop instruction. The second code sequence above
emits 20 instructions to the object code file. At run time
the 80x86 CPU simply executes
these 20 instructions sequentially
with no control transfer. The second form will be
faster
since the 80x86 does not have to execute the loop instruction every third
instruction. On the other hand
the second version is also much larger because it
replicates the body of the loop ten times in the object code file.
Unlike standard macros
you do not define and invoke repeat
macros separately. MASM emits the code between the repeat and endm
directives upon encountering the repeat directive. There isn't a separate
invocation phase. If you want to create a repeat macro that can be invoked
throughout your program
consider the following:
REPTMacro macro Count repeat Count <statements> endm endm
By placing the repeat macro inside a standard
macro
you can invoke the repeat macro anywhere in your program by invoking
the REPTMacro macro. Note that you need two endm directives
one
to terminate the repeat macro
one to terminate the standard macro.
Rept is a synonym for repeat. Repeat
is the newer form
MASM supports Rept for compatibility with older
source files. You should always use the repeat form.
Another form of the repeat macro is the for macro.
This macro takes the following form:
for parameter
<item1 {
item2 {
item3 {
...}}}>
<statements>
endm
The angle brackets are required around the items in the
operand field of the for directive. The braces surround optional items
the
braces should not appear in the operand field.
The for directive replicates the instructions
between for and endm once for each item appearing in the operand
field. Furthermore
for each iteration
the first symbol in the operand field is assigned
the value of the successive items from the second parameter. Consider the following loop:
for value <0 1 2 3 4 5> byte value endm
This loop emits six bytes containing the values zero one two ... five. It is absolutely identical to the sequence of instructions:
byte 0 byte 1 byte 2 byte 3 byte 4 byte 5
Remember
the for loop
like the repeat loop
executes at assembly time
not at run time.
For's second operand need not be a literal
text constant; you can supply a macro parameter
macro function result
or a text equate
for this value. Keep in mind
though
that this parameter must expand to a text value with
the text delimiters around it.
Irp is an older
obsolete
synonym for for.
MASM allows irp to provide compatibility with older source code. However
you
should always use the for directive.
The third form of the loop macro is the forc macro.
It differs from the for macro in that it repeats a loop the number of times
specified by the length of a character string rather than by the number of operands
present. The syntax for the forc directive is
forc parameter <string> <statements> endm
The statements in the loop repeat once for each character in the string operand. The angle brackets must appear around the string. Consider the following loop:
forc value <012345> byte value endm
This loop produces the same code as the example for the for
directive above.
Irpc is an old synonym for forc provided
for compatibility reasons. You should always use forc in your new code.
The while macro lets you repeat a sequence of
code in your assembly language file an indefinite number of times. An assembly time
expression
that while evaluates before emitting the code for each loop
determines
whether it repeats. The syntax for this macro is
while expression <Statements> endm
This macro evaluates the assembly-time expression; if this
expression's value is zero
the while macro ignores the statements up to the
corresponding endm directive. If the expression evaluates to a non-zero value
(true)
then MASM assembles the statements up to the endm directive and
reevaluates the expression to see if it should assemble the body of the while
loop again.
Normally
the while directive repeats the
statements between the while and endm as long as the expression
evaluates true. However
you can also use the exitm directive to prematurely
terminate the expansion of the loop body. Keep in mind that you need to provide some
condition that terminates the loop
otherwise MASM will go into an infinite loop and
continually emit code to the object code file until the disk fills up (or it will simply
go into an infinite loop if the loop does not emit any code).
Standard MASM macros are very flexible. If the number of
actual parameters (those supplied in the operand field of the macro invocation) does not
match the number of formal parameters (those appearing in the operand field of the macro
definition)
MASM won't necessarily complain. If there are more actual parameters than
formal parameters
MASM ignores the extra parameters and generates a warning. If there are
more formal parameters than actual parameters
MASM substitutes the empty string
("<>") for the extra formal parameters. By using the ifb and ifnb
conditional assembly directives
you can test this last condition. While this parameter
substitution technique is flexible
it also leaves open the possibility of error. If you
want to require that the programmer supply exactly three parameters and they actually
supply less
MASM will not generate an error. If you forget to test for the presence of
each parameter using ifb
you could generate bad code. To overcome this
limitation
MASM provides the ability to specify that certain macro parameters are
required. You can also assign a default value to a parameter if the programming doesn't
supply one. Finally
MASM also provides facilities to allow a variable number of macro
arguments.
If you want to require a programmer to supply a particular
macro parameters
simply put ":req" after the macro parameter in
the macro definition. At assembly time
MASM will generate an error if that particular
macro is missing.
Needs2Parms macro parm1:req parm2:req . . . endm . . . Needs2Parms ax ;Generates an error. Needs2Parms ;Generates an error. Needs2Parms ax bx ;Works fine.
Another possibility is to have the macro supply a default
value for a macro if it is missing from the actual parameter list. To do this
simply use
the ":=<text>" operator immediately after the parameter name in the formal
parameter list. For example
the int 10h BIOS function provides various video
services. One of the most commonly used video services is the ah=0eh function
that outputs the character in al to the video display. The following macro
lets the caller specify which function they want to use
and defaults to function 0eh
if they don't specify a parameter:
Video macro service := <0eh> mov ah service int 10h endm
The last feature MASM's macros support is the ability to
process a variable number of parameters. To do this you simply place the operator ":vararg"
after the last formal parameter in the parameter list. MASM associates the first n actual
parameters with the corresponding formal parameters appearing before the variable
argument
it then creates a text equate of all remaining parameters to the formal
parameter suffixed with the ":vararg" operator. You can use the for
macro to extract each parameter from this variable argument list. For example
the
following macro lets you declare an arbitrary number of two dimensional arrays
all the
same size. The first two parameters specify the number of rows and columns
the remaining
optional parameters specify the names of the arrays:
MkArrays macro NumRows:req NumCols:req Names:vararg for AryName Names &AryName& word NumRows dup (NumCols dup (?)) endm endm . . . MkArrays 8 12 A B X Y
|
Table of Content | Chapter Eight (Part 10) |
Chapter Eight: MASM: Directives &
Pseudo-Opcodes (Part 9)
26 SEP 1996