Tatara

Chapter 16
Macros

A macro is a name for a group of lines. Once the group is defined, the name can be used like an instruction, and TATARA replaces each use with the lines of the group. The result of one use is called an expansion.

The system macro of chapter 14 is one: system _STROUT is replaced by ld c,_STROUT and call BDOS. A macro is not a subroutine. A subroutine exists once in the program and is reached with call; a macro’s lines are put into the program again at every use. A macro saves typing, not bytes.

This chapter describes how to define a macro, how to pass it values, and the directives that are used inside one. REPT, IRP and IRPC, which repeat lines without a name, are in chapter 17; they follow the same rules for arguments, LOCAL and EXITM.

16.1 Defining and using a macro

A macro is defined with MACRO, which is preceded by the name of the macro and followed by the names of its parameters, separated by commas. The lines that follow are its body, and ENDM ends it:

fill            macro   addr,value 
                ld      hl,addr 
                ld      (hl),value 
                endm
 

As with EQU, the name is written without a colon (chapter 12). The definition produces no bytes; TATARA only stores the body. A macro must be defined before its first use.

To use the macro, write its name as if it were an instruction, followed by the arguments: the values its parameters stand for in this use. TATARA replaces each parameter in the body with the matching argument, the first argument for the first parameter, the second for the second (figure 16.1).

PIC

Figure 16.1: A macro’s definition, a use of it, and the expansion.

The listing shows each use followed by its expansion, with the generated lines marked +:

                                                fill    4000h,0 
  0000'   21 00 40        +                     ld      hl,4000h 
  0003'   36 00           +                     ld      (hl),0 
                                                fill    4001h,0ffh 
  0005'   21 01 40        +                     ld      hl,4001h 
  0008'   36 FF           +                     ld      (hl),0ffh
 

Chapter 18 describes how to show less of an expansion in the listing, or none of it.

16.2 Arguments

The arguments of a use are separated by commas. Blanks before an argument are not part of it.

This macro puts its first argument in a DB, and its second in another if there is one:

show            macro   a,b 
                db      a 
                ifnb    <b> 
                db      b 
                endif 
                endm
 

In these uses, show 3 leaves b empty, the 6 in show 4,5,6 is ignored, <7,8> is one argument, and ’!>’ passes a string holding >:

                                                show    3 
  0002'   03              +                     db      3 
                                                show    4,5,6 
  0003'   04              +                     db      4 
  0004'   05              +                     db      5 
                                                show    <7,8>,9 
  0005'   07 08           +                     db      7,8 
  0007'   09              +                     db      9 
                                                show    '!>',10 
  0008'   3E              +                     db      '>' 
  0009'   0A              +                     db      10
 

An argument is text, not a value: five*2 is passed as the six characters five*2. A % in front of an argument passes its value instead, written as a decimal number. With a body of db ’&x’ (the & is explained in the next section), the first use below passes the text and the second its value:

                                                show    five*2 
  0000'   66 69 76 65     +                     db      'five*2' 
  0004'   2A 32           + 
                                                show    %five*2 
  0006'   31 30           +                     db      '10'
 

The value must be one TATARA already knows, as for IF (chapter 15).

16.3 Joining text with &

A parameter is replaced only where its name stands as a word of its own. To join it to other text, put & between them: lab&n with the argument 1 becomes lab1. The & itself disappears.

Inside a string, a parameter is not replaced at all unless it is joined with &. In the string ’n’, the n is just a letter; in ’&n’, it is the parameter:

label           macro   n 
lab&n:          db      'n' 
                db      '&n' 
                endm
 
                                                label   1 
  0000'   6E              +     lab1:           db      'n' 
  0001'   31              +                     db      '1'
 

16.4 Comments in a body

A comment that starts with ; is kept in the body and appears in every expansion. One that starts with ;; is dropped when the macro is defined, so it is seen in the definition only. Use ;; for notes about how the macro works, which would only repeat themselves in the listing:

note            macro 
                nop             ; kept 
                nop             ;; dropped 
                endm
 
                                                note 
  0000'   00              +                     nop             ; kept 
  0001'   00              +                     nop
 

16.5 LOCAL

A macro that defines a label can be used only once, because a second use defines the label again (chapter 12):

