タイトル通りです。
ちなみにマクロは使用していません。
タイトル通りです。
ちなみにマクロは使用していません。
//-----------------------------------------------------------------------------------------// 可変長引数(笑) |// 2015/07/04 Flat |//-----------------------------------------------------------------------------------------/*■特徴コードセグメントを直に読みますですので無限に引数を付けられます更にあらゆる型の引数を受け付けます言い換えれば型の自動変換がありません尤も、あらゆる型を受け付けられてもその型の処理ができなければ意味がありませんがね!■使用できる型現在対応している型は・空引数・ユーザー定義命令・関数・変数、配列(※)・その他HSPの変数に格納できる全ての型となりますvfunc関数を編集すれば他の型にも対応可能です※配列は正常に動作しないことがあります(文字列型など)おそらくHSPのバグまたは仕様なので、ランタイムの方を編集してください■注意・vfuncから呼び出された関数の中でvfuncを呼び出すとreturn時に死にますこれはvfuncから他の関数を呼び出す際に定義情報を無理矢理書き換えている関係です根本的な解決策は現在見つかっていません…・関数内からvfuncを呼び出す際、引数に関数の引数(ローカル変数含む)は使えませんこれは引数の評価処理がvfunc内部で行われているためで、根本的な解決策は(略)■その他vfuncは命令形式の呼び出しですが、少し書き換えるだけで関数形式の呼び出しにできますつまり、今まで夢だった関数へのラベル渡しもできます■使い方使い方はサンプルを見たほうが早いので、ここでは割愛します*/// 引数格納庫// タイプが-1のときは引数の変数をクローンする#module ParameterStore m_type, m_var#modinit int p_type, array p_varm_type = p_typeif m_type == -1 {dup m_var, p_var} else {m_var = p_var}return#modcfunc gettypereturn m_type#modcfunc getparamreturn m_var#modfunc dupparam var p_vardup p_var, m_varreturn#global// 可変長引数モジュール#module Variadic// PVal取得関数// http://d.hatena.ne.jp/chaperatta/20081012/1223803468#defcfunc local getpval var#deffunc local _getpval int p_pvalreturn p_pval// コールバック用ダミー関数#deffunc local callbackreturn// 可変長引数で任意の関数を呼び出す関数// vfunc 呼び出す関数, 引数1, 引数2, 引数3, …#deffunc vfunc \local param, local param_index, local param_num, \local hspctx, local hsphed, local mcs, local cs, local callback_st, \local pcs, local old_pcs, local code_num, \local info, local is48, local ex0, local ex1, local ex2, local type, local code, \local params, local size, local label, local vtype, local bytecode, local func_st, \local flag, local t_offset, local t_type, local t_code, \local func// ローカル変数paramのインデックスを取得// 次がparamの参照となるようなラベルを作成newlab label, 0param = 0// その場所のコードを取得dupptr cs, lpeek(label, 0), 6, 2// インデックス(=Code)を取得if wpeek(cs, 0) & 0x8000 {param_index = lpeek(cs, 2)} else {param_index = wpeek(cs, 2)}// CSを取得// HSPCTX取得mref hspctx, 68// HSPHED取得dupptr hsphed, hspctx(0), 96, 4// 関数呼び出し元のCSポインタ取得dupptr mcs, hspctx(207) - 16, 4// CSポインタからCSを取得dupptr cs, mcs, hsphed(5) - (hspctx(2) - mcs)// CSをなめる// http://codetter.com/?p=1165 からパクったpcs = 0old_pcs = 0param_num = 0code_num = 0repeat// ExやType等取得info = wpeek(cs, pcs)is48 = info & 0x8000ex2 = info & 0x4000ex1 = info & 0x2000ex0 = info & 0x1000type = info & 0x0FFF// 引数の区切りif ex1 | ex2 {// 引数のコードサイズsize = pcs - old_pcs// 例外処理vtype = 0switch wpeek(cs, old_pcs) & 0x0FFF// 空引数case 0if wpeek(cs, old_pcs) & 0x8000 {t_code = lpeek(cs, old_pcs + 2)} else {t_code = wpeek(cs, old_pcs + 2)}if t_code != 0x3F : swbreak// とりあえず0にでもしておくparam = 0// vtypeセットvtype = -3swbreak// 変数及び配列の要素case 1/*TYPE_VAR*/flag = 0if code_num == 1 {// 変数flag = 1} else : if code_num >= 4 {// 配列の要素?// TYPE_VARの直後が'('で末尾が')'なら配列の要素とみなす// a(3) * a(2) などはコンパイル後 a(3) a(2) * となるので問題はなさそうflag = 1t_offset = old_pcsrepeat code_numt_type = wpeek(cs, t_offset) & 0x0FFFif wpeek(cs, t_offset) & 0x8000 {t_code = lpeek(cs, t_offset + 2)t_offset += 6} else {t_code = wpeek(cs, t_offset + 2)t_offset += 4}if type == 11/*TYPE_CMPCMD*/ {t_offset += 2}switch cnt// 先頭のチェックcase 1if t_type == 0x000 : swbreakif t_code == 0x0028 : swbreakflag = 0break// 末尾のチェックcase code_num - 1if t_type == 0x000 : swbreakif t_code == 0x0029 : swbreakflag = 0breakswendloop}if flag {// バイトコードの生成sdim bytecode, size + 18wpoke bytecode, 0, 0x200F // dupwpoke bytecode, 2, 0x000Ewpoke bytecode, 4, 0x8005 // paramlpoke bytecode, 6, param_indexmemcpy bytecode, cs, size, 10, old_pcs // 変数、配列の要素wpoke bytecode, size + 10, 0x200F // returnwpoke bytecode, size + 12, 0x0002wpoke bytecode, size + 14, 0x200F // return(なんでもいいので何かひとつ必要)wpoke bytecode, size + 16, 0x0002// 先頭のEx2フラグを立てるwpoke bytecode, 10, wpeek(bytecode, 10) | 0x4000// バイトコード呼び出しnewlab label, 0lpoke label, 0, varptr(bytecode)gosub label// vtypeセットvtype = -1}swbreak// ユーザー定義関数case 12/*TYPE_MODCMD*/if code_num != 1 : swbreak// バイトコードの生成sdim bytecode, size + 20wpoke bytecode, 0, 0x200F // returnwpoke bytecode, 2, 0x0002wpoke bytecode, 4, 0x0011 // libptrwpoke bytecode, 6, 0x0103wpoke bytecode, 8, 0x0000 // (wpoke bytecode, 10, 0x0028memcpy bytecode, cs, size, 12, old_pcs // 関数wpoke bytecode, size + 12, 0x0000 // )wpoke bytecode, size + 14, 0x0029wpoke bytecode, size + 16, 0x200F // return(なんでもいいので何かひとつ必要)wpoke bytecode, size + 18, 0x0002// 先頭のEx2フラグを下ろすwpoke bytecode, 12, wpeek(bytecode, 12) & 0xBFFF// バイトコード呼び出しnewlab label, 0lpoke label, 0, varptr(bytecode)gosub label// param、vtypeセットparam = statvtype = -2swbreakswendif vtype == 0 {// バイトコードの生成sdim bytecode, size + 18wpoke bytecode, 0, 0xA005 // paramlpoke bytecode, 2, param_indexwpoke bytecode, 6, 0x0000 // =wpoke bytecode, 8, 0x0008memcpy bytecode, cs, size, 10, old_pcs // 引数wpoke bytecode, size + 10, 0x200F // returnwpoke bytecode, size + 12, 0x0002wpoke bytecode, size + 14, 0x200F // return(なんでもいいので何かひとつ必要)wpoke bytecode, size + 16, 0x0002// 先頭のEx2フラグを下ろすwpoke bytecode, 10, wpeek(bytecode, 10) & 0xBFFF// バイトコード呼び出しnewlab label, 0lpoke label, 0, varptr(bytecode)gosub label// vtypeセットvtype = vartype(param)}// 処理if param_num < 1 {// vfuncが使用する引数switch param_num// 最初の引数(呼び出す関数)case 0if (vtype != -2) && (vartype(param) != 4) {// エラーを引き起こす_errorfunc@Variadic 123}func = paramswbreakswend} else {// ユーザー定義関数に渡す引数newmod params, ParameterStore, vtype, param}// paramクリアdim param// 情報更新code_num = 0old_pcs = pcsparam_num++}// 引数終了if ex1 {break}// ポインタを進めるpcs += 2// Code取得if is48 {code = lpeek(cs, pcs)pcs += 4} else {code = wpeek(cs, pcs)pcs += 2}// TYPE_CMPCMDのときはジャンプ先が記録されている// 一応書いておいたが、不要かもしれないif type == 11/*TYPE_CMPCMD*/ {pcs += 2}// デバッグ用;mes strf("%08X %d %d %d %d %4d %08X", pcs, is48!=0, ex0!=0, ex1!=0, ex2!=0, type, code)// コード数更新(あとで使用する)code_num++loop// 引数不足のチェックif param_num < 1 {// エラーを引き起こす_errorfunc@Variadicreturn}// callbackを弄るdupptr callback_st, libptr(callback@Variadic), 28, 2dupptr func_st, func, 28, 2memcpy callback_st, func_st, 28// callback呼び出しcallback@Variadic params// 引数解放foreach paramsdelmod params(cnt)loop// 戻り先を修正mcs += pcsreturn#deffunc local _errorfunc str areturn#global// 以下サンプル、#if 0を#if 1にして動作#if 0// テスト関数#module#deffunc testfunc array p_params, \local type, local varmes strf("NUM OF PARAMS: %d", length(p_params))foreach p_params// 引数の種類を取得type = gettype(p_params(cnt))// 引数を変数にクローンdupparam p_params(cnt), var// 表示してみるswitch typecase -3mes strf("TYPE: EMPTY")swbreakcase -2mes strf("TYPE: FUNCTION, PTR TO STRUCTDAT: %08X", var)swbreakcase -1if length(var) > 1 {mes strf("TYPE: ARRAY[%d], DATA[0]: %s", length(var), str(var(0)))} else {mes strf("TYPE: VARIABLE, DATA: %s", str(var))}swbreakcase 1mes strf("TYPE: LABEL, DESTINATION: %08X", lpeek(var, 0))swbreakcase 2mes strf("TYPE: STRING, DATA: %s", var)swbreakcase 3mes strf("TYPE: DOUBLE, DATA: %g", var)swbreakcase 4mes strf("TYPE: INTEGER, DATA: %d", var)swbreakdefaultmes strf("TYPE: %d", var)swbreakswendloopreturn#global*labelabc = "a", "b", "c"def = 1, 2, 3, 4vfunc testfunc, 2, "xyz", 3.14, *label, 4 * 5, "3" + 4, 4.6mesvfunc testfunc, abc, def, abc(1), def(2), testfuncmesvfunc testfunc, , , , 5mes#endif