Tatara

第16章
マクロ

マクロ(macro)は、行のまとまりに付けた名前です。まとまりを定義すると、その名前を命令と同じように使えるようになり、TATARAはそれぞれの使用をそのまとまりの行に置き換えます。1回の使用からできたものを展開(expansion)と呼びます。

14章のsystemマクロもその1つです。system _STROUTは、ld c,_STROUTとcall BDOSに置き換えられます。マクロはサブルーチンではありません。サブルーチンはプログラムの中に1つだけあり、callで呼び出します。マクロの行は、使うたびにプログラムの中にもう一度置かれます。マクロで省けるのは入力の手間で、バイト数ではありません。

この章では、マクロの定義のしかた、マクロへの値の渡し方、マクロの中で使う疑似命令を説明します。名前を付けずに行を繰り返すREPT、IRP、IRPCは17章で説明します。これらも、引数、LOCAL、EXITMについては同じ規則に従います。

16.1 マクロの定義と使用

マクロはMACROで定義します。MACROの前にはマクロの名前を、あとにはコンマで区切ったパラメーター(parameter)の名前を書きます。それに続く行がマクロの本体(body)で、ENDMで終わります。

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

EQUと同じように、名前はコロンを付けずに書きます(12章)。定義はバイトを作りません。TATARAは本体を保存するだけです。マクロは、最初に使う前に定義しておかなければなりません。

マクロを使うには、その名前を命令のように書き、そのあとに引数(argument)、つまり今回の使用でパラメーターが表す値を書きます。TATARAは本体の中のそれぞれのパラメーターを、対応する引数に置き換えます。1番目のパラメーターには1番目の引数、2番目には 2番目の引数が対応します(図16.1)。

PIC

図 16.1: マクロの定義、その使用、そして展開

リスティングには、それぞれの使用のあとにその展開が表示され、作られた行には+の印が付きます。

                                                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
 

展開をリスティングに少なく表示する方法や、まったく表示しない方法は、18章で説明します。

16.2 引数

使用のときの引数はコンマで区切ります。引数の前の空白は引数に含まれません。

次のマクロは、1番目の引数をDBに入れ、2番目の引数があればもう1つのDBに入れます。

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

次の使用では、show 3はbを空にし、show 4,5,6の6は無視され、<7,8>は1つの引数になり、’!>’は>を含む文字列を渡します。

                                                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
 

引数は値ではなくテキストです。five*2は、five*2という 6文字として渡されます。引数の前に%を付けると、代わりにその値が 10進数で書かれて渡されます。本体がdb ’&x’のとき(&は次の節で説明します)、次の1つ目の使用はテキストを、2つ目は値を渡します。

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

その値は、IFの場合と同じように、TATARAがすでに知っているものでなければなりません(15章)。

16.3 &によるテキストの連結

パラメーターが置き換えられるのは、その名前が独立した語になっているところだけです。ほかのテキストとつなげるには、その間に&を書きます。引数が1なら、lab&nはlab1になります。&自体は消えます。

文字列の中のパラメーターは、&でつながない限り、まったく置き換えられません。文字列’n’のnはただの文字ですが、’&n’のnはパラメーターです。

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

16.4 本体の中のコメント

;で始まるコメントは本体に残り、すべての展開に現れます。;;で始まるコメントはマクロを定義するときに捨てられるので、定義の中でしか見えません。マクロのしくみについてのメモのように、リスティングで繰り返されても意味のないものには;;を使います。

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

16.5 LOCAL

ラベルを定義するマクロは、1回しか使えません。2回目の使用でそのラベルをもう一度定義することになるからです(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)
 

これは、1つ以上の名前を続けたLOCALで解決します。TATARAは、それぞれの展開の中でそれらの名前を、??0000、??0001のように、毎回違う新しい名前に置き換えます。

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
 

作られた名前はふつうのラベルで、シンボル表にも表示されます。自分のラベルには??で始まる名前を使わないでください。LOCALの行は、本体の最初、ほかのどの行よりも前に書かなければなりません。そうでないと、TATARAはLOCAL must come before the macro body.と表示して止まります。

16.6 EXITM

EXITMは、展開をすぐに終わらせます。本体のそれ以降の行は使われません。条件付きアセンブルの中で使い、場合によってマクロを早めに終わらせます。次のマクロは、引数が与えられないと何もしません。

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

15章のテキストの判定が役に立つのは、ここです。IFBとIFNBは引数が与えられたかどうかを調べ、IFIDNとIFDIFは引数をレジスター名のような決まったテキストと比べます。EXITMは、マクロの中で開いたままの条件付きアセンブルも一緒に閉じます。

16.7 マクロの中のマクロ

マクロの本体では、別のマクロを使うことも、定義することもできます。

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
 

ここでは、pair 1,2はbyteを通してdb 1とdb 2を作ります。maker three,3はバイトを作りませんが、threeというマクロを定義し、そのthreeがdb 3を作ります。本体の中のMACROの行は、本体が展開されるまではただのテキストです。それぞれのENDMは、いちばん内側のMACROに対応します。

マクロは自分自身を使うこともできます。その場合は、止めるための条件が必要です。次のマクロは0まで数え下ります。

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
 

展開の中の展開は、インクルード・ファイルと合わせて16段まで重ねられます。止める条件がないと、自分自身を使うマクロはこの制限に達し、TATARAはsources nested too deeply.と表示して止まります。

マクロは定義し直すことができ、その行からは新しい定義が古い定義に置き換わります。systemマクロはこれを利用しています。MSXDOS.INCを取り込むそれぞれのモジュールが、マクロを定義し直すからです(14章)。

16.8 大文字と小文字

マクロの名前は、ほかの名前と同じ規則に従います。/CがなければPUTでマクロputを使えますが、/Cがあると使えず、TATARAはnot a directive, a macro or an instruction.と表示して止まります(7章)。

パラメーターの名前は、M80と同じように、どちらのモードでも大文字と小文字を区別せずに照合されます。パラメーターvalは、本体にval、VAL、Valのどれで書いても置き換えられます。

16.9 メッセージ

マクロについてのメッセージを、それぞれの原因となる行とともに表16.1に示します。

行

メッセージ

前に名前のないmacro

MACRO without a name.

65文字のマクロの名前

a macro name may be at most 64 characters.

put: macro

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

パラメーターが17個の
マクロ

too many macro parameters.

bad macro a„b

bad macro parameter list.

ENDMのない
MACRO

macro definition not closed by ENDM.

MACROのない
ENDM

ENDM without a macro definition.

本体の行のあとの
LOCAL

LOCAL must come before the macro body.

マクロの外のEXITM

EXITM outside a macro or repeat block.

終わりなく自分自身を
使うマクロ

sources nested too deeply.

表 16.1: マクロについてのメッセージ

展開の中の行がエラーを起こすと、メッセージはマクロを定義したファイルの中の本体の行を示し、その下の行が、どのマクロのどこでの使用かを示します。

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

この経路の詳しい読み方は、20章で説明します。