Summary: You can specify required and default parameters for macros.
You can give macro parameters special attributes to make them more flexible and improve error handling; you can make them required, give them default values, or vary their number. Because variable parameters are used almost exclusively with the FOR directive, discussion of them is postponed until Section 9.4.3, “FOR Loops and Variable-Length Parameters.”
The syntax for a required parameter is
parameter:REQ
For example, you can rewrite the writechar macro to require the char parameter:
writechar MACRO char:REQ
mov ah, 2 ;; Select DOS Print Char function
mov dl, char ;; Select ASCII char
int 21h ;; Call DOS
ENDM
If the call does not include a matching argument, the assembler reports the error in the line that contains the macro call. The effect of REQ is to improve error reporting.
Summary: A default value fills in missing parameters.
Another way to handle missing parameters is to specify a default value. The syntax is
parameter:=textvalue
Suppose that you often use writechar to beep by printing ASCII 7. The following macro definition uses an equal sign to tell the assembler to assume the parameter char is 7 unless you specify otherwise:
writechar MACRO char:=<7>
mov ah, 2 ;; Select DOS Print Char function
mov dl, char ;; Select ASCII char
int 21h ;; Call DOS
ENDM
In this case, char is not required. If you don't supply a value, the assembler fills in the blank with the default value of 7 and the macro beeps when called.
The default parameter value is enclosed in angle brackets so that the supplied value will be recognized as a text value. Section 9.3.1, “Text Delimiters (<>) and the Literal-Character Operator (!),” explains this in more detail.<$I<< \ra (angle brackets);default parameters>
Missing arguments can also be handled with the IFB, IFNB, .ERRB, and .ERRNB directives. They are described briefly in Section 1.3.3, “Conditional Directives,” and in online help. Here is a slightly more complex macro that uses some of these techniques.
Scroll MACRO distance:REQ, attrib:=<07h>, tcol, trow, bcol, brow
IFNB <tcol> ;; Ignore arguments if blank
mov cl, tcol
ENDIF
IFNB <trow>
mov ch, trow
ENDIF
IFNB <bcol>
mov dl, bcol
ENDIF
IFNB <brow>
mov dh, brow
ENDIF
IFDIFI <attrib>, <bh> ;; Don't move BH onto itself
mov bh, attrib
ENDIF
IF distance LE 0 ;; Negative scrolls up, positive down
mov ax, 0600h + (-(distance) AND 0FFh)
ELSE
mov ax, 0700h + (distance AND 0FFh)
ENDIF
int 10h
ENDM
In this macro, the distance parameter is required. The attrib parameter has a default value of 07h (white on black), but the macro also tests to make sure the corresponding argument isn't BH, since it would be inefficient (though legal) to load a register onto itself. The IFNB directive is used to test for blank arguments. These are ignored to allow the user to manipulate rows and columns directly in registers CX and DX at run time.
The following are two valid ways to call the macro:
; Assume DL and CL already loaded
dec dh ; Decrement top row
inc ch ; Increment bottom row
Scroll -3 ; Scroll white on black dynamic
; window up three lines
Scroll 5, 17h, 2, 2, 14, 12 ; Scroll white on blue constant
; window down five lines
This macro can generate completely different code, depending on its arguments. In this sense, it is not comparable to a procedure, which always has the same code regardless of arguments.