9.6 Returning Values with Macro Functions

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.