6. Macro Assembly
Part of
the SMAL Manual
|
The SMAL macro facilities allow assembly-time control structures comparable to the procedure structures of many high level languages. A macro is a named block of text which is assembled into the program wherever its name occurs in the context of a macro call. If a macro is defined as having formal parameters, the corresponding actual parameters are substituted for the formal parameters within the body of the macro before it is assembled.
Note: Macros control how the assembler sees your code. They do not control the execution of the assembled machine code.
Each macro definition begins with a MACRO directive and ends with an ENDMAC directive. The MACRO directive is followed by the name of the macro and its formal parameter list.
<symbolic directive> ::= MACRO <identifier> [ <formal list> ] | ENDMAC
The semantics of a macro declaration are most easily described in terms of macro blocks which begin with a MACRO directive and end with an endmac directive. The body of the block between the two is saved by the assembler and assembled as a result of each call to the macro.
<macro block> ::= MACRO <identifier> [ <formal list> ] <line end> { <line> } ENDMAC
Note that any labels on the line containing the MACRO directive are not interpreted as having anything to do with the macro but are processed as normal labels. Labels on the line containing the ENDMAC directive are completely ignored! If a macro block is not properly terminated with an ENDMAC directive, a "missing endmac" error will result. The following fragment of valid SMAL32 code illustrates the definition of a simple parameterless macro:
MACRO ZO W 0 W -1 ENDMAC
A call to this macro can be used to put the two word sequence 0, -1 in memory.
Macro definitions may contain other macro definitions, but these do not create local macros, as might be expected by anology with high level languages. Instead, the internal macro definition will be processed by the assembler each time the containing macro is called. Thus, a macro may be used to create a number of other macros constructed from the values of its parameters.
The formal parameter list on a macro definition gives the names of each parameter and the parameter passing mode. Forml parameter names are identifiers. There may be a limit on the number of formal parameters allowed; if this is exceded, a "too many macro parameters" error will be raised. All versions of SMAL support at least 8 parameters.
<formal list> ::= <formal parameter> { , <formal parameter> } <formal parameter> ::= <identifier> | ( <identifier> ) | = <identifier>
The three macro parameter modes are:
The treatment of actual parameters in each of these modes will be discussed in Section 6.3.
The following fragment of a SMAL assembly listing illustrates the definition of a simple macro with one parameter passed by name:
MACRO WZO TEXT W TEXT ZO ENDMAC
Note that the above macro contains a call to the macro ZO defined in the previous example.
Within the macro body, each occurance of any macro formal parameter name is identified. This includes formal parameters embedded in comments and character strings. The only time that a formal parameter will not be identified is when it is embedded in a larger identifier. For example, if A and B are formal parameters, neither of them will be identified in the string AB. If AB is to be seen as the concatenation of two parameters, an apostrophe should be inserted between them, as in A'B. Within a macro body, single apostrophes will be deleted, and strings of two or more apostrophes will be shortened by one. Thus, special care must be taken when using apostrophes as single quotes around quoted strings in macros.
A macro call takes the form of a symbolic directive which begins with the name of a previously defined macro, followed by a list of actual parameters.
<symbolic directive> ::= <identifier> <actual list> <actual list> ::= <actual parameter> { , <actual parameter> } <actual parameter> ::= [ <by name> | <by list> | <by value> ]
The first step in processing a macro call is to store the text of each actual parameter, according to the parameter passing rules associated with that parameter type. Individual parameters may be omitted or blank, in which case, no text is passed. In all cases, the number of actual parameters must be less than or equal to the number of formal parameters. Missing actual parameters are passed as empty strings. The following rules apply:
<by list> ::= ( <balanced string> ) [ <substring> ] <substring> ::= : [ <expression> ] [ : <expression> ]
If the substring specification is absent, the entire actual parameter is passed, minus enclosing parentheses. The first expression in the substring specification gives the index of the first character in the parameter to be passed (the default is one, the character right after the opening parenthesis). The second expression gives how many characters from the parameter are to be passed (the default is "up to but not including the closing parenthesis"). Substring specification should be used with care because it may introduce strings with unbalanced parentheses.
<by value> ::= <expression>
The expression will be evaluated. If the value is absolute, the text of the unsigned decimal representation of the value will be passed. This means that -1 will be passed as 4294967295. As a result, identifiers to be constructed by appending the value of the parameter to a letter. If the value relocatable, a short expression with the same value will be passed.
Macros will not be expanded when there are errors in the actual parameter list. After actual parameters processing, macro expansion proceeds by assembling the macro body. As the body is assembled, formal parameters in the body are replaced with the actual parameter text. If the resulting text for any line is longer than the implementation defined line length limit, the error "text too long for line" will result. During expansion, other macro calls may be processed, even recursive calls.
The following SMAL32 assembly listing fragments (see Section 10.2) show the correct use of macros. The first example demonstrates the use of each parameter passing mode:
29 MACRO TT NAME,=NUMBER, ( LIST ) 30 NAME NUMBER 31 LIST 32 ENDMAC 33 34 TT W,5+4,(COMMON A,5) +000026: 00000009 34 W 9 34 COMMON A,5 34 END 35 36 TT W,1,(BIW -25):3 +00002A: 00000001 36 W 1 +00002E: FFFFFFE7 36 W -25 36 END 37 38 TT W, 1 + A + 1, ("; NONESUCH"):2:6 +000032:+00000002 38 W A+2 38 ; NONE 38 END
All lines produced by macro expansion are listed after the call, with the same line number as the call. Normally, macro expansion listing is suppressed, but it can be turned on using the LIST directive (see Section 7.4). END directives mark the end of each macro.
In the first call to TT, the expression 5+4 was evaluated and the value 9 was substituted in the macro body. In the second call, the expression 1 was evaluated and passed as 1. In the third call, the value of 1 + A + 1 could not be converted to a number because the value is relative to the common name A; the string that was passed, A+2, is the result of evaluating the expression and then constructing a new string from the value.
The following macro shows how to package halfword and word alignment in SMAL:
3 MACRO ALIGN =x 4 IF x > 1 5 IF (x & 1) = 1 6 ERROR odd parameter to ALIGN 7 ELSE 8 ALIGN (x>>1) 9 .=.+(ABS(.)&(x>>1)) 10 ENDIF 11 ENDIF 12 ENDMAC 13 14 ALIGN 1 ; no operation +000000: 01 15 B 1 16 ALIGN 2 ; align to a halfword boundary +000002: 0002 17 H 2 18 ALIGN 4 ; align to a word boundary +000004: 00000003 19 W 3 20 ALIGN 3 ; an improper alignment 20 ERROR odd parameter to ALIGN error message
If the location counter (see Chapter 3) is absolute, this macro aligns to any power of 2; in relocatable code, it can only align to the nearest word unless alignment directives are included in the linker control file (see Chapter 8) to align the relocation process. Here, conditional and recursive macro assembly were used. This example also uses the ERROR directive (see Section 7.7) to report an imporper macro parameter.
The following two macros demonstrate the use of value parameters and concatenation for automatic label generation. The macro CATNUM simply concatenates its three parameters, where the middle parameter is an expression. This is used by the second macro, USER, to construct new symbols using a counter, LAB, which is incremented once for each call.
40 MACRO CATNUM (PART1),=NUM,(PART2) 41 PART1'NUM'PART2 42 ENDMAC 43 44 LAB = 1 45 MACRO USER 46 LAB = LAB + 1 47 CATNUM (L),LAB,(:) 48 W 0 49 CATNUM (W L),LAB 50 ENDMAC 51 52 USER 52 LAB = LAB + 1 52 CATNUM (L),LAB,(:) 52 L2: 52 END +000036: 00000000 52 W 0 52 CATNUM (W L),LAB +00003A:+00000036 52 W L2 52 END 52 END 53 54 USER 54 LAB = LAB + 1 54 CATNUM (L),LAB,(:) 54 L3: 54 END +00003E: 00000000 54 W 0 54 CATNUM (W L),LAB +000042:+0000003E 54 W L3 54 END 54 END
Note that the symbol LAB could have been initialized in the macro USER instead of in the main program. To do this, the initialization would have to be assembled conditionally depending on whether or not LAB had been previously defined.
The last example illustrates a macro similar to the built in ASCII directive:
19 MACRO TEXT S,(PART1),(PART2) 20 IF LEN(S) > 0 21 TEXT ,(S):2:1,(S):3:LEN(S)-3 22 ELSEIF LEN(''PART1'') > 2 23 B ''PART1'' 24 TEXT ,(PART2):1:1,(PART2):2 25 ENDIF 26 ENDMAC 27 +00003E: 43 41 4C 43 28 TEXT "CALCULATE" 55 4C 41 54 45
This example demonstrates the combination of conditional and macro assembly, the use of substring parameters, the use of the function LEN to detect missing parameters, and the use of recursion. Note also the use of doubled single quotes within the macro definition which result in single quotes at expansion time.