9.2.3 Specifying Required and Default Parameters

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.