MASM で変数定義と PUBLIC 指定を同時にやるマクロ

タグ: #asm 

MASM では、some_func PROC PUBLIC と書いて、関数を書くと同時に他のモジュールから参照可能な公開扱いにすることができるが、どうも変数はそうではないらしい。 例えば hoge db 0 という変数があったとき、これを公開したければ PUBLIC hoge を別に書かなくてはならない。 そこで、MASM のマクロの勉強も兼ねて PUBVAR hoge db 0 のように書くと、hoge の PUBLIC 指定も同時にしてくれる PUBVAR マクロを作ってみることにした。

MASM の変数定義は 変数名 型 初期値 の形式で、例えば hoge db 100 と書くと、初期値が 100 の 1 バイト変数 hoge が定義される。 また、初期値の部分にカンマ区切りで複数の値を書くことができるので、手っ取り早い実装は、VARARG を用いて以下のようになるだろう。

PUBVAR MACRO varname:REQ, decl:VARARG
	PUBLIC varname
	varname decl
ENDM

PUBVAR	hoge, db 1
PUBVAR	fuga, db 2, 3, 4
PUBVAR	piyo, dw 10 dup (2)

実際、上記のマクロでも実用上割と問題はないと思わないではないのだが、マクロの引数が varname (変数名)と decl(変数の定義内容)に分かれているので、変数名の後にカンマが必要になっている。 PUBVAR を付けたり外したりするのに合わせてカンマを書いたり消したりするのは、個人的には面倒そうで気に食わない。

というわけで、カンマ無しで書ける版を作った。 このマクロは、変数定義のうち hoge db 1 といった変数名から1個目の初期値までの範囲を decl 引数に、さらにカンマ区切りで継続する初期値があればそれらを VARARGdecl2 引数に受け取る。 マクロ内では、decl の先頭から最初に見つかったスペースまたはタブの手前までの内容を PUBLIC に渡し、decldecl2 の内容を使って変数定義を行う。 文字列検索は @Instr でできるが、OR 検索のようなものはないので、スペースとタブ両方で検索を行い、最初に見つかった方を採用している。

PUBVAR MACRO decl:REQ, decl2:VARARG
	LOCAL pos, pos_sp, pos_tab
	pos_sp = @InStr(1, <decl>, < >)
	pos_tab = @InStr(1, <decl>, <	>)
	IF pos_sp EQ 0
		IF pos_tab EQ 0
			.ERR <space or tab was not found>
		ELSE
			pos = pos_tab
		ENDIF
	ELSEIF pos_tab EQ 0
		pos = pos_sp
	ELSE
		IF pos_sp LE pos_tab
			pos = pos_sp
		ELSE
			pos = pos_tab
		ENDIF
	ENDIF
	PUBLIC @SubStr(<decl>, 1, pos - 1)
	IFB <decl2>
		decl
	ELSE
		decl, decl2
	ENDIF
ENDM

PUBVAR	hoge	db 1
PUBVAR	fuga	db 2, 3, 4
PUBVAR	piyo	dw 10 dup (2)

今回の作業で、置換 + α 程度でないような MASM のマクロ機能を初めて幾つか使ってみたが結構高機能で頑張れば色々できそうなので、何か他にいい案が浮かんで便利なマクロができたら今後も類似の紹介記事を書くかもしれない。


投稿一覧に戻るトップに戻る