STRUCTDAT, STRUCTPRM あたりを調べた

HSP on JS でそろそろユーザ定義命令・関数を実装するかーと思ったんで、理解が浅い STRUCTDAT, STRUCTPRM あたりを調べることにした。結構複雑。

STRUCTDAT

ユーザー定義命令・関数や DLL の関数、モジュール変数定義の情報。 ax の FINFO にこれの配列が格納されている。

//	DLL function flags
#define STRUCTDAT_OT_NONE 0
#define STRUCTDAT_OT_CLEANUP 1
#define STRUCTDAT_OT_STATEMENT 2
#define STRUCTDAT_OT_FUNCTION 4

//	Module function flags
#define STRUCTDAT_INDEX_FUNC -1
#define STRUCTDAT_INDEX_CFUNC -2
#define STRUCTDAT_INDEX_STRUCT -3
#define STRUCTDAT_FUNCFLAG_CLEANUP 0x10000

// function,module specific data
typedef struct STRUCTDAT {
	short	index;				// base LIBDAT index
	short	subid;				// struct index
	int		prmindex;			// STRUCTPRM index(MINFO)
	int		prmmax;				// number of STRUCTPRM
	int		nameidx;			// name index (DS)
	int		size;				// struct size (stack)
	int		otindex;			// OT index(Module) / cleanup flag(Dll)
	union {
	void	*proc;				// proc address
	int		funcflag;			// function flags(Module)
	};
} STRUCTDAT;
index
LINFO のインデックス。LINFO は LIBDAT の配列で、 LIBDAT は #uselib で定義した DLL 一つにつき一つ用意されている。ユーザ定義命令・関数の場合はこれが負数になり、 STRUCTDAT_INDEX_*** で定義された値になる。 STRUCTDAT_INDEX_FUNC はユーザ定義命令、STRUCTDAT_INDEX_CFUNCはユーザ定義関数、 STRUCTDAT_INDEX_STRUCT はモジュール変数の定義。
subid
FINFO のインデックス。または STRUCTPRM_SUBID_*** のいずれかの値。
prmindex
MINFO のインデックス。 MINFO は STRUCTPRM の配列で、パラメータの情報が格納されている。
prmmax
パラメータの数。 MINFO には prmindex から prmmax 個連続して STRUCTPRM が格納されている。
nameidx
関数名の DS オフセット。
size
すべてのパラメータの値を格納するのに必要なサイズ。たとえば、 #deffunc foo int a, double b, var c だったら sizeof(int) + sizeof(double) + sizeof(MPVarData) で 20 になる。
otindex
ラベルID (OT のインデックス)。 OT はラベルID の順に CS の位置が格納されている。ここから関数のコード位置を取得できる。DLL関数の場合、otindexには STRUCTDAT_OT_*** のフラグが格納されている。モジュール変数定義の場合、デストラクタの FINFO インデックスが格納されているようだ。
proc, funcflag
実行時に DLL 関数の関数ポインタを格納する場所である。 DLL 関数でなければ、 STRUCTDAT_FUNCFLAG_*** のフラグが格納されている。

STRUCTPRM

DLL 命令・関数やユーザ定義命令・関数のパラメータに関する情報。 ax の MINFO にこれの配列が格納されている。

typedef struct STRUCTPRM {
	short	mptype;				// Parameter type
	short	subid;				// struct index
	int		offset;				// offset from top
} STRUCTPRM;
mptype
パラメータのタイプ。MPTYPE_*** のいずれかの値。
subid
FINFO のインデックス。または STRUCTPRM_SUBID_*** のいずれかの値。
offset
同じ関数の先頭パラメータからのオフセット。たとえば、 #deffunc foo int a, double b, var c だったら int a は 0, double b は sizeof(int) で 4, var c は sizeof(int) + sizeof(double) で 12。

MPTYPE 一覧