wait            macro   n 
                ld      b,n 
loop:           djnz    loop 
                endm
 
LOCALNO.AS(4): ERROR: this name already has a value. 
    in wait, called from LOCALNO.AS(8)
 

LOCAL, followed by one or more names, solves this. In each expansion, TATARA replaces those names with new ones, ??0000, ??0001 and so on, a different one each time:

wait            macro   n 
                local   loop 
                ld      b,n 
loop:           djnz    loop 
                endm
 
                                                wait    10 
  0000'   06 0A           +                     ld      b,10 
  0002'   10 FE           +     ??0000:         djnz    ??0000 
                                                wait    20 
  0004'   06 14           +                     ld      b,20 
  0006'   10 FE           +     ??0001:         djnz    ??0001
 

The generated names are ordinary labels, and appear in the symbol table. Do not use names that start with ?? for labels of your own. LOCAL lines must come first in the body, before any other line; otherwise TATARA stops with LOCAL must come before the macro body.

16.6 EXITM

EXITM ends the expansion at once: the lines of the body after it are not used. It is used inside a conditional, so that the macro stops early in some cases. This macro does nothing when it is given no argument:

put             macro   x 
                ifb     <x> 
                exitm 
                endif 
                db      x 
                endm
 
                                                put     1 
  0000'   01              +                     db      1 
                                                put 
                                                put     3 
  0001'   03              +                     db      3
 

This is where the text tests of chapter 15 are useful. IFB and IFNB ask whether an argument was given, and IFIDN and IFDIF compare an argument with a fixed text, such as a register name. The conditionals that EXITM leaves open inside the macro are closed with it.

16.7 Macros inside macros

A macro’s body can use another macro, and can define one:

byte            macro   x 
                db      x 
                endm 
pair            macro   x,y 
                byte    x 
                byte    y 
                endm 
maker           macro   name,val 
name            macro 
                db      val 
                endm 
                endm
 

Here pair 1,2 produces db 1 and db 2 through byte. maker three,3 produces no bytes, but defines a macro called three, and three then produces db 3. A MACRO line in a body is only text until the body is expanded, and each ENDM belongs to the innermost MACRO.

A macro can also use itself. It then needs a condition that stops it, as in this macro, which counts down to zero:

down            macro   n 
                db      n 
                if      n gt 0 
                down    %n-1 
                endif 
                endm
 
                                                down    3 
  0000'   03              +                     db      3 
  0001'   02              +                     db      2 
  0002'   01              +                     db      1 
  0003'   00              +                     db      0
 

Expansions inside expansions, together with include files, can be 16 deep. Without a condition to stop it, a macro that uses itself reaches that limit, and TATARA stops with sources nested too deeply.

A macro can be defined again, and the new definition replaces the old one from that line on. The system macro depends on this: each module that includes MSXDOS.INC defines it again (chapter 14).

16.8 Upper and lower case

Macro names follow the same rule as other names: without /C, PUT uses the macro put; with /C, it does not, and TATARA stops with not a directive, a macro or an instruction. (chapter 7).

Parameter names are matched ignoring case in both modes, as in M80: a parameter val is replaced wherever the body says val, VAL or Val.

16.9 Messages

Table 16.1 lists the messages about macros, each with the line that causes it.

Line

Message

macro with no name before it

MACRO without a name.

a macro name of 65 characters

a macro name may be at most 64 characters.

put: macro

EQU, DEFL and MACRO take a name, not a label.

a macro with 17 parameters

too many macro parameters.

bad macro a„b

bad macro parameter list.

a MACRO with no ENDM

macro definition not closed by ENDM.

ENDM with no MACRO

ENDM without a macro definition.

LOCAL after a line of the body

LOCAL must come before the macro body.

EXITM outside a macro

EXITM outside a macro or repeat block.

a macro that uses itself with no end

sources nested too deeply.

Table 16.1: Messages about macros.

When a line in an expansion causes an error, the message names the line of the body, in the file where the macro was defined, and the line below it says which macro it was and where it was used:

ERRIN.AS(4): ERROR: not a form this instruction has. 
    in bad, called from ERRIN.AS(8)
 

Chapter 20 describes these trails in full.