Tatara

Chapter 30
Macros and the listing modes

A macro turns one line of the source into several, and a repeat block turns a few lines into many. The listing (chapter 18) shows what they turned into, and how much of it is up to the source. This chapter follows both through MACROS, the example in A:\TATARA\EXAMPLES\MACROS: the macros and repeat blocks in its source, the program they make, and the same lines in the three listing modes.

30.1 The example

MACROS prints two lines, with a pause after each:

A:\TATARA\EXAMPLES\MACROS>macros 
A macro is a line that becomes many. 
LOCAL is why DELAY can be used twice.
 

The example has three files: the source, MACROS.AS; a second source of two lines, LALL.AS, that lists the first in full; and BUILD.BAT, which makes the program and two listings of it.

30.2 The source

; MACROS.AS - a line that becomes many. 
; 
; MACRO defines one, ENDM ends the definition, and the name is then 
; used like a mnemonic. LOCAL, REPT and IRP are below. 
 
                include msxdos.inc      ; _STROUT, _TERM0 and "system" 
                include ascii.inc       ; CHR_CR and CHR_LF 
 
; PRINT - three instructions from one line. The parameter is 
; substituted wherever the name appears in the body. 
 
print           macro   addr 
                ld      de,addr 
                system  _STROUT ; a macro inside a macro 
                endm 
 
; DELAY - and why LOCAL exists. The body has a label in it, and a 
; macro used twice would define that label twice. LOCAL makes a fresh 
; name for each expansion, so this may be used as often as you like. 
 
delay           macro   n 
                local   loop 
                ld      bc,n 
loop:           dec     bc 
                ld      a,b 
                or      c 
                jr      nz,loop 
                endm 
 
                cseg 
 
start:          print   msg1 
                delay   20000 
                print   msg2 
                delay   20000 
                system  _TERM0 
 
msg1:           db      "A macro is a line that becomes many.",CHR_CR,CHR_LF,"$" 
msg2:           db      "LOCAL is why DELAY can be used twice.",CHR_CR,CHR_LF,"$" 
 
; REPT repeats a body a counted number of times, with no parameter. 
; Neither it nor IRP takes a label: the body is what produces the 
; bytes, and a label belongs on a line inside it. 
 
                rept    8 
                db      0ffh 
                endm 
 
; IRP repeats it once for each item in the list, and IRPC once for 
; each character of a word. INSIDE A STRING the parameter is only 
; substituted if an ampersand is put in front of it, which is how M80 
; tells a parameter from two letters that happen to match. 
 
                irp     n,<1,2,4,8> 
                db      n 
                endm 
 
                irpc    c,TATARA 
                db      '&c' 
                endm 
                db      0 
 
                end     start
 

The source has two macros, a program that uses them, and three repeat blocks:

LALL.AS is the same program, with one line before it:

; LALL.AS - the same program, listed in full. 
; 
; .LALL asks for every line of every macro expansion, including the 
; ones that produce no bytes. The default is .XALL, which keeps only 
; the lines that emitted something. Nothing else here differs from 
; MACROS.AS, so the two listings differ only in what they show. 
 
                .lall 
                include macros.as
 

30.3 Building and running it

rem BUILD.BAT - EXAMPLE: MACROS 
rem 
rem The listing is the example here. /L writes one, and the file it 
rem goes to is named THIRD on the command line, after the source and 
rem the object. 
rem 
rem A listing shows the bytes a line produced, and a line that came 
rem out of a macro is marked with a +. HOW MUCH of an expansion is 
rem listed is a choice, and the source makes it three times: 
rem 
rem   .LALL   every line of every expansion 
rem   .XALL   only the lines that produced bytes (the default) 
rem   .SALL   none of them, only the call 
rem 
rem It is assembled twice, to two listings, so the two can be read 
rem side by side. 
 
rem The headers are in A:\TATARA\INCLUDE and are not copied here. 
rem TATARA is rule 3 of the include search - see the DIRS example. 
rem CHANGE THE PATH BELOW if you put the tree somewhere else. 
 
set TATARA=a:\tatara\include 
 
echo === Assembling, listing under the default XALL 
tatara /q /l macros.as macros.tro macxall.lst 
 
echo === Assembling again, listing everything 
tatara /q /l lall.as lall.tro maclall.lst 
 
echo === Linking 
tanren /q /o:macros.com macros.tro 
 
echo === Done. Compare MACXALL.LST with MACLALL.LST, then type MACROS. 
 
set TATARA=
 

/L writes a listing to the file named third on the command line (section 18.1). MACROS.AS is assembled into MACXALL.LST, and LALL.AS into MACLALL.LST; only MACROS.TRO is linked.

A:\TATARA\EXAMPLES\MACROS>build 
=== Assembling, listing under the default XALL 
=== Assembling again, listing everything 
=== Linking 
=== Done. Compare MACXALL.LST with MACLALL.LST, then type MACROS. 
A:\TATARA\EXAMPLES\MACROS>macros 
A macro is a line that becomes many. 
LOCAL is why DELAY can be used twice.
 

The program is 135 bytes long, from 0100h to 0186h.

30.4 The three listing modes

