後ろで定義されている関数を呼び出せるようにするパッチ
改良しました -> 後ろで定義されている関数を呼び出せるようにするパッチ その2 - fujidigの雑記
だいたい以下のような仕組みです。
- プリプロセス時のラベル情報を使って関数の名前を type = TYPE_MODCMD, opt = -1 で登録
- opt = -1 の関数の呼び出しがあったら FINFO にダミー登録。 opt をその FINFO ID に更新
- ダミー登録済みの関数の #deffunc があったらダミー登録に上書き
ただこれだけだと以下のようなのは動くんですが、
f stop #module #deffunc f return #global
以下のようにモジュール内で呼び出すと動きません。
#module #deffunc f g return #deffunc g return #global f
なぜかというとプリプロセス後に「g」が「g@m0」になっちゃうからです。「g@」と書けば動くんですが、それでは駄目ですよね。そこでちょっと小細工を入れて動くようにしています。 ExpandToken の変更や SearchSymbolOrRegisterVar のあたりです。
以下のような小細工を入れています:
- プリプロセス時にモジュール内で@をつけていない識別子は終端に@をつけるようにします。たとえば "foo" は "foo@modname@" になります。
- コンパイル時に "foo@modname@" という形式になっている識別子は、まず "foo" という名前の関数を探し、それがなければ "foo@modname" という名前の識別子を使うようにしています。
Index: token.cpp =================================================================== --- token.cpp (revision 241) +++ token.cpp (working copy) @@ -1348,6 +1348,11 @@ char *CToken::ExpandToken( char *str, in if (wrtbuf!=NULL) { // AddModuleName( (char *)s2 ); wrtbuf->PutStr( fixname ); + if ( strcmp( (char *)s2, fixname ) ) { + // 後ろで定義されている関数の呼び出しのために + // モジュール内の foo はプリプロセス済みソースで foo@modname@ とする + wrtbuf->Put( '@' ); + } // wrtbuf->Put( '?' ); } *type = TK_OBJ; Index: codegen.cpp =================================================================== --- codegen.cpp (revision 241) +++ codegen.cpp (working copy) @@ -160,17 +160,9 @@ void CToken::CalcCG_factor( CGVAR &v ) CalcCG_token(); return; case TK_OBJ: - id = lb->Search( cg_str ); - if ( id < 0 ) { - //Mesf( "[%s][%d]",cg_str, cg_valcnt ); - id = lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - v.curtype = TYPE_VAR; - v.ival = cg_valcnt; - cg_valcnt++; - } else { - v.curtype = lb->GetType( id ); - v.ival = lb->GetOpt(id); - } + id = SearchSymbolOrRegisterVar( cg_str ); + v.curtype = lb->GetType( id ); + v.ival = lb->GetOpt(id); if ( v.minflag ) { if ( v.cnt > 0 ) { ttype=TK_CALCERROR; return; @@ -339,6 +331,63 @@ void CToken::CalcCG( int ex ) //----------------------------------------------------------------------------- +int CToken::SymbolEndsWithAtMark( char *name, int *len ) +{ + // シンボルが foo@modname@ という形式になっているか + // + unsigned char *p = (unsigned char *)name; + int state = 0; + while ( *p != '\0' ) { + unsigned char c = *p; + if ( c == '@' ) { + if ( state % 2 == 0 ) return 0; + if ( state == 1 ) { + state = 2; + *len = (int)((char *)p - name); + } + if ( state == 3 ) { + return *(p+1) == '\0'; + } + } else if ( state % 2 == 0 ) { + state ++; + } + if ( issjisleadbyte(c) ) { + p += 2; + } else { + p ++; + } + } + return 0; +} + + +int CToken::SearchSymbolOrRegisterVar( char *name ) +{ + int id = lb->Search( name ); + int len; + char new_name[256]; + if ( SymbolEndsWithAtMark( name, &len ) ) { + // "foo@modname@" というシンボルに対して、 + // まず "foo" という関数がないか探し、次に "foo@modname" というシンボルを探す + strcpy2( new_name, name, sizeof new_name ); + new_name[len] = '\0'; + id = lb->Search( new_name ); + if ( id >= 0 && lb->GetType(id) == TYPE_MODCMD ) { + return id; + } + new_name[len] = '@'; + new_name[strlen(new_name)-1] = '\0'; + id = lb->Search( new_name ); + name = new_name; + } + if ( id < 0 ) { + id = lb->Regist( name, TYPE_VAR, cg_valcnt ); + cg_valcnt++; + } + return id; +} + + char *CToken::PickLongStringCG( char *str ) { // 指定文字列をmembufへ展開する @@ -924,15 +973,11 @@ void CToken::GenerateCodePRMF2( void ) GetTokenCG( GETTOKEN_NOFLOAT ); break; case TK_OBJ: - id = lb->Search( cg_str ); - if ( id < 0 ) { - id = lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - cg_valcnt++; - } + id = SearchSymbolOrRegisterVar( cg_str ); t = lb->GetType(id); if (( t == TYPE_XLABEL )||( t == TYPE_LABEL )) throw CGERROR_LABELNAME; - PutCS( t, lb->GetOpt(id), ex ); + PutCSSymbol( id, ex ); GetTokenCG( GETTOKEN_DEFAULT ); if ( ttype == TK_NONE ) { @@ -971,11 +1016,7 @@ void CToken::GenerateCodePRMF3( void ) GetTokenCG( GETTOKEN_DEFAULT ); if ( ttype != TK_OBJ ) throw CGERROR_PP_BAD_STRUCT_SOURCE; - id = lb->Search( cg_str ); - if ( id < 0 ) { - id = lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - cg_valcnt++; - } + id = SearchSymbolOrRegisterVar( cg_str ); GenerateCodeVAR( id, ex ); if ( ttype != TK_NONE ) throw CGERROR_PP_BAD_STRUCT_SOURCE; @@ -1052,11 +1093,7 @@ void CToken::GenerateCodeMethod( void ) GetTokenCG( GETTOKEN_DEFAULT ); break; case TK_OBJ: - id = lb->Search( cg_str ); - if ( id < 0 ) { - id = lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - cg_valcnt++; - } + id = SearchSymbolOrRegisterVar( cg_str ); GenerateCodeVAR( id, ex ); break; default: @@ -1130,16 +1167,10 @@ void CToken::GenerateCodePRMN( void ) ex = 0; break; case TK_OBJ: - i = lb->Search( cg_str ); - if ( i < 0 ) { - lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - PutCS( TYPE_VAR, cg_valcnt, ex ); - cg_valcnt++; - } else { - t = lb->GetType( i ); - if ( t == TYPE_XLABEL ) t = TYPE_LABEL; - PutCS( t, lb->GetOpt(i), ex ); - } + i = SearchSymbolOrRegisterVar( cg_str ); + t = lb->GetType( i ); + if ( t == TYPE_XLABEL ) t = TYPE_LABEL; + PutCS( t, lb->GetOpt(i), ex ); ex = 0; break; case TK_LABEL: @@ -1200,7 +1231,7 @@ void CToken::GenerateCodeVAR( int id, in t = lb->GetType(id); if (( t == TYPE_XLABEL )||( t == TYPE_LABEL )) throw CGERROR_LABELNAME; // - PutCS( t, lb->GetOpt(id), ex ); + PutCSSymbol( id, ex ); GetTokenCG( GETTOKEN_DEFAULT ); if ( t == TYPE_SYSVAR ) return; @@ -1365,7 +1396,7 @@ void CToken::GenerateCodeCMD( int id ) t = lb->GetType(id); opt = lb->GetOpt(id); orgcs = GetCS(); - PutCS( t, opt & 0xffff, EXFLG_1 ); + PutCSSymbol( id, EXFLG_1 ); if ( t == TYPE_PROGCMD ) CheckInternalProgCMD( opt, orgcs ); if ( t == TYPE_CMPCMD ) CheckInternalIF( opt ); GetTokenCG( GETTOKEN_DEFAULT ); @@ -1827,12 +1858,18 @@ int CToken::GetParameterResTypeCG( char } -void CToken::GenerateCodePP_deffunc( void ) +#define GET_FI_SIZE() ((int)(fi_buf->GetSize() / sizeof(STRUCTDAT))) +#define GET_FI(n) (((STRUCTDAT *)fi_buf->GetBuffer()) + (n)) +#define STRUCTDAT_INDEX_DUMMY ((short)0x8000) + + +void CToken::GenerateCodePP_deffunc0( int is_command ) { - // HSP3Codeを展開する(deffunc) + // HSP3Codeを展開する(deffunc / defcfunc) // int i,t,ot,prmid,subid; - int clean; + int index; + int funcflag; int regflag; int prep; char funcname[1024]; @@ -1843,7 +1880,7 @@ void CToken::GenerateCodePP_deffunc( voi GetTokenCG( GETTOKEN_DEFAULT ); if ( ttype != TK_OBJ ) throw CGERROR_PP_NAMEREQUIRED; - if ( !strcmp( cg_str,"prep" ) ) { // プロトタイプ宣言 + if ( is_command && !strcmp( cg_str,"prep" ) ) { // プロトタイプ宣言 prep = 1; GetTokenCG( GETTOKEN_DEFAULT ); if ( ttype != TK_OBJ ) throw CGERROR_PP_NAMEREQUIRED; @@ -1855,12 +1892,17 @@ void CToken::GenerateCodePP_deffunc( voi lb->SetFlag( cg_localstruct[i], -1 ); // 以前に指定されたパラメーター名を削除する } cg_localcur = 0; - clean = 0; + funcflag = 0; regflag = 1; - i = lb->Search( funcname ); - if ( i >= 0 ) { - throw CGERROR_PP_ALREADY_USE_FUNC; + index = -1; + int label_id = lb->Search( funcname ); + if ( label_id >= 0 ) { + if ( lb->GetType(label_id) != TYPE_MODCMD ) throw CGERROR_PP_ALREADY_USE_FUNC; + index = lb->GetOpt(label_id); + if ( index >= 0 && GET_FI(index)->index != STRUCTDAT_INDEX_DUMMY ) { + throw CGERROR_PP_ALREADY_USE_FUNC; + } } PutStructStart(); @@ -1869,8 +1911,8 @@ void CToken::GenerateCodePP_deffunc( voi if ( ttype >= TK_EOL ) break; if ( ttype != TK_OBJ ) throw CGERROR_PP_WRONG_PARAM_NAME; - if ( !strcmp( cg_str,"onexit" ) ) { - clean |= STRUCTDAT_FUNCFLAG_CLEANUP; + if ( is_command && !strcmp( cg_str,"onexit" ) ) { + funcflag |= STRUCTDAT_FUNCFLAG_CLEANUP; break; } @@ -1888,13 +1930,13 @@ void CToken::GenerateCodePP_deffunc( voi //Mesf( "%s:struct%d",cg_str,subid ); if ( t == MPTYPE_IMODULEVAR ) { if ( prm[ lb->GetOpt(i) ].offset != -1 ) throw CGERROR_PP_MODINIT_USED; - prm[ lb->GetOpt(i) ].offset = fi_buf->GetSize() / sizeof(STRUCTDAT); + prm[ lb->GetOpt(i) ].offset = GET_FI_SIZE(); regflag = 0; } if ( t == MPTYPE_TMODULEVAR ) { st = (STRUCTDAT *)fi_buf->GetBuffer(); if ( st[ subid ].otindex != 0 ) throw CGERROR_PP_MODTERM_USED; - st[ subid ].otindex = fi_buf->GetSize() / sizeof(STRUCTDAT); + st[ subid ].otindex = GET_FI_SIZE(); regflag = 0; } prmid = PutStructParam( t, subid ); @@ -1923,91 +1965,30 @@ void CToken::GenerateCodePP_deffunc( voi } ot = PutOT( GetCS() ); - i = PutStructEnd( funcname, STRUCTDAT_INDEX_FUNC, ot, clean ); - if ( regflag ) { - lb->Regist( funcname, TYPE_MODCMD, i ); + if ( index == -1 ) { + index = GET_FI_SIZE(); + fi_buf->PreparePtr( sizeof(STRUCTDAT) ); + if ( regflag ) { + lb->Regist( funcname, TYPE_MODCMD, index ); + } + } + if ( label_id >= 0 ) { + lb->SetOpt( label_id, index ); } + int dat_index = is_command ? STRUCTDAT_INDEX_FUNC : STRUCTDAT_INDEX_CFUNC; + PutStructEnd( index, funcname, dat_index, ot, funcflag ); } -void CToken::GenerateCodePP_defcfunc( void ) +void CToken::GenerateCodePP_deffunc( void ) { - // HSP3Codeを展開する(defcfunc) - // - int i,t,ot,prmid,subid; - int funcflag; - char funcname[1024]; - STRUCTPRM *prm; - - /* - GetTokenCG( GETTOKEN_DEFAULT ); - t = GetParameterResTypeCG( cg_str ); - if ( t <= MPTYPE_NONE ) { - throw CGERROR_PP_WRONG_PARAM_NAME; - } - funcflag = t; - */ - funcflag = 0; - - GetTokenCG( GETTOKEN_DEFAULT ); - if ( ttype != TK_OBJ ) throw CGERROR_PP_NAMEREQUIRED; - strncpy( funcname, cg_str, 1023 ); - - for(i=0;i<cg_localcur;i++) { - lb->SetFlag( cg_localstruct[i], -1 ); // 以前に指定されたパラメーター名を削除する - } - cg_localcur = 0; - - - PutStructStart(); - while(1) { - GetTokenCG( GETTOKEN_DEFAULT ); - if ( ttype >= TK_EOL ) break; - if ( ttype != TK_OBJ ) throw CGERROR_PP_WRONG_PARAM_NAME; - t = GetParameterTypeCG( cg_str ); - if ( t == MPTYPE_NONE ) throw CGERROR_PP_WRONG_PARAM_NAME; - if ( t == MPTYPE_MODULEVAR ) { - // モジュール名指定 - GetTokenCG( GETTOKEN_DEFAULT ); - if ( ttype != TK_OBJ ) throw CGERROR_PP_WRONG_PARAM_NAME; - i = lb->Search( cg_str ); - if ( i < 0 ) throw CGERROR_PP_BAD_STRUCT; - if ( lb->GetType(i) != TYPE_STRUCT ) throw CGERROR_PP_BAD_STRUCT; - prm = (STRUCTPRM *)mi_buf->GetBuffer(); - subid = prm[ lb->GetOpt(i) ].subid; - //Mesf( "%s:struct%d",cg_str,subid ); - prmid = PutStructParam( t, subid ); - GetTokenCG( GETTOKEN_DEFAULT ); - - } else { - prmid = PutStructParam( t, STRUCTPRM_SUBID_STACK ); - //Mesf( "%d:type%d",prmid,t ); - - GetTokenCG( GETTOKEN_DEFAULT ); - if ( ttype == TK_OBJ ) { - // 引数のエイリアス - i = lb->Search( cg_str ); - if ( i >= 0 ) { - throw CGERROR_PP_ALREADY_USE_PARAM; - } - i = lb->Regist( cg_str, TYPE_STRUCT, prmid ); - cg_localstruct[ cg_localcur++ ] = i; - GetTokenCG( GETTOKEN_DEFAULT ); - } - } + GenerateCodePP_deffunc0( 1 ); +} - if ( ttype >= TK_EOL ) break; - if ( ttype != TK_NONE ) throw CGERROR_PP_WRONG_PARAM_NAME; - if ( val != ',' ) throw CGERROR_PP_WRONG_PARAM_NAME; - } - i = lb->Search( funcname ); - if ( i >= 0 ) { - throw CGERROR_PP_ALREADY_USE_FUNC; - } - ot = PutOT( GetCS() ); - i = PutStructEnd( funcname, STRUCTDAT_INDEX_CFUNC, ot, funcflag ); - lb->Regist( funcname, TYPE_MODCMD, i ); +void CToken::GenerateCodePP_defcfunc( void ) +{ + GenerateCodePP_deffunc0( 0 ); } @@ -2177,27 +2158,20 @@ int CToken::GenerateCodeSub( void ) // break; case TK_OBJ: cg_lastcmd = CG_LASTCMD_LET; - i = lb->Search( cg_str ); - if ( i < 0 ) { - //Mesf( "[%s][%d]",cg_str, cg_valcnt ); - i = lb->Regist( cg_str, TYPE_VAR, cg_valcnt ); - cg_valcnt++; + i = SearchSymbolOrRegisterVar( cg_str ); + t = lb->GetType( i ); + switch( t ) { + case TYPE_VAR: + case TYPE_STRUCT: GenerateCodeLET( i ); - } else { - t = lb->GetType( i ); - switch( t ) { - case TYPE_VAR: - case TYPE_STRUCT: - GenerateCodeLET( i ); - break; - case TYPE_LABEL: - case TYPE_XLABEL: - throw CGERROR_LABELNAME; - break; - default: - GenerateCodeCMD( i ); - break; - } + break; + case TYPE_LABEL: + case TYPE_XLABEL: + throw CGERROR_LABELNAME; + break; + default: + GenerateCodeCMD( i ); + break; } // sprintf( tmp,"#obj:%s (%d)",cg_str,i ); // Mes( tmp ); @@ -2326,6 +2300,25 @@ int CToken::GenerateCodeBlock( void ) } +void CToken::RegisterFuncLabels( void ) +{ + // プリプロセス時のラベル情報から関数を定義 + // + if ( tmp_lb == NULL ) return; + int len = tmp_lb->GetCount(); + for( int i = 0; i < len; i ++ ) { + if ( tmp_lb->GetType(i) == LAB_TYPE_PPMODFUNC && tmp_lb->GetFlag(i) >= 0 ) { + char *name = tmp_lb->GetName(i); + if ( lb->Search(name) >= 0 ) { + throw CGERROR_PP_ALREADY_USE_FUNC; + } + int id = lb->Regist( name, TYPE_MODCMD, -1 ); + lb->SetData2( id, (char *)&i, sizeof i ); // tmp_lbのidをdata2内に保存 + } + } +} + + int CToken::GenerateCodeMain( CMemBuf *buf ) { // ソースをHSP3Codeに展開する @@ -2354,6 +2347,8 @@ int CToken::GenerateCodeMain( CMemBuf *b for( a=0; a<CG_REPLEV_MAX; a++) { repend[a] = -1; } try { + RegisterFuncLabels(); + while(1) { if ( GenerateCodeBlock() == TK_EOF ) break; } @@ -2372,6 +2367,15 @@ int CToken::GenerateCodeMain( CMemBuf *b errend++; } } + + // 関数未処理チェック + for( a=0; a<GET_FI_SIZE(); a++ ) { + if ( GET_FI(a)->index == STRUCTDAT_INDEX_DUMMY ) { + Mesf( "#関数が存在しません [%s]", lb->GetName(GET_FI(a)->otindex) ); + errend++; + } + } + if ( errend ) throw CGERROR_FATAL; } catch ( CGERROR code ) { @@ -2416,6 +2420,26 @@ void CToken::PutCS( int type, double val } +void CToken::PutCSSymbol( int label_id, int exflag ) +{ + // まだ定義されていない関数の呼び出しがあったら仮登録する + // + int type = lb->GetType(label_id); + int value = lb->GetOpt(label_id); + if ( type == TYPE_MODCMD && value == -1 ) { + int id = *(int *)lb->GetData2(label_id); + tmp_lb->AddReference( id ); + + STRUCTDAT st = { STRUCTDAT_INDEX_DUMMY }; + st.otindex = label_id; + value = GET_FI_SIZE(); + fi_buf->PutData( &st, sizeof(STRUCTDAT) ); + lb->SetOpt( label_id, value ); + } + if ( exflag & EXFLG_1 && type != TYPE_VAR && type != TYPE_STRUCT ) { + value &= 0xffff; + } + PutCS( type, value, exflag ); +} + + int CToken::GetCS( void ) { // Get current CS index @@ -2609,7 +2633,7 @@ int CToken::PutStructParam( short mptype prm.mptype = mptype; if ( extype == STRUCTPRM_SUBID_STID ) { - prm.subid = fi_buf->GetSize() / sizeof(STRUCTDAT); + prm.subid = GET_FI_SIZE(); } else { prm.subid = extype; } @@ -2673,7 +2697,7 @@ int CToken::PutStructParamTag( void ) i = mi_buf->GetSize() / sizeof(STRUCTPRM); prm.mptype = MPTYPE_STRUCTTAG; - prm.subid = fi_buf->GetSize() / sizeof(STRUCTDAT); + prm.subid = GET_FI_SIZE(); prm.offset = -1; cg_stnum++; @@ -2690,13 +2714,11 @@ void CToken::PutStructStart( void ) } -int CToken::PutStructEnd( char *name, int libindex, int otindex, int funcflag ) +int CToken::PutStructEnd( int i, char *name, int libindex, int otindex, int funcflag ) { // STRUCTDATを登録する(モジュール用) // - int i; STRUCTDAT st; - i = fi_buf->GetSize() / sizeof(STRUCTDAT); st.index = libindex; st.nameidx = PutDS( name ); st.subid = i; @@ -2710,19 +2732,27 @@ int CToken::PutStructEnd( char *name, in } else { st.otindex = otindex; } - fi_buf->PutData( &st, sizeof(STRUCTDAT) ); + *GET_FI(i) = st; //Mesf( "#%d : %s(LIB%d) prm%d size%d ot%d", i, name, libindex, cg_stnum, cg_stsize, otindex ); return i; } +int CToken::PutStructEnd( char *name, int libindex, int otindex, int funcflag ) +{ + int i = GET_FI_SIZE(); + fi_buf->PreparePtr( sizeof(STRUCTDAT) ); + return PutStructEnd( i, name, libindex, otindex, funcflag ); +} + + int CToken::PutStructEndDll( char *name, int libindex, int subid, int otindex ) { // STRUCTDATを登録する(DLL用) // int i; STRUCTDAT st; - i = fi_buf->GetSize() / sizeof(STRUCTDAT); + i = GET_FI_SIZE(); st.index = libindex; if ( name[0] == '*' ) { st.nameidx = -1; Index: token.h =================================================================== --- token.h (revision 241) +++ token.h (working copy) @@ -169,6 +169,7 @@ public: int GenerateCode( CMemBuf *srcbuf, char *oname, int mode ); void PutCS( int type, int value, int exflg ); + void PutCSSymbol( int label_id, int exflag ); int GetCS( void ); void PutCS( int type, double value, int exflg ); int PutOT( int value ); @@ -186,6 +187,7 @@ public: int PutStructParamTag( void ); void PutStructStart( void ); int PutStructEnd( char *name, int libindex, int otindex, int funcflag ); + int PutStructEnd( int i, char *name, int libindex, int otindex, int funcflag ); int PutStructEndDll( char *name, int libindex, int subid, int otindex ); void CalcCG( int ex ); @@ -257,6 +259,7 @@ private: // For Code Generate // int GenerateCodeMain( CMemBuf *src ); + void RegisterFuncLabels( void ); int GenerateCodeBlock( void ); int GenerateCodeSub( void ); void GenerateCodePP( char *buf ); @@ -271,9 +274,12 @@ private: int GenerateCodePRMF4( int t ); void GenerateCodeMethod( void ); void GenerateCodeLabel( char *name, int ex ); + int SearchSymbolOrRegisterVar( char *name ); + int SymbolEndsWithAtMark( char *name, int *len ); void GenerateCodePP_regcmd( void ); void GenerateCodePP_cmd( void ); + void GenerateCodePP_deffunc0( int is_command ); void GenerateCodePP_deffunc( void ); void GenerateCodePP_defcfunc( void ); void GenerateCodePP_uselib( void );
追記 (2009-06-12T21:44:20+09:00)
PutCSSymbol を修正しました。 常に value & 0xffff とすると thismod が -1 から 0xffff になってしまうので ex1 フラグのときのみマスクをかけるように。
追記 (2009-06-19T19:21:24+09:00)
TYPE_VAR や TYPE_STRUCT のときはマスクをかけないように修正...