後ろで定義されている関数を呼び出せるようにするパッチ その2

後ろで定義されている関数を呼び出せるようにするパッチ - fujidigの雑記 の改良。
前のパッチは codegen で識別子の @ がどうこうしているのが心残りでした(SearchSymbolOrRegisterVarまわり)。 識別子の @ の処理とかはプリプロセスで済ますべきだったと思います。

その代わりの実装方法:
問題のモジュール内で@をつけていない識別子はその位置を記録しておきます。そしてプリプロセスの終了時にその識別子から @modname を除いた名前の関数が定義されているか探し、あれば @modname を削除します。

また前回のパッチでは以下のスクリプトコンパイルエラーになっていたのですが、それも修正されています。

#cmpopt optcode 0
#module m
*l
#global

a = *l@m

追記 (2009-06-29T16:54:47+09:00)

このパッチを ML に投稿してみたところ、取り込まれました。やったー。
http://dev.onionsoft.net/trac/changeset/323

Index: hsc3.cpp
===================================================================
--- hsc3.cpp	(リビジョン 305)
+++ hsc3.cpp	(作業コピー)
@@ -161,6 +161,7 @@ int CHsc3::PreProcess( char *fname, char
 	if ( res<-1 ) return -1;
 	res = tk.ExpandFile( outbuf, fname, rname );
 	if ( res<0 ) return -1;
+	tk.FinishPreprocess( outbuf );
 
 	cmpopt = tk.GetCmpOption();
 	if ( cmpopt & CMPMODE_PPOUT	 ) {
Index: membuf.cpp
===================================================================
--- membuf.cpp	(リビジョン 305)
+++ membuf.cpp	(作業コピー)
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <assert.h>
 #include "membuf.h"
 
 //-------------------------------------------------------------
@@ -276,6 +277,13 @@ int CMemBuf::PutFile( char *fname )
 }
 
 
+void CMemBuf::ReduceSize( int new_cur )
+{
+	assert( new_cur >= 0 && new_cur <= cur );
+	cur = new_cur;
+}
+
+
 //-------------------------------------------------------------
 //		Interfaces
 //-------------------------------------------------------------
Index: token.cpp
===================================================================
--- token.cpp	(リビジョン 317)
+++ token.cpp	(作業コピー)
@@ -1345,6 +1345,15 @@ char *CToken::ExpandToken( char *str, in
 	//
 	if (wrtbuf!=NULL) {
 //		AddModuleName( (char *)s2 );
+		if ( strcmp( (char *)s2, fixname ) ) {
+			//	後ろで定義されている関数の呼び出しのために
+			//	モジュール内で@をつけていない識別子の位置を記録する
+			undefined_symbol_t sym;
+			sym.pos = wrtbuf->GetSize();
+			sym.len_include_modname = (int)strlen( fixname );
+			sym.len = (int)strlen( (char *)s2 );
+			undefined_symbols.push_back( sym );
+		}
 		wrtbuf->PutStr( fixname );
 //		wrtbuf->Put( '?' );
 	}
@@ -3338,6 +3347,41 @@ void CToken::SetCommonPath( char *path )
 }
 
 
+void CToken::FinishPreprocess( CMemBuf *buf )
+{
+	//	後ろで定義された関数がある場合、それに書き換える
+	//
+	//	この関数では foo@modname を foo に書き換えるなどバッファサイズが小さくなる変更しか行わない
+	//
+	int read_pos = 0;
+	int write_pos = 0;
+	size_t i;
+	size_t len = undefined_symbols.size();
+	char *p = buf->GetBuffer();
+	for ( i = 0; i < len; i ++ ) {
+		undefined_symbol_t sym = undefined_symbols[i];
+		int pos = sym.pos;
+		int len_include_modname = sym.len_include_modname;
+		int len = sym.len;
+		int id;
+		memmove( p + write_pos, p + read_pos, pos - read_pos );
+		write_pos += pos - read_pos;
+		read_pos = pos;
+		// @modname を消した名前の関数が存在したらそれに書き換え
+		p[pos+len] = '\0';
+		id = lb->Search( p + pos );
+		if ( id >= 0 && lb->GetType(id) == LAB_TYPE_PPMODFUNC ) {
+			memmove( p + write_pos, p + pos, len );
+			write_pos += len;
+			read_pos += len_include_modname;
+		}
+		p[pos+len] = '@';
+	}
+	memmove( p + write_pos, p + read_pos, buf->GetSize() - read_pos );
+	buf->ReduceSize( buf->GetSize() - (read_pos - write_pos) );
+}
+
+
 int CToken::LabelRegist( char **list, int mode )
 {
 	//		ラベル情報を登録
Index: codegen.cpp
===================================================================
--- codegen.cpp	(リビジョン 307)
+++ codegen.cpp	(作業コピー)
@@ -889,7 +889,7 @@ void CToken::GenerateCodePRMF2( void )
 
 			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 ) {
@@ -1148,7 +1148,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;
@@ -1313,7 +1313,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 );
@@ -1771,12 +1771,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];
@@ -1787,7 +1793,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;
@@ -1799,12 +1805,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();
@@ -1813,8 +1824,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;
 		}
 
