6. Macro Assembly

Part of the SMAL Manual
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

Index

  1. Macro Definitions
  2. Macro Formal Parameters
  3. Macro Calls
  4. Examples

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.

 

6.1 Macro Definitions

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 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.

 

6.2. Macro Formal 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: Name mode, in which the formal parameter is declared by just its name; list mode, in which the formal parameter name is surrounded by parentheses; and value mode, in which the formal parameter name is preceded by an equals sign. The treatment of actual parameters in each of these three modes will be discussed in more detail later.

In summary, in name mode, the text of the actual parameter is substituted, without change, for the formal parameter; in this case, the actual parameter may be any text, excluding unparenthesized commas; this parameter passing mode is present in essentially all macro processors. The other two modes are eccentric but useful additions to SMAL: In list mode, the actual parameter must be parenthesized, and all or part of the text between the parentheses will be passed. In value mode, the actual parameter must be an expression and a textual representation of the value of that expression will be substituted for the formal parameter.

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 as the macro is defined. Formal parameters will be identified within comments and within 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 the two, as in "A'B". Within the body of any macro, single apostrophes will be deleted, and strings of two or more apostrophes will be shortened by one when that macro is defined. Thus, special care must be taken when using apostrophes as single quotes around quoted strings.

 

6.3. Macro Calls

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. After the parameters are stored, assembly of the body of the macro begins. As the body is being assembled, all formal parameters which had been identified at the time the body was originally defined are replaced with the text of the corresponding actual parameters. 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.

When a formal parameter is declared as a name parameter, the actual parameter may be any text which does not include commas unless the commas are parenthesized and as long as any parentheses in the text are balanced. The entire text of a name parameter will be passed with no changes other than to remove leading and trailing blanks.

When a formal parameter is declared as a list parameter, the actual parameter must be enclosed in parentheses and may contain any lexically valid text as long as the parentheses it contains are balanced. A substring specification is allowed after the end parenthesis; this consists of two expressions set off from the parameter and each other by colons.

<by list> ::= ( <balanced string> ) [ <substring> ]
<substring> ::= : [ <expression> ] [ : <expression> ]

If the substring specification is absent, the entire balanced string will be passed as a parameter. Note that the enclosing parentheses are never passed. If the first expression in the substring specification is present, it specifies the index of the first character in the balanced string to be passed (the default value of the first expression is one). If the second expression in the substring specification is present, it specifies how many characters from the balanced string are to be passed (the default value of the second expression is "all"). Substring specifications should be used with care because they may introduce strings with unbalanced parentheses.

For formal parameters declared using value mode, the actual parameter must be an expression.

<by value> ::= <expression>

The expression will be evaluated at the time of the macro call; if the result is an absolute value, the text of the decimal representation of that value will be passed as a parameter. Note that the decimal representation used will be unsigned, that is, -1 will be passed as a large positive integer; this allows identifiers to be constructed by appending the value of the parameter to a letter. If the value is not absolute, an expression will be passed which is guarnateed to evaluate to the actual parameter's value at the time of the call.

Macro calls will not take place when errors are found in the actual parameter list. During the assembly of the body of a macro, other macro calls may be processed, even recursive calls.

6.4. Examples

The following fragments of SMAL32 assembly listings demonstrate the correct use of macros. The first example is contrived to demonstrate the use of each parameter passing mode:

                            29  MACRO T NAME,=NUMBER, ( LIST )
                            30    NAME NUMBER
                            31    LIST
                            32  ENDMAC
                            33
                            34  T W,5+4,(COMMON A,5)
+000026: 00000009           34    W 9
                            34    COMMON A,5
                            34  END
                            35
                            36  T W,1,(BIW -25):3
+00002A: 00000001           36    W 1
+00002E: FFFFFFE7           36    W -25
                            36  END
                            37
                            38  T W, A + 2, ("; NONESUCH"):2:6
+000032:+00000002           38    W A + 2
                            38    ; NONE
                            38  END

All lines in the listing with identical line numbers are the result of macro expansion. Normally, these would not be listed! The END directives are introduced automatically at the end of each macro body.

In the first call to the macro T, note that the expression "5+4" has been evaluated, and the value "9" has been substituted into the macro body. Similarly, in the second call, the expression "1" was evaluated and passed as "1". In the third call, the expression "A+2" could not be passed as a number because it is relocated relative to the common name "A", which was defined in the first call to the macro.

The following macro demonstrates the use of macros to hide an ugly aspect of SMAL. In this case, the strange syntax used to achieve halfword and word alignment in SMAL programs:

                             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

This macro is recommended for achieving alignment, and in absolute assembly code, it will align to any power of 2; in relocatable assembly code, however, it can only be guaranteed to relocate to the nearest word unless corresponding alignment directives are included in the linker control file to align the relocation process. This example illustrates how conditional and macro assembly can be combined to perform complex computations; it illustrates a recursive macro, and it illustrates the use of the ERROR directive to report an imporper parameter to a macro.

The following two macros demonstrate the use of value parameters and concatenation for automatic label generation. The macro "CATNUM" simply concatenates its three parameters, with the constraint that the middle parameter is an expression. This is used to construct new symbols by the second macro. The second macro maintains a counter, "LAB", which is incremented once each time it is called. Thus, each time it is called, it will be able to create new symbols.
 

                            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. This is:

                            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
                            28  TEXT "CALCULATE"
+00003E: 43  41  4C  43     29
         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.

Unfortunately, this example also demonstrates a minor bug. When listing is turned off during macro expansion, the object code generated by the macro is not listed until the line after the macro call.