Summary: A macro function returns a text string.
A macro function is a named group of statements that returns a value. When a macro function is called, its argument list must be enclosed in parentheses, even if the list is empty. The value returned is always text.
Macro functions are new to MASM 6.0, as are several predefined macro functions for common tasks. The predefined macros include @Environ (see Section 1.2.3) and the string functions @SizeStr, @CatStr, @SubStr, and @InStr (discussed in the preceding section).
Macro functions are defined in exactly the same way as macro procedures, except that a value must always be returned using the EXITM directive. Here is an example:
DEFINED MACRO symbol:REQ
IFDEF symbol
EXITM <-1> ;; True
ELSE
EXITM <0> ;; False
ENDIF
ENDM
This macro works like the defined operator in the C language. You can use it to test the defined state of several different symbols with a single statement, as shown below:
IF DEFINED( DOS ) AND NOT DEFINED( XENIX )
;; Do something
ENDIF
Notice that the macro returns integer values as strings of digits, but the IF statement evaluates numeric values or expressions. There is no conflict because the value returned by the macro function is seen in the statement exactly as if the user had typed the values directly into the program:
IF -1 AND NOT 0
Returning Values with EXITM
The return value must be text, a text equate name, or the result of another macro function. If a function must return a numeric value (such as a constant, a numeric equate, or the result of a numeric expression), it must first convert the value to text using angle brackets or the expansion operator (%). The defined macro, for example, could have returned its value as
EXITM %-1
Although macro functions can include any legal statement, they seldom need to include instructions. This is because a macro function is expanded and its value returned at assembly time, while instructions are executed at run time.
Here is another example of a macro function. It uses the WHILE directive to calculate factorials:
factorial MACRO num:REQ
LOCAL i, factor
factor = num
i = 1
WHILE factor GT 1
i = i * factor
factor = factor - 1
ENDM
EXITM %i
ENDM
The integer result of the calculation is changed to a text string with the expansion operator (%). The factorial macro can be used to define data, as shown below:
var WORD factorial( 4 )
The effect of this statement is to initialize var with the number 24 (the factorial of 4).
Using Macro Functions with Variable-Length Parameter Lists
Summary: Macro functions can enhance FOR loops.
You can use the FOR directive to handle macro parameters with the VARARG attribute. Section 9.4.3 explains how to do this in simple cases where the variable parameters are handled sequentially, from first to last. However, you may sometimes need to process the parameters in reverse order or nonsequentially. Macro functions make these techniques possible.
You may need to know the number of arguments in a VARARG parameter. The following macro functions handle this.
@ArgCount MACRO arglist:VARARG
LOCAL count
count = 0
FOR arg, <arglist>
count = count + 1 ;; Count the arguments
ENDM
EXITM %count
ENDM
You could use this inside a macro that has a VARARG parameter, as shown below:
work MACRO args:VARARG
% ECHO Number of arguments is: @ArgCount( args )
ENDM
Another useful task might be to select an item from an argument list using an index to indicate which item. The following macro simplifies this.
@ArgI MACRO index:REQ, arglist:VARARG
LOCAL count, retstr
retstr TEXTEQU <> ;; Initialize count
count = 0 ;; Initialize return string
FOR arg, <arglist>
count = count + 1
IF count EQ index ;; Item is found
retstr TEXTEQU <arg> ;; Set return string
EXITM ;; and exit IF
ENDIF
ENDM
EXITM retstr ;; Exit function
ENDM
This function can be used as shown below:
work MACRO args:VARARG
% ECHO Third argument is: @ArgI( 3, args )
ENDM
Finally, you might need to process arguments in reverse order. The following macro returns a new argument list in reverse order.
@ArgRev MACRO arglist:REQ
LOCAL txt, arg
txt TEXTEQU <>
% FOR arg, <arglist>
txt CATSTR <arg>, <,>, txt ;; Paste each onto list
ENDM
;; Remove terminating comma
txt SUBSTR txt, 1, @SizeStr( %txt ) - 1
txt CATSTR <!<>, txt, <!>> ;; Add angle brackets
EXITM txt
ENDM
You could call this function as shown below:
work MACRO args:VARARG
% FOR arg, @ArgRev( <args> ) ;; Process in reverse order
ECHO arg
ENDM
ENDM
These three macro functions are provided on the MASM distribution disk in the MACROS.INC include file.
Macro Operators and Macro Functions
This list summarizes the behavior of the expansion operator with macro functions.
If a macro function is not preceded by a %, it will be expanded. However, if it expands to a text macro or a macro function call, the result will not be expanded further.
If you use a macro function call as an argument for another macro function call, a % is not needed.
If a macro function expands to a text macro (or another macro function), the macro function will be recursively expanded.
If a macro function is called inside angle brackets and is preceded by %, it will be expanded.