Each listing is about 33 KB. Both include files are listed, line by line, before the program: the program’s own lines start at line 339. .XLIST and .LIST around the INCLUDE lines would leave them out (section 18.3). The examples below are the program’s part of each listing.

30.4.1 .XALL, the default

MACXALL.LST lists the lines of each expansion that produce bytes, marked with +:

  0000'                         start:          print   msg1 
  0000'   11 25 00        +                     ld      de,msg1 
  0003'   0E 09           +                     ld      c,_STROUT 
  0005'   CD 05 00        +                     call    BDOS 
                                                delay   20000 
  0008'   01 20 4E        +                     ld      bc,20000 
  000B'   0B              +     ??0000:         dec     bc 
  000C'   78              +                     ld      a,b 
  000D'   B1              +                     or      c 
  000E'   20 FB           +                     jr      nz,??0000 
                                                print   msg2 
  0010'   11 4C 00        +                     ld      de,msg2 
  0013'   0E 09           +                     ld      c,_STROUT 
  0015'   CD 05 00        +                     call    BDOS 
                                                delay   20000 
  0018'   01 20 4E        +                     ld      bc,20000 
  001B'   0B              +     ??0001:         dec     bc 
  001C'   78              +                     ld      a,b 
  001D'   B1              +                     or      c 
  001E'   20 FB           +                     jr      nz,??0001 
                                                system  _TERM0 
  0020'   0E 00           +                     ld      c,_TERM0 
  0022'   CD 05 00        +                     call    BDOS
 

Two things show here that the source does not. The label of delay’s loop is ??0000 the first time and ??0001 the second: those are the names LOCAL made (section 16.5). And the system _STROUT line of print is not listed, although its two instructions are: the line itself produces no bytes, the lines of its expansion do.

The repeat blocks are listed the same way: the block as written, and then each line it produced:

                                                irpc    c,TATARA 
                                                db      '&c' 
                                                endm 
  0080'   54              +                     db      'T' 
  0081'   41              +                     db      'A' 
  0082'   54              +                     db      'T' 
  0083'   41              +                     db      'A' 
  0084'   52              +                     db      'R' 
  0085'   41              +                     db      'A' 
  0086'   00                                    db      0
 

30.4.2 .LALL

MACLALL.LST lists every line of every expansion. The only difference in this program is the line that uses system, listed without an address, because it produces no bytes of its own:

  0000'                         start:          print   msg1 
  0000'   11 25 00        +                     ld      de,msg1 
                          +                     system  _STROUT ; a macro inside a macro 
  0003'   0E 09           +                     ld      c,_STROUT 
  0005'   CD 05 00        +                     call    BDOS
 

A macro with a conditional in it shows more: under .LALL, the lines the conditional skipped are listed too (section 18.4).

30.4.3 .SALL

The example does not use the third mode. SALL.AS, like LALL.AS, is one line and the INCLUDE:

; SALL.AS - the same program, with no expansion listed. 
 
                .sall 
                include macros.as
 
A:\TATARA\EXAMPLES\MACROS>tatara /l sall.as sall.tro macsall.lst 
... 
ended at MACROS.AS(63)
 

MACSALL.LST lists no line of any expansion. Each line that uses a macro is marked with +, to show that there is more to it than the listing shows:

  0000'                   +     start:          print   msg1 
                          +                     delay   20000 
                          +                     print   msg2 
                          +                     delay   20000 
                          +                     system  _TERM0
 

The repeat blocks are listed as they are written, and none of the bytes they produce appear anywhere in the listing.

Figure 30.1 puts the three side by side for one call.

PIC

Figure 30.1: What each mode lists of the call print msg1.

.XALL is the usual choice: every byte is in the listing, next to the line that made it. .LALL is for finding out what a macro does, line by line, including its conditionals. .SALL is for a listing that reads like the source, once the macros are trusted. The three can be mixed in one source: each applies from its line to the next of the three.

30.5 Things to try

The files below are not part of the example: make them in its directory, with TATARA set as in BUILD.BAT.

30.5.1 Leave out LOCAL

NOLOCAL.AS is MACROS.AS without the line local loop. The first use of delay defines loop; the second defines it again:

A:\TATARA\EXAMPLES\MACROS>tatara nolocal.as nolocal.tro 
... 
NOLOCAL.AS(23): ERROR: this name already has a value. 
    in delay, called from NOLOCAL.AS(34)
 

Line 23 is loop: in the definition of delay, and line 34 is the second delay 20000 (section 20.3).

30.5.2 Leave out the &

NOAMP.AS is MACROS.AS with db ’c’ in place of db ’&c’ in the IRPC. It assembles without an error, but inside the string, c is no longer the parameter; it is the letter:

A:\TATARA\EXAMPLES\MACROS>tatara /l noamp.as noamp.tro noamp.lst 
... 
ended at NOAMP.AS(63)
 
                                                irpc    c,TATARA 
                                                db      'c' 
                                                endm 
  0080'   63              +                     db      'c' 
  0081'   63              +                     db      'c' 
  0082'   63              +                     db      'c' 
  0083'   63              +                     db      'c' 
  0084'   63              +                     db      'c' 
  0085'   63              +                     db      'c'
 

Six bytes of 63h, the letter c, where the example has the six letters of TATARA. A mistake like this one does not stop TATARA; the listing is where to see it.