名前 説明
MPTYPE_NONE 0
MPTYPE_VAR 1
MPTYPE_STRING 2
MPTYPE_DNUM 3 double
MPTYPE_INUM 4 int
MPTYPE_STRUCT 5
MPTYPE_LABEL 7 label
MPTYPE_LOCALVAR -1 ユーザ定義関数の local
MPTYPE_ARRAYVAR -2 ユーザ定義関数の array
MPTYPE_SINGLEVAR -3 ユーザ定義関数の var
MPTYPE_FLOAT -4 DLL 関数の float
MPTYPE_STRUCTTAG -5 モジュール変数定義の最初につけられるパラメータ。*1
MPTYPE_LOCALSTRING -6 str
MPTYPE_MODULEVAR -7 #modfunc の最初につけられるパラメータ
MPTYPE_PPVAL -8 DLL 関数の pval
MPTYPE_PBMSCR -9 DLL 関数の bmscr
MPTYPE_PVARPTR -10 DLL 関数の var
MPTYPE_IMODULEVAR -11 #modinit の最初につけられるパラメータ
MPTYPE_IOBJECTVAR -12 DLL 関数の comobj *2
MPTYPE_LOCALWSTR -13 DLL 関数の wstr
MPTYPE_FLEXSPTR -14 DLL 関数の sptr
MPTYPE_FLEXWPTR -15 DLL 関数の wptr
MPTYPE_PTR_REFSTR -16 DLL 関数の prefstr
MPTYPE_PTR_EXINFO -17 DLL 関数の pexinfo
MPTYPE_PTR_DPMINFO -18 #func に数値を指定したとき 0x20 を立てると第四引数がこれになる
MPTYPE_NULLPTR -19 DLL 関数の nullptr
MPTYPE_TMODULEVAR -20 #modterm の最初につけられるパラメータ

MPTYPE_STRING や MPTYPE_STRUCT は ax には現れることはないが、実行時に内部で使っているようだ。
MPTYPE_STRING, MPTYPE_DNUM, MPTYPE_INUM, MPTYPE_STRUCT は HSPVAR_FLAG_STR, HSPVAR_FLAG_DOUBLE, HSPVAR_FLAG_INT, HSPVAR_FLAG_STRUCT と同じ値である。 MPTYPE_LABEL と HSPVAR_FLAG_LABEL は違う値。

STRUCTPRM_SUBID_***

STRUCTDAT や STRUCTPRM の subid メンバに格納されることがある値。
STRUCTPRM_SUBID_STACK は TYPE_STRUCT でモジュール変数のメンバか、関数のパラメータかを識別するためにあるようだ。ユーザ定義命令・関数の STRUCTDAT::subid やそのパラメータの STRUCTPRM::subid はすべて STRUCTPRM_SUBID_STACK になっていた。ユーザ定義命令・関数のSTRUCTDAT::subidは STRUCTPRM_SUBID_STACK ではなく、 FINFO ID でした。勘違いしてました。ただし、mptype が MPTYPE_MODULEVAR, MPTYPE_IMODULEVAR, MPTYPE_TMODULEVAR のいずれかである STRUCTPRM では subid にモジュール変数定義の FINFO インデックスが格納されていた。
STRUCTPRM_SUBID_STID はコンパイル中に内部で使用するためのものらしい。ひとまず STRUCTPRM_SUBID_STID を格納しておいて、後からそれを FINFO インデックスに置き換えるようだ。

#define STRUCTPRM_SUBID_STACK -1
#define STRUCTPRM_SUBID_STID -2
#define STRUCTPRM_SUBID_DLL -3
#define STRUCTPRM_SUBID_DLLINIT -4
#define STRUCTPRM_SUBID_OLDDLL -5
#define STRUCTPRM_SUBID_OLDDLLINIT -6
#define STRUCTPRM_SUBID_COMOBJ -7

*1:offsetにコンストラクタのFINFOインデックスを格納するためのもの?

*2:#comfunc の最初にもつけられる?