文字列で構造体のシンボルを指定して構造体の中のデータを参照したり 関数を呼び出したりできるようにします。
Sym が動的に構造体の内容を参照できるようにするに、 構造体の構成を登録しておく必要があります。 登録するには、SYM_STRUCT 系マクロを使用して 関数(〜_registSymStruct)を定義し、その関数を 呼び出します。
ヘッダファイル中に、以下のようなプロトタイプ宣言をします。
extern Sym_Struct* Struct_registSymStruct( Sym* ); // (構造体型名) + _registSymStruct extern Sym_Struct Struct_symStruct; // (構造体型名) + _symStruct |
ソースファイル中に次のように記述すると Struct_registSym (構造体型名+_registSymStruct)関数を定義します。
SYM_STRUCT_START( Struct ) SYM_STRUCT_LOOP_FUNC( Struct, Struct_doLoopFunc ) SYM_STRUCT_MEMB_FUNC( Struct, Struct_doReadMemb, NULL ) SYM_STRUCT_MEMB( Struct, int, name ) SYM_STRUCT_MEMB( Struct, void*, adr ) SYM_STRUCT_ST( Struct, Sub, sub ) SYM_STRUCT_STP( Struct, Sub, sub_p ) // Sub* 型 SYM_STRUCT_STP_ST( Struct, ListX, Sub, sub_p ) // ListX* 集合 Sub 型要素 SYM_STRUCT_END( Struct ) |
初期化関数で、動的参照構造体を登録するとよいでしょう。
void Struct_init( Struct* this )
{
static int bStart = 1;
if ( bStart ) { Struct_registSymStruct( &sym ); bStart = 0; }
Sym_registVar( &sym, "Struct", "take", this );
}
|
後始末関数で、動的参照構造体の登録を解除するとよいでしょう。
void Struct_finish( Struct* this )
{
Sym_unregistVar( &sym, "take" );
}
|
集合を走査する関数(
/************************************************************************ * <<< [ListX_doLoopFunc] SYM_STRUCT_LOOP_FUNC に指定する関数 >>> *【引数】 * ・Sym_Ref* container; 集合クラスの参照、または配列の先頭アドレス * ・Sym_Ref* elem; ループ変数(要素の参照)(入出力) * ・bool 返り値; 次の要素があったかどうか ************************************************************************/ #ifdef USES_SYM bool ListX_doLoopFunc( Sym_Ref* container, Sym_Ref* elem ) { ListX* this; if ( container->type == Sym_StructType ) this = container->adr; else this = *(ListX**)container->adr; if ( elem->adr == NULL ) elem->adr = this->first; else elem->adr = Offset_ref( (Offset)container->elem_param, elem->adr, void* ); return elem->adr != NULL; } #endif |
SYM_STRUCT マクロを使って静的に定義される構造体のメンバ変数を
取得できますが、動的にメンバ変数が変化する場合は、
/************************************************************************ * <<< [Xxx_doReadMemb] SYM_STRUCT_MEMB_FUNC に指定する関数 >>> *【引数】 * ・Sym_Ref* obj; 構造体の参照 * ・char* name; メンバ変数名(変更不可) * ・Sym_Ref* ret; メンバ変数(出力) ************************************************************************/ #ifdef USES_SYM void Xxx_doReadMemb( Sym_Ref* obj, char* name, Sym_Ref* ret ) { Xxx* this = obj->adr; if ( strcmp( name, "memb" ) == 0 ) { ret->adr = "memb"; ret->type = Sym_CharP; } } #endif |
メンバ変数設定関数(
プロパティを参照する関数(
void Sym_Struct_getNextProp( void* obj, void* ret ) { Sym_Struct* this = obj; // オブジェクトの型にキャスト *(char**)ret = this->name + 1; // プロパティの型へのポインタ型にキャストして格納 } |
ヘッダファイル中に、以下のようなプロトタイプ宣言をします。
Sym_Func* symbol_registSymFunc( Sym* ); // (シンボル名) + _registSymFunc |
ソースファイル中に次のように記述すると atoi_registSymFunc 関数 (シンボル名+_registSymFunc)を定義します。
SYM_FUNC_START_R1( atoi, int, atoi, String ) SYM_FUNC_STRUCT_ARG( atoi, 1, String ) SYM_FUNC_END( atoi ) |
登録されたデータは、Sym_getRef 関数で取得します。
Sym_getRef 関数の内部では、Sym_getVar 関数で構造体のトップを
取得し、Sym_Ref_getRef 関数でメンバ変数を Sym_Ref 型で取得します。