@@ -1832,13 +1843,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 );
@@ -1867,91 +1878,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 );
 }
 
 
@@ -2270,6 +2220,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 );
+		}
+	}
+}
+
+
 int CToken::GenerateCodeMain( CMemBuf *buf )
 {
 	//		ソースをHSP3Codeに展開する
@@ -2298,6 +2267,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;
 		}
@@ -2316,6 +2287,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 ) {
@@ -2360,6 +2340,29 @@ 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
@@ -2553,7 +2556,7 @@ int CToken::PutStructParam( short mptype
 
 	prm.mptype = mptype;
 	if ( extype == STRUCTPRM_SUBID_STID ) {
-		prm.subid  = fi_buf->GetSize() / sizeof(STRUCTDAT);
+		prm.subid  = (short)GET_FI_SIZE();
 	} else {
 		prm.subid = extype;
 	}
@@ -2617,7 +2620,7 @@ int CToken::PutStructParamTag( void )
 	i = mi_buf->GetSize() / sizeof(STRUCTPRM);
 
 	prm.mptype = MPTYPE_STRUCTTAG;
-	prm.subid  = fi_buf->GetSize() / sizeof(STRUCTDAT);
+	prm.subid  = (short)GET_FI_SIZE();
 	prm.offset = -1;
 
 	cg_stnum++;
@@ -2634,13 +2637,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;
@@ -2654,19 +2655,26 @@ 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: membuf.h
===================================================================
--- membuf.h	(リビジョン 305)
+++ membuf.h	(作業コピー)
@@ -47,6 +47,7 @@ public:
 	int SaveFile( char *fname );
 	char *GetFileName( void );
 	int GetSize( void ) { return cur; }
+	void ReduceSize( int new_cur );
 	char *PreparePtr( int sz );
 
 private:
Index: token.h
===================================================================
--- token.h	(リビジョン 305)
+++ token.h	(作業コピー)
@@ -5,6 +5,8 @@
 #ifndef __token_h
 #define __token_h
 
+#include <vector>
+
 // token type
 #define TK_NONE 0
 #define TK_OBJ 1
@@ -134,6 +136,7 @@ public:
 
 	int ExpandLine( CMemBuf *buf, CMemBuf *src, char *refname );
 	int ExpandFile( CMemBuf *buf, char *fname, char *refname );
+	void FinishPreprocess( CMemBuf *buf );
 	void SetCommonPath( char *path );
 	int SetAdditionMode( int mode );
 
@@ -159,6 +162,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 );
@@ -176,6 +180,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 );
@@ -249,6 +254,7 @@ private:
 	//		For Code Generate
 	//
 	int GenerateCodeMain( CMemBuf *src );
+	void RegisterFuncLabels( void );
 	int GenerateCodeBlock( void );
 	int GenerateCodeSub( void );
 	void GenerateCodePP( char *buf );
@@ -266,6 +272,7 @@ private:
 
 	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 );
@@ -352,6 +359,12 @@ private:
 	char modname[MODNAME_MAX+2];	// Module Name Prefix
 	int	modgc;						// Global counter for Module
 	int enumgc;						// Global counter for Enum
+	typedef struct undefined_symbol_t {
+		int pos;
+		int len_include_modname;
+		int len;
+	} undefined_symbol_t;
+	std::vector<undefined_symbol_t> undefined_symbols;
 
 	//		for CodeGenerator
 	//