By using macros, you can use a single source statement to insert a sequence of source statements into a program. A macro definition contains the source statements of the macro. The macro definition may have formal arguments. You can use these formal arguments throughout the sequence of source statements within the definition. When the macro is called, the formal arguments are replaced by the actual arguments within the macro call. The macro call is a single source statement consisting of the macro name, optionally followed by arguments. When the macro is called, the assembler replaces the line containing the macro call with the source statements in the macro definition. The assembler replaces any occurrences of formal arguments in the macro definition with the actual arguments specified in the macro call. This process is called the macro expansion. By default, macro expansions are not printed in the assembly listing. To print the macro expansions, you must specify the /SHOW=EXPANSIONS qualifier and argument in the command line. Note that the examples of macro expansions used in this chapter are listed as they would appear using the /SHOW=EXPANSIONS qualifier and argument. Use .SHOW with a symbolic argument of EXPANSIONS in the source text of a program to specify the listing of expansions.
1 – Arguments
Macros have two types of arguments: actual and formal. Actual arguments are the text given in the macro call after the name of the macro. Formal arguments are specified by name in the macro definition; that is, after the macro name in the .MACRO directive. Actual arguments in macro calls and formal arguments in macro definitions can be separated by commas (,), tabs, or spaces. The number of actual arguments in the macro call can be less than or equal to the number of formal arguments in the macro definition. If the number of actual arguments is greater than the number of formal arguments, the assembler displays an error message. Formal and actual arguments normally maintain a strict positional relationship. That is, the first actual argument in a macro call replaces all occurrences of the first formal argument in the macro definition. This strict positional relationship can be overridden by using keyword arguments. See the section on keyword arguments. An example of a macro definition using formal arguments follows: .MACRO STORE ARG1,ARG2,ARG3 .LONG ARG1 ; ARG1 is first argument .WORD ARG3 ; ARG3 is third argument .BYTE ARG2 ; ARG2 is second argument .ENDM STORE The following two examples show possible calls and expansions of the macro previously defined: STORE 3,2,1 ; Macro call .LONG 3 ; 3 is first argument .WORD 1 ; 1 is third argument .BYTE 2 ; 2 is second argument STORE X,X-Y,Z ; Macro call .LONG X ; X is first argument .WORD Z ; Z is third argument .BYTE X-Y ; X-Y is second argument
2 – Default Values
Default values are values that are defined in the macro definition. They are used when no value for a formal argument is specified in the macro call. Default values are specified in the .MACRO directive as follows: formal-argument-name = default-value An example of a macro definition specifying default values follows: .MACRO STORE ARG1=12,ARG2=0,ARG3=1000 .LONG ARG1 .WORD ARG3 .BYTE ARG2 .ENDM STORE The following three examples show possible calls and expansions of the macro defined previously: STORE ; No arguments supplied .LONG 12 .WORD 1000 .BYTE 0 STORE ,5,X ; Last two arguments supplied .LONG 12 .WORD X .BYTE 5 STORE 1 ; First argument supplied .LONG 1 .WORD 1000 .BYTE 0
3 – Keyword Arguments
Keyword arguments allow a macro call to specify the arguments in any order. In this case, the macro call must specify the same formal argument names that appear in the macro definition. Keyword arguments are useful when a macro definition has more formal arguments than necessary in the call. In any one macro call, it is good practice to specify the arguments as either all positional arguments or all keyword arguments. For example, the following macro definition specifies three arguments: .MACRO STORE ARG1,ARG2,ARG3 .LONG ARG1 .WORD ARG3 .BYTE ARG2 .ENDM STORE The following macro call specifies keyword arguments: STORE ARG3=27+5/4,ARG2=5,ARG1=SYMBL .LONG SYMBL .WORD 27+5/4 .BYTE 5 Because the keywords are specified in the macro call, the arguments in the macro call need not be given in the order they were listed in the macro definition. Positional and keyword arguments may be mixed. Usually, positional arguments are placed before keyword arguments. For example: .MACRO STORE ARG1,ARG2,ARG3=27+5/4 .LONG ARG1 .BYTE ARG2 .WORD 27+5/4 .ENDM STORE NOTE Keyword arguments are not counted when positional arguments are parsed. This means that when positional and keyword arguments are used in the same macro, one argument can be specified twice. The last value specified for the argument is used.
4 – String Arguments
If an actual argument is a string containing characters that the assembler interprets as separators (such as a tab, space, or comma), the string must be enclosed by delimiters. String delimiters for macro arguments are usually paired angle brackets (<>). A quoted literal enclosed in double quotes ("") is also a valid string argument. The assembler also interprets any character (except A, B, C, D, O, or X) after an initial circumflex (^) as a delimiter. Note that ^B, ^D, ^O, and ^X are used as radix control operators rather than argument delimiters. ^A is used as the ASCII operator and ^C is used as the complement operator. To pass an angle bracket as part of a string, you can use the circumflex form of the delimiter. The following are examples of delimited macro arguments: <HAVE THE SUPPLIES RUN OUT?> <LAB: CLR R4> "A quoted literal is taken as a single parameter value." ^%ARGUMENT IS <LAST,FIRST> FOR CALL% ^?EXPRESSION IS <5+3>*<4+2>? In the last two examples, the initial circumflex indicates that the percent sign (%) and question mark (?) are the delimiters. Note that only the left-hand delimiter is preceded by a circumflex. The assembler interprets a string argument enclosed by delimiters as one actual argument and associates it with one formal argument. If a string argument that contains separator characters is not enclosed by delimiters, the assembler interprets it as successive actual arguments and associates it with successive formal arguments. For example, the following macro definition has one formal argument: .MACRO DOUBLE_ASCII STRNG .ASCII "STRNG" .ASCII "STRNG" .ENDM DOUBLE_ASCII The following two macro calls demonstrate actual arguments with and without delimiters: DOUBLE_ASCII <A B C D E> .ASCII "A B C D E" .ASCII "A B C D E" DOUBLE_ASCII A B C D E %MACRO64-E-TOOMNYARGS, Too many arguments in macro call Note that the assembler interprets the second macro call as having five actual arguments instead of one actual argument with spaces. When a macro is called, the assembler removes normal delimiters around a string before associating it with the formal arguments. However, a quoted literal within double quotes is treated as a single token and retains its double quote delimiters. If a string contains a semicolon (;), the string must be enclosed by delimiters; otherwise, the semicolon will mark the start of the comment field. Further, if the string contains a semicolon, you cannot continue the line unless the string is a quoted literal. You can nest macro invocations, that is, a macro definition can contain a call to another macro. If, within a macro definition, another macro is called and is passed a string argument, you must delimit the argument so that the entire string is passed to the second macro as one argument. The following macro definition contains a call to the DOUBLE_ ASCII macro defined earlier: .MACRO CNTDA LAB1,LAB2,STR_ARG LAB1: .BYTE LAB2-LAB1-1 ; Length of 2*string DOUBLE_ASCII <STR_ARG> ; Call DOUBLE_ASCII macro LAB2: .ENDM CNTDA Note that the argument in the call to DOUBLE_ASCII is enclosed in angle brackets even though it does not contain any separator characters. The argument is thus delimited because it is a formal argument in the definition of the macro CNTDA and will be replaced with an actual argument that may contain separator characters. The following example calls the macro CNTDA, which in turn calls the macro DOUBLE_ASCII: CNTDA ST,FIN,<LEARN YOUR ABC'S> ST: .BYTE FIN-ST-1 DOUBLE_ASCII <LEARN YOUR ABC'S> .ASCII "LEARN YOUR ABC'S" .ASCII "LEARN YOUR ABC'S" FIN: In addition to nested macro invocations, you can also nest macro definitions. That is, you can define one macro within another. In this example, the INNER_MACRO_DEF macro is not defined until the OUTER_MACRO_DEF macro is invoked and expanded: .macro OUTER_MACRO_DEF .macro INNER_MACRO_DEF ... .endm INNER_MACRO_DEF .endm OUTER_MACRO_DEF You can use this capability to define a macro that redefines itself: .macro SETUP A = 75 B = 92 C = 87 D = 0 E = -12 F = 42 .macro SETUP ; Setup is done - do nothing .endm SETUP .endm SETUP In this example, the SETUP macro defines a number of assembly constants. After the SETUP macro has been expanded once, its work is done. Subsequent expansions of the setup macro need not take any action. Therefore, the SETUP macro redefines itself to a macro whose expansion includes only a comment statement. As described elsewhere, when you redefine a macro, the original version of the macro is automatically deleted. If that macro is currently expanding (as would be the case with the previous SETUP macro), the new definition is immediately associated with the macro name. However, the old definition is retained until all pending expansions complete normally. When all pending expansions complete, the old version of the macro is deleted. Thus, the SETUP macro may be invoked any number of times in the assembly unit. Since the first expansion redefines itself, the expansion of the SETUP macro has no effect other than the first time it is invoked. Another way to pass string arguments in nested macros is to enclose the macro argument in nested delimiters. NOTE Each time you use the delimited argument in a macro call, the assembler removes the outermost pair of delimiters before associating it with the formal argument. This method is not recommended because it requires that you know how deeply a macro is nested. The following macro definition also contains a call to the DOUBLE_ASCII macro: .MACRO CNTDA2 LAB1,LAB2,STR_ARG LAB1: .BYTE LAB2-LAB1-1 ; Length of 2*string DOUBLE_ASCII STR_ARG ; Call DOUBLE_ASCII macro LAB2: .ENDM CNTDA2 Note that the argument in the call to DOUBLE_ASCII is not enclosed in angle brackets. The following example calls the macro CNTDA2: CNTDA2 BEG,TERM,<<MIND YOUR P'S AND Q'S>> BEG: .BYTE TERM-BEG-1 ; Length of 2*string DOUBLE_ASCII <MIND YOUR P'S AND Q'S> ; Call DOUBLE_ASCII macro .ASCII "MIND YOUR P'S AND Q'S" .ASCII "MIND YOUR P'S AND Q'S" TERM: Note that even though the call to DOUBLE_ASCII in the macro definition is not enclosed in delimiters, the call in the expansion is enclosed because the call to CNTDA2 contains nested delimiters around the string argument.
5 – Argument Concatentation
The argument concatenation operator, the apostrophe ('), concatenates a macro argument with constant text or another argument. Apostrophes can either precede or follow a formal argument name in the macro source. If an apostrophe precedes the argument name, the text before the apostrophe is concatenated with the actual argument when the macro is expanded. For example, if ARG1 is a formal argument associated with the actual argument TEST, then ABCDE'ARG1 is expanded to ABCDETEST. If an apostrophe follows the formal argument name, the actual argument is concatenated with the text that follows the apostrophe when the macro is expanded. The apostrophe itself does not appear in the macro expansion. To concatenate two arguments, separate the two formal arguments with two successive apostrophes. Two apostrophes are needed because each concatenation operation discards an apostrophe from the expansion. An example of a macro definition that uses concatenation follows: .MACRO CONCAT A,B A''B: .WORD 0 .ENDM CONCAT Note that two successive apostrophes are used when concatenating the two formal arguments A and B. An example of a macro call and expansion follows: CONCAT X,Y XY: .WORD 0
6 – Passing Numeric Values of Symbols
When a symbol is specified as an actual argument, the name of the symbol, not the numeric value of the symbol, is passed to the macro. You can pass the value of the symbol by inserting a backslash (\) before the symbol in the macro call. The assembler passes the characters representing the decimal value of the symbol to the macro. For example, if the symbol COUNT has a value of 2 and the actual argument specified is \COUNT, the assembler passes the string 2 to the macro; it does not pass the name of the symbol, COUNT. Passing numeric values of symbols is especially useful with the apostrophe (') concatenation operator for creating new symbols. An example of a macro definition for passing numeric values of symbols follows: .MACRO WORD n WORD'n: .WORD n .ENDM WORD The following example shows a possible call and expansion of the macro previously defined: X = 1 ; Start counting at 1 WORD \X WORD1: .WORD 1
7 – Created Temporary Labels
Temporary labels are often very useful in macros. You can create a macro definition that specifies temporary labels within it, but these temporary labels might be duplicated elsewhere in the temporary label block, possibly causing errors. However, the assembler can create temporary labels in the macro expansion that will not conflict with other temporary labels. These labels are called created temporary labels. Created temporary labels range from 30000$ to 65535$. Each time the assembler creates a new temporary label, it increments the numeric part of the label name by 1. Consequently, no user- defined temporary labels should be in the range of 30000$ to 65535$. A created temporary label is specified by a question mark (?) in front of the formal argument name. When the macro is expanded, the assembler creates a new temporary label if the corresponding actual argument is blank. If the corresponding actual argument is specified, the assembler substitutes the actual argument for the formal argument. The following example is a macro definition specifying a created temporary label: .MACRO POSITIVE ARG1,?L1 BGE ARG1,L1 NEGQ ARG1,ARG1 L1: .ENDM POSITIVE The following three calls and expansions of the macro defined previously show both created temporary labels and a user-defined temporary label: POSITIVE R0 BGE R0,30000$ NEGQ R0,R0 30000$: POSITIVE R5 BGE R5,30001$ NEGQ R5,R5 30001$: POSITIVE R7,10$ BGE R7,10$ NEGQ R7,R7 10$: