Tatara

第30章
マクロとリスティングのモード

マクロはソースの1行を複数の行に変え、繰り返しブロックは数行を多くの行に変えます。リスティング(18章)は、それが何に変わったかを示し、そのうちどれだけを示すかはソースで決められます。この章では、A:\TATARA\EXAMPLES\MACROSにある例、MACROSを使って、そのソースにあるマクロと繰り返しブロック、それが作るプログラム、そして同じ行を3つのリスティングのモードで見ていきます。

30.1 この例

MACROSは2行を表示し、それぞれのあとで少し待ちます。

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

この例には3つのファイルがあります。ソースのMACROS.AS、それをすべてリスティングする2行のソースLALL.AS、そしてプログラムと 2つのリスティングを作るBUILD.BATです。

30.2 ソース

; 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
 

ソースには、2つのマクロ、それを使うプログラム、そして3つの繰り返しブロックがあります。

LALL.ASは、同じプログラムの前に1行を加えたものです。

; 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 作って実行する

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は、コマンド・ラインの3番目に指定したファイルにリスティングを書き出します(18.1節)。MACROS.ASはMACXALL.LSTに、LALL.ASはMACLALL.LSTにアセンブルされ、リンクされるのはMACROS.TROだけです。

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.
 

プログラムは、0100hから0186hまでの135バイトです。

30.4 3つのリスティングのモード

どちらのリスティングも約33 KBあります。プログラムの前に2つのインクルード・ファイルが1行ずつリスティングされ、プログラム自身の行は339行目から始まります。INCLUDEの行を.XLISTと.LISTではさめば、それを省けます(18.3節)。以下の例は、それぞれのリスティングのうちプログラムの部分です。

30.4.1 標準の.XALL

MACXALL.LSTは、展開された行のうちバイトを作る行を、+を付けてリスティングします。

  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
 

ここには、ソースにない2つのことが表れています。delayのループのラベルは、1回目は??0000、2回目は??0001です。これがLOCALの作った名前です(16.5節)。そして、printのsystem _STROUTの行は、その2つの命令はリスティングされているのに、行そのものはリスティングされていません。その行自体はバイトを作らず、展開された行がバイトを作るからです。

繰り返しブロックも同じようにリスティングされます。書いたとおりのブロックのあとに、それが作った各行が続きます。

                                                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は、すべての展開のすべての行をリスティングします。このプログラムで違うのは、systemを使う行だけです。この行は自分ではバイトを作らないので、アドレスなしでリスティングされます。

  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
 

条件付きアセンブルを含むマクロでは、もっと違いが出ます。.LALLでは、条件によって飛ばされた行もリスティングされます(18.4節)。

30.4.3 .SALL

この例は3つ目のモードを使っていません。SALL.ASは、LALL.ASと同じく、1行と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は、どの展開の行もリスティングしません。マクロを使う各行には、リスティングに表れている以上のものがあることを示すため、+が付きます。

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

繰り返しブロックは書いたとおりにリスティングされ、それが作るバイトはリスティングのどこにも表れません。

図30.1に、1つの呼び出しについて3つのモードを並べて示します。

PIC

図 30.1: 呼び出しprint msg1について、それぞれのモードがリスティングするもの。

ふつうは.XALLを使います。すべてのバイトが、それを作った行の隣にリスティングされるからです。.LALLは、マクロが何をするかを、条件付きアセンブルも含めて1行ずつ調べるためのものです。.SALLは、マクロを信頼できるようになってから、ソースのように読めるリスティングを作るためのものです。3つは1つのソースの中で混ぜて使えます。それぞれ、その行から、3つのうち次のものが現れるまで効きます。

30.5 試してみること

次のファイルは例には含まれていません。BUILD.BATと同じようにTATARAを設定して、例のディレクトリに作ってください。

30.5.1 LOCALを外す

NOLOCAL.ASは、MACROS.ASからlocal loopの行を除いたものです。delayの1回目の使用でloopが定義され、2回目でもう一度定義されます。

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)
 

23行目はdelayの定義の中のloop:で、34行目は2回目のdelay 20000です(20.3節)。

30.5.2 &を外す

NOAMP.ASは、MACROS.ASのIRPCのdb ’&c’をdb ’c’にしたものです。エラーなしでアセンブルできますが、文字列の中のcはもうパラメーターではなく、ただの文字です。

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'
 

この例ではTATARAの6文字が入るところに、文字cである63hが 6バイト入ります。このような誤りではTATARAは止まらないので、見つける場所はリスティングです。