プリプロセッサ命令の後ろに余分なトークンがあったらエラーにするパッチ
http://hsp.tv/play/pforum.php?mode=all&num=22946#22959 を見て作ってみたんだけど微妙な感じ。
- #if, #ifdef, #ifndef で実行されないブロック内ではチェックされない
- #enum は 「if ( GetToken() == '=' ) {」ってやってるので余分なトークンがひとつだけではエラーにならない
- #uselib などいくつかのプリプロセッサ命令は token.cpp では処理しないので余分なトークンがあってもエラーにならない
- #func 系の命令や #usecom は token.cpp では途中までしか処理しないので余分なトークンがあることをチェックできない
- #ahtmes, #pack, #packopt なんかは条件が揃わないとトークンを処理しないんだけど、これらは条件が揃わなくてもトークンを処理するように簡単に修正できるのでそうした
- ほかにも最後までトークンを処理しないようなプリプロセッサ命令を見逃しているかも
- エラーを表す int 型の戻り値のマジックナンバーだけど何か意味があるのだろうか。何も考えずに 1 をつかったけど。
- hsp31/sample 内のすべてのソースで同じオブジェクトファイル、プリプロセス済みソース、コンパイルメッセージが出力されることを確認しています。(調べるのに使ったスクリプト:hspcmp_result_compare.hsp)
Index: token.cpp =================================================================== --- token.cpp (revision 189) +++ token.cpp (working copy) @@ -2406,6 +2406,7 @@ // wrtbuf->PutStrf( "#%s %s%s",name, word, (char *)wp ); wrtbuf->PutCR(); + GetToken(); // return -1; } @@ -2564,11 +2565,10 @@ // #ahtmes解析 // int i; + bool execute = ahtmodel != NULL && + ahtbuf != NULL && + wp != NULL; - if ( ahtmodel == NULL ) return 0; - if ( ahtbuf == NULL ) return 0; - if ( wp == NULL ) return 0; - while(1) { if ( wp == NULL ) break; @@ -2577,7 +2577,7 @@ if (( i != TK_OBJ )&&( i != TK_NUM )&&( i != TK_STRING )) { SetError("illegal ahtmes parameter"); return 1; } - ahtbuf->PutStr( (char *)s3 ); + if ( execute ) ahtbuf->PutStr( (char *)s3 ); if ( wp == NULL ) break; @@ -2585,7 +2585,7 @@ if ( i != '+' ) { SetError("invalid ahtmes format"); return 1; } } - ahtbuf->PutCR(); + if ( execute ) ahtbuf->PutCR(); return 0; } @@ -2595,11 +2595,11 @@ // #pack,#epack解析 // (mode:0=normal/1=encrypt) int i; + i = GetToken(); + if ( i != TK_STRING ) { + SetError("invalid pack name"); return 1; + } if ( packbuf!=NULL ) { - i = GetToken(); - if ( i != TK_STRING ) { - SetError("invalid pack name"); return 1; - } AddPackfile( (char *)s3, mode ); } return 0; @@ -2613,16 +2613,16 @@ int i; char tmp[1024]; char optname[1024]; + i = GetToken(); + if ( i != TK_OBJ ) { + SetError("illegal option name"); return 1; + } + strncpy( optname, (char *)s3, 128 ); + i = GetToken(); + if (( i != TK_OBJ )&&( i != TK_NUM )&&( i != TK_STRING )) { + SetError("illegal option parameter"); return 1; + } if ( packbuf!=NULL ) { - i = GetToken(); - if ( i != TK_OBJ ) { - SetError("illegal option name"); return 1; - } - strncpy( optname, (char *)s3, 128 ); - i = GetToken(); - if (( i != TK_OBJ )&&( i != TK_NUM )&&( i != TK_STRING )) { - SetError("illegal option parameter"); return 1; - } sprintf( tmp, ";!%s=%s", optname, (char *)s3 ); AddPackfile( tmp, 2 ); } @@ -2752,10 +2752,11 @@ // ソース生成コントロール // if (tstrcmp(word,"ifdef")) { // generate control + type = GetToken(); if ( mulstr == LMODE_OFF ) { res = PP_SwitchStart( 0 ); } else { - res = 1; type = GetToken(); + res = 1; if ( type == TK_OBJ ) { strcase2( word, fixname ); AddModuleName( fixname ); @@ -2766,13 +2767,14 @@ } } if (res) { SetError("bad ifdef syntax"); return 6; } - return 0; + goto leave; } if (tstrcmp(word,"ifndef")) { // generate control + type = GetToken(); if ( mulstr == LMODE_OFF ) { res = PP_SwitchStart( 0 ); } else { - res = 1; type = GetToken(); + res = 1; if ( type == TK_OBJ ) { strcase2( word, fixname ); AddModuleName( fixname ); @@ -2783,21 +2785,21 @@ } } if (res) { SetError("bad ifdef syntax"); return 6; } - return 0; + goto leave; } if (tstrcmp(word,"else")) { // generate control if ( PP_SwitchReverse() ) { SetError("bad else syntax"); return 6; } - return 0; + goto leave; } if (tstrcmp(word,"endif")) { // generate control if ( PP_SwitchEnd() ) { SetError("bad endif syntax"); return 6; } - return 0; + goto leave; } // これ以降は#off時に実行しません @@ -2818,12 +2820,14 @@ res = lb->SearchLocal( word, fixname ); //res = lb->Search( word ); - if ( res < 0 ) return 0; + if ( res < 0 ) goto leave; lb->SetFlag( res, -1 ); - return 0; + goto leave; } return -1; +leave: + return CheckExtraTokensAtDirective(); } @@ -2854,7 +2858,7 @@ } else res=1; } if (res) { SetError("bad if syntax"); return 6; } - return 0; + goto leave; } // これ以降は#off時に実行しません @@ -2865,6 +2869,7 @@ // if (tstrcmp(word,"include")) { // text include if ( GetToken() != TK_STRING ) { SetError("invalid include suffix"); return 1; } + if ( CheckExtraTokensAtDirective() ) return 1; incinf++; if (incinf>32) { SetError("too many include level"); return 2; } strcpy( tmp_spath, search_path ); @@ -2877,6 +2882,7 @@ if (tstrcmp(word,"addition")) { // text include int add_bak; if ( GetToken() != TK_STRING ) { SetError("invalid addition suffix"); return 1; } + if ( CheckExtraTokensAtDirective() ) return 1; incinf++; if (incinf>32) { SetError("too many include level"); return 2; } strcpy( tmp_spath, search_path ); @@ -2893,11 +2899,11 @@ } if (tstrcmp(word,"const")) { // constant define res = PP_Const(); - return res; + goto leave; } if (tstrcmp(word,"enum")) { // constant enum define res = PP_Enum(); - return res; + goto leave; } /* if (tstrcmp(word,"define")) { // keyword define @@ -2908,35 +2914,35 @@ */ if (tstrcmp(word,"module")) { // module define res = PP_Module(); - return res; + goto leave; } if (tstrcmp(word,"global")) { // module exit res = PP_Global(); - return res; + goto leave; } if (tstrcmp(word,"deffunc")) { // module function res = PP_Deffunc(0); - return res; + goto leave; } if (tstrcmp(word,"defcfunc")) { // module function (2) res = PP_Defcfunc(0); - return res; + goto leave; } if (tstrcmp(word,"modfunc")) { // module function (2) res = PP_Deffunc(1); - return res; + goto leave; } if (tstrcmp(word,"modinit")) { // module function (3) res = PP_Deffunc(2); - return res; + goto leave; } if (tstrcmp(word,"modterm")) { // module function (4) res = PP_Deffunc(3); - return res; + goto leave; } if (tstrcmp(word,"struct")) { // struct define res = PP_Struct(); - return res; + goto leave; } if (tstrcmp(word,"func")) { // DLL function res = PP_Func( "func" ); @@ -2948,7 +2954,7 @@ } if (tstrcmp(word,"cmd")) { // DLL function (3.0) res = PP_Cmd( "cmd" ); - return res; + goto leave; } /* if (tstrcmp(word,"func2")) { // DLL function (2) @@ -2962,7 +2968,7 @@ } if (tstrcmp(word,"aht")) { // AHT definition res = PP_Aht(); - return res; + goto leave; } if (tstrcmp(word,"ahtout")) { // AHT command line output res = PP_Ahtout(); @@ -2970,27 +2976,27 @@ } if (tstrcmp(word,"ahtmes")) { // AHT command line output (mes) res = PP_Ahtmes(); - return res; + goto leave; } if (tstrcmp(word,"pack")) { // packfile process res = PP_Pack( 0 ); - return res; + goto leave; } if (tstrcmp(word,"epack")) { // packfile process res = PP_Pack( 1 ); - return res; + goto leave; } if (tstrcmp(word,"packopt")) { // packfile process res = PP_PackOpt(); - return res; + goto leave; } if (tstrcmp(word,"runtime")) { // runtime process res = PP_RuntimeOpt(); - return res; + goto leave; } if (tstrcmp(word,"cmpopt")) { // compile option process res = PP_CmpOpt(); - return res; + goto leave; } if (tstrcmp(word,"usecom")) { // COM definition res = PP_Usecom(); @@ -3004,8 +3010,19 @@ wrtbuf->PutCR(); //wrtbuf->PutStr( (char *)s3 ); return -1; +leave: + if( res && !(res & 0x1000) ) return res; + if( CheckExtraTokensAtDirective() ) return 1; + return res; } +int CToken::CheckExtraTokensAtDirective() { + if ( GetToken() != TK_NONE ) { + SetError("extra tokens at end of preprocessing directive"); + return 1; + } + return 0; +} int CToken::ExpandLine( CMemBuf *buf, CMemBuf *src ) { Index: token.h =================================================================== --- token.h (revision 189) +++ token.h (working copy) @@ -238,6 +238,8 @@ char *SendLineBuf( char *str ); char *SendLineBufPP( char *str, int *lines ); int ReplaceLineBuf( char *str1, char *str2, char *repl, int macopt, MACDEF *macdef ); + + int CheckExtraTokensAtDirective(); // For Code Generate