第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)。
リスティングには、それぞれの使用のあとにその展開が表示され、作られた行には+の印が付きます。
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 引数
使用のときの引数はコンマで区切ります。引数の前の空白は引数に含まれません。
- 省略した引数は空になります。パラメーターは何もないものに置き換えられるので、本体はそれに対応していなければなりません。本体にdb 0,bがあると、bが空のときはdb 0,となり、TATARAはこれを受け付けません。空かどうかはIFBとIFNBで調べられます(16.6節)。
- 最後のパラメーターより多い引数は、M80と同じように無視されます。
- コンマを含む引数は山かっこで囲みます。かっこは取り除かれます。<7,8>は、7,8という1つの引数です。
- 文字の前に!を付けると、その文字は何であっても引数の一部になります。本来なら引数を終わらせる>やコンマ、本来ならコメントを始めるセミコロンなどです。山かっこの中のセミコロンも引数の一部です。
次のマクロは、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. |
| macro definition not closed by ENDM. |
|
| ENDM without a macro definition. |
|
| LOCAL must come before the macro body. |
|
| EXITM outside a macro or repeat block. |
|
終わりなく自分自身を |
sources nested too deeply. |
展開の中の行がエラーを起こすと、メッセージはマクロを定義したファイルの中の本体の行を示し、その下の行が、どのマクロのどこでの使用かを示します。
ERRIN.AS(4): ERROR: not a form this instruction has. in bad, called from ERRIN.AS(8)
この経路の詳しい読み方は、20章で説明します。