#include "stdafx.h" #include #include #include #include #include const string BasicSource::generateDirectiveName = "#generate"; class CDefine{ vector names; public: CDefine( int majorVer ); ~CDefine(); void Free(); void Init( int majorVer ); BOOL add(char *name); BOOL undef(char *name); BOOL check(char *name); void preprocessor_ifdef(char *buffer,bool isNot); void DirectiveIfdef(char *buffer); }; // TODO: バージョン番号の識別子defineが未完成 CDefine objDefine(0); ////////////////////////////////////// // #requireの管理 ////////////////////////////////////// class CRequireFiles{ char **ppFilePath; int count; public: CRequireFiles(){ ppFilePath = (char **)malloc( 1 ); count = 0; } ~CRequireFiles(){ for( int i = 0; i < count; i++ ){ free( ppFilePath[i] ); } free( ppFilePath ); } void clear(){ for( int i = 0; i < count; i++ ){ free( ppFilePath[i] ); } free( ppFilePath ); ppFilePath = (char **)malloc( 1 ); count = 0; } bool IsIncluded( const char *includeFilePath ){ // '/' → '\\' char tempPath[MAX_PATH]; lstrcpy( tempPath, includeFilePath ); for( int i=0; tempPath[i]; i++ ){ if( tempPath[i] == '/' ){ tempPath[i] = '\\'; } } for( int i=0; i::iterator i = names.begin(); BOOST_FOREACH( const string &temp, names ){ if( temp == name ){ names.erase( i ); return 1; } i++; } return 0; } BOOL CDefine::check(char *name){ //重複チェック BOOST_FOREACH( const string &temp, names ){ if( temp == name ){ return 1; } } return 0; } int Search_endif(char *buffer,int i, int *pLine = 0){ for(;;i++){ if(buffer[i]=='\0') break; if( buffer[i] == '\n' ){ if( pLine ){ (*pLine)++; } } if(buffer[i-1]=='\n'){ if(memicmp(buffer+i,"#ifdef",6)==0||memicmp(buffer+i,"#ifndef",7)==0){ i=Search_endif(buffer,i+6, pLine); if(buffer[i]=='\0') break; continue; } else if(memicmp(buffer+i,"#endif",6)==0){ break; } } } return i; } void CDefine::preprocessor_ifdef(char *buffer,bool isNot){ int i,i2,i3; char temporary[VN_SIZE]; if(isNot) i=lstrlen("#ifndef"); else i=lstrlen("#ifdef"); while(buffer[i]==' '||buffer[i]=='\t') i++; for(i2=0;;i++,i2++){ if(buffer[i]=='\n'||buffer[i]=='\0'){ temporary[i2]=0; break; } temporary[i2]=buffer[i]; } int sw=0; if(check(temporary)) sw=1; if(isNot){ //#ifndefのとき(反対にする) if(sw) sw=0; else sw=1; } //#ifdefの行を消去 Text::SlideString(buffer+i,-i); i=0; BOOL bElse=0; if(sw){ //TRUEのとき //#else、#endifを探索 for(;;i++){ if(buffer[i]=='\0') break; if(i==0||buffer[i-1]=='\n'){ if(memicmp(buffer+i,"#ifdef",6)==0||memicmp(buffer+i,"#ifndef",7)==0){ i=Search_endif(buffer,i+6); if(buffer[i]=='\0') break; continue; } else if(memicmp(buffer+i,"#else",5)==0){ i2=5; bElse=1; break; } else if(memicmp(buffer+i,"#endif",6)==0){ i2=6; bElse=0; break; } } } //行を消去 Text::SlideString(buffer+i+i2,-i2); if(bElse){ //#elseがある場合はその区間を消去 for(i2=i,i3=0;;i2++){ if(buffer[i2]=='\0') break; if(buffer[i2]=='\n') i3++; if(i2==0||buffer[i2-1]=='\n'){ if(memicmp(buffer+i2,"#ifdef",6)==0||memicmp(buffer+i2,"#ifndef",7)==0){ i2=Search_endif(buffer,i2+6, &i3 ); if(buffer[i2]=='\0') break; continue; } if(memicmp(buffer+i2,"#endif",6)==0){ i2+=6; break; } } } //ソースコード区間を消去し、改行コードを挿入 Text::SlideString(buffer+i2,i-i2+i3); memset(buffer+i,'\n',i3); } } else{ //FALSEのとき //#else、#endifを探索 for(i2=i,i3=0;;i2++){ if(buffer[i2]=='\0') break; if(buffer[i2]=='\n') i3++; if(i2==0||buffer[i2-1]=='\n'){ if(memicmp(buffer+i2,"#ifdef",6)==0||memicmp(buffer+i2,"#ifndef",7)==0){ i2=Search_endif(buffer,i2+6, &i3 ); if(buffer[i2]=='\0') break; continue; } else if(memicmp(buffer+i2,"#else",5)==0){ i2+=5; bElse=1; break; } else if(memicmp(buffer+i2,"#endif",6)==0){ i2+=6; bElse=0; break; } } } //ソースコード区間を消去し、改行コードを挿入 Text::SlideString(buffer+i2,i-i2+i3); memset(buffer+i,'\n',i3); if(bElse){ //#endifを探索 for(;;i++){ if(buffer[i]=='\0') break; if(i==0||buffer[i-1]=='\n'){ if(memicmp(buffer+i,"#ifdef",6)==0||memicmp(buffer+i,"#ifndef",7)==0){ i=Search_endif(buffer,i+6); if(buffer[i]=='\0') break; continue; } else if(memicmp(buffer+i,"#endif",6)==0){ i2=6; bElse=0; break; } } } //行を消去 Text::SlideString(buffer+i+i2,-i2); } } } void CDefine::DirectiveIfdef(char *buffer){ int i,i2,i3,sw; char temporary[VN_SIZE]; for(i=0;;i++){ if(buffer[i]=='\0') break; if(i==0||(i>=1&&buffer[i-1]=='\n')){ sw=0; if(memicmp(buffer+i,"#define",7)==0){ i2=i+7; while(buffer[i2]==' '||buffer[i2]=='\t') i2++; for(i3=0;;i2++,i3++){ if(buffer[i2]=='\n'||buffer[i2]=='\0'){ temporary[i3]=0; break; } temporary[i3]=buffer[i2]; } add(temporary); i2-=i; //ディレクティブを消去 Text::SlideString(buffer+i+i2,-i2); } if(memicmp(buffer+i,"#undef",6)==0){ i2=i+7; while(buffer[i2]==' '||buffer[i2]=='\t') i2++; for(i3=0;;i2++,i3++){ if(buffer[i2]=='\n'||buffer[i2]=='\0'){ temporary[i3]=0; break; } temporary[i3]=buffer[i2]; } undef(temporary); i2-=i; //ディレクティブを消去 Text::SlideString(buffer+i+i2,-i2); } else if(memicmp(buffer+i,"#ifdef",6)==0){ preprocessor_ifdef(buffer+i,false); continue; } else if(memicmp(buffer+i,"#ifndef",7)==0){ preprocessor_ifdef(buffer+i,true); continue; } else continue; } } } bool Text::ReadFile( const string &filePath ){ //ファイルオープン HANDLE hFile=CreateFile(filePath.c_str(),GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile==INVALID_HANDLE_VALUE){ return false; } length = GetFileSize( hFile, NULL ); buffer = (char *)realloc( buffer, length + 1 ); //読み込み DWORD dwAccBytes; ::ReadFile(hFile,buffer,length,&dwAccBytes,0); buffer[dwAccBytes]=0; //ファイルクローズ CloseHandle(hFile); return true; } void BasicSource::ChangeReturnLineChar(){ int i,i2; bool isMustChange = false; for( i=0; ; i++ ){ if( buffer[i] == '\0' ){ break; } if( buffer[i]=='\n' ) { if( i>0 ) { if( buffer[i-1] == '\r' ) { isMustChange = true; } } } } if( !isMustChange ) { // 改行コードの変換は必要ない return; } #ifdef _DEBUG //改行コードの整合性チェック for( i=0; ; i++ ){ if( buffer[i] == '\0' ){ break; } if( buffer[i]!='\r' && buffer[i+1]=='\n' || buffer[i]=='\r' && buffer[i+1]!='\n' ){ char temporary[255]; strncpy( temporary, buffer + i-100, 130 ); temporary[130] = 0; for(int i2=0; ;i2++){ if(temporary[i2]=='\r') temporary[i2]='A'; if(temporary[i2]=='\n') temporary[i2]='B'; if(temporary[i2]=='\0') break; } extern HWND hOwnerEditor; MessageBox( hOwnerEditor, temporary, "改行コードの整合性チェック", MB_OK | MB_ICONEXCLAMATION ); } } #endif //改行コードのCRLFをLFに変換 for(i=0,i2=0;;i++,i2++){ if(buffer[i]=='\r'&&buffer[i+1]=='\n') i++; buffer[i2]=buffer[i]; if(buffer[i]=='\0') break; } length = i; } void BasicSource::RemoveComments(){ int i,i2,i3,IsStr; char *temporary; temporary=(char *)GlobalAlloc(GMEM_FIXED,lstrlen(buffer)+1); for(i=0,i2=0,i3=0,IsStr=0;;i++,i2++){ if(buffer[i]=='\"') IsStr^=1; if(buffer[i]=='\n'||buffer[i]=='\0'){ i2--; while(temporary[i2]==' '||temporary[i2]=='\t') i2--; i2++; if(i3){ //複数行に渡る注釈文の中に改行が存在するとき memset(temporary+i2,'\n',i3); i2+=i3; i3=0; } } if(buffer[i]=='\''&&IsStr==0){ //注釈文 i2--; while(temporary[i2]==' '||temporary[i2]=='\t') i2--; i2++; while(buffer[i]!='\n'&&buffer[i]!='\0') i++; } if(buffer[i]=='/'&&buffer[i+1]=='*'&&IsStr==0){ //注釈文(複数行) i+=2; i3=0; while(!(buffer[i]=='*'&&buffer[i+1]=='/')){ if(buffer[i]=='\n') i3++; if(buffer[i]=='\0') break; i++; } if(buffer[i]){ i+=2; } i--; i2--; continue; } temporary[i2]=buffer[i]; if(buffer[i]=='\0') break; } lstrcpy(buffer,temporary); GlobalFree(temporary); } bool BasicSource::ReadFile_InIncludeDirective( const string &filePath ){ if( !Text::ReadFile( filePath ) ){ return false; } // 改行コードをCRLFからLFに変換 ChangeReturnLineChar(); // コメントを削除 RemoveComments(); // #ifdefディレクティブを処理 objDefine.DirectiveIfdef( buffer ); // アンダーバーによる改行を正規表現に戻す RemoveReturnLineUnderbar(); // ダミー改行をセット Realloc( length + 2 ); Text::SlideString( buffer, 2 ); buffer[0] = '\n'; buffer[1] = '\n'; return true; } void BasicSource::DirectiveIncludeOrRequire(){ extern HANDLE hHeap; extern char BasicCurDir[MAX_PATH]; int i,i2,i3,sw1,LineNum,FileLayer[255],layer,LastFileByte[255]; char temporary[MAX_PATH],temp2[MAX_PATH+255],*LayerDir[255]; layer=0; FileLayer[layer]=0; LastFileByte[layer]=GetLength(); LineNum=0; if( includedFilesRelation.GetLineCounts() != 0 ) { Jenga::Throw( "インクルードファイル構造の初期値が不正" ); } // メインソースコード FileLayer[layer] = includedFilesRelation.AddFile( program.GetSourceFilePath() ); //参照ディレクトリ LayerDir[0]=(char *)malloc(lstrlen(BasicCurDir)+1); lstrcpy(LayerDir[0],BasicCurDir); for(i=0;;i++){ if(buffer[i]=='\0'){ break; } if(buffer[i]=='\n'){ includedFilesRelation.AddLine( FileLayer[layer] ); } if(i>LastFileByte[layer]){ free(LayerDir[layer]); LayerDir[layer]=0; layer--; } if((buffer[i-1]=='\n'||i==0)&&buffer[i]=='#'){ bool isRequire = false; if(memcmp( buffer + i + 1, "include", 7 ) == 0 || memcmp( buffer + i + 1, "require", 7 ) == 0){ //#requireの場合 if( buffer[i + 1] == 'r' ) isRequire = true; i2=i+8; while(buffer[i2]==' '||buffer[i2]=='\t') i2++; if(buffer[i2]=='\"') sw1=0; else if(buffer[i2]=='<') sw1=1; i2++; for(i3=0;;i2++,i3++){ if((buffer[i2]=='\"'&&sw1==0)||(buffer[i2]=='>'&&sw1==1)||buffer[i2]=='\n'||buffer[i2]=='\0'){ temporary[i3]=0; break; } temporary[i3]=buffer[i2]; } while(buffer[i2]!='\n'&&buffer[i2]!='\0') i2++; if(sw1){ sprintf(temp2,"%s%s", program.GetIncludeDir().c_str(), temporary ); lstrcpy(temporary,temp2); } else{ Jenga::Common::Directory dir( LayerDir[layer] ); lstrcpy( temporary, dir.GetFullPath( temporary ).c_str() ); } } else if(memcmp(buffer+i+1,"prompt",6)==0){ i2=i+7; sprintf(temporary,"%sbasic\\prompt.sbp", program.GetIncludeDir().c_str() ); } else if(memcmp(buffer+i+1,"N88BASIC",8)==0){ i2=i+9; sprintf(temporary,"%sbasic\\prompt.sbp", program.GetIncludeDir().c_str() ); } else if(memcmp(buffer+i+1,"console",7)==0){ //サブシステム タイプをCUIに変更 extern unsigned short TypeOfSubSystem; TypeOfSubSystem=IMAGE_SUBSYSTEM_WINDOWS_CUI; i2=i+8; sprintf(temporary,"%sbasic\\dos_console.sbp", program.GetIncludeDir().c_str() ); } else continue; if( i == 0 && Jenga::Common::Path(temporary).GetFileName() == "basic" ) { } else { //ディレクティブが消えるため、一行減ってしまうのを防ぐ(basic.sbpを除く) Text::SlideString(buffer+i2,1); buffer[i2]='\n'; for(i3=0;i3<=layer;i3++) LastFileByte[i3]++; } layer++; FileLayer[layer] = includedFilesRelation.AddFile( temporary ); //#requireの場合では、既に読み込まれているファイルは読み込まないようにする bool isFake = false; if( isRequire ){ if( requireFiles.IsIncluded( temporary ) ){ //既に読み込まれているとき isFake = true; } } BasicSource source; if( isFake ){ //既に読み込まれているときは空データ source.SetBuffer( "" ); } else{ //取り込まれたファイルを収集する requireFiles.Add( temporary ); //インクルードファイルを読み込む if( !source.ReadFile_InIncludeDirective( temporary ) ){ sprintf(temp2,"インクルードファイル \"%s\" をオープンできません",temporary); compiler.errorMessenger.Output(-1,temp2,i); break; } } i3=lstrlen(buffer)+source.GetLength(); Realloc( i3 ); Text::SlideString(buffer+i2,source.GetLength()+(i-i2)); memcpy(buffer+i,source.GetBuffer(),source.GetLength()); //新しい参照ディレクトリをセット char temp4[MAX_PATH]; _splitpath(temporary,temp2,temp4,0,0); lstrcat(temp2,temp4); LayerDir[layer]=(char *)malloc(lstrlen(temp2)+1); lstrcpy(LayerDir[layer],temp2); //ファイル範囲をスライド LastFileByte[layer]=i+source.GetLength()-1; for(i3=0;i30 && buffer[lstrlen(buffer)-1] != '\n' ) { Realloc( length + 1 ); lstrcat( buffer, "\n" ); } // アンダーバーによる改行を正規表現に戻す RemoveReturnLineUnderbar(); } void BasicSource::SetBuffer( const char *buffer ){ this->buffer = (char *)calloc( lstrlen(buffer) + 1, 1 ); lstrcpy( this->buffer, buffer ); length = lstrlen(buffer); // ダミー改行をセット Realloc( length + 2 ); Text::SlideString( this->buffer, 2 ); this->buffer[0] = '\n'; this->buffer[1] = '\n'; } bool BasicSource::ReadFile( const string &filePath ){ if( !Text::ReadFile( filePath ) ){ return false; } // 改行コードをCRLFからLFに変換 ChangeReturnLineChar(); // basic.sbpをインクルード //const char *headCode = "#include \n"; const char *headCode = ""; Realloc( length + lstrlen(headCode) ); Text::SlideString( buffer, lstrlen(headCode) ); memcpy( buffer, headCode, lstrlen(headCode) ); // #defineと#requireを初期化 // TODO: バージョン番号の識別子defineが未完成 objDefine.Init(0); requireFiles.clear(); // コメントを削除 RemoveComments(); // #ifdefディレクティブを処理 objDefine.DirectiveIfdef( buffer ); //最終行には文字を含ませないようにする Realloc( length + 1 ); lstrcat( buffer, "\n" ); // #include / #require ディレクティブを処理 DirectiveIncludeOrRequire(); // アンダーバーによる改行を正規表現に戻す RemoveReturnLineUnderbar(); // ダミー改行をセット Realloc( length + 2 ); Text::SlideString( buffer, 2 ); buffer[0] = '\n'; buffer[1] = '\n'; extern char *basbuf; basbuf = GetBuffer(); return true; } bool BasicSource::Generate( const string &genName, const char *genBuffer ){ const int genBufferLength = lstrlen( genBuffer ); #ifdef _DEBUG // 挿入ソースに改行コードが含まれていないかを検査する for( int i=0; genBuffer[i] ; i++ ){ if( genBuffer[i] == '\n' ){ compiler.errorMessenger.OutputFatalError(); break; } } #endif bool isFound = false; for( int i=0; ; i++ ){ if( i == 0 || buffer[i] == '\n' ){ if( buffer[i] == '\n' ){ i++; } while( IsBlank( buffer[i] ) ){ i++; } int startIndex = i; if( memicmp( buffer + i, generateDirectiveName.c_str(), generateDirectiveName.size() ) == 0 ){ i += (int)generateDirectiveName.size(); while( IsBlank( buffer[i] ) ){ i++; } char temporary[VN_SIZE]; for( int i2=0; ; i++, i2++ ){ if( buffer[i] == '\n' ){ temporary[i2] = 0; break; } temporary[i2] = buffer[i]; } if( genName == temporary ){ // 一致 int endIndex = i; int lengthOffset = genBufferLength - ( endIndex - startIndex ); Realloc( length + lengthOffset ); Text::SlideString( buffer + endIndex, lengthOffset ); memcpy( buffer + startIndex, genBuffer, genBufferLength ); isFound = true; break; } } } } return isFound; } void BasicSource::Addition( const char *buffer ){ Realloc( length + lstrlen(buffer) ); lstrcat( this->buffer, buffer ); } bool BasicSource::GetLineInfo( int sourceCodePos, int &line, std::string &filePath ) const { int i2,i3,i4,i5; const char *buffer = GetBuffer(); int i = sourceCodePos; if(buffer[i]=='\n') i--; for(i3=0,i2=0;i3 &values ) { std::string result = source; std::map::const_iterator it = values.begin(); while( it != values.end() ) { while( true ) { std::string::size_type index = result.find( it->first ); if( index == std::string::npos ) { break; } result = result.substr( 0, index ) + it->second + result.substr( index + it->first.length() ); } it++; } return result; }