#include "stdafx.h" #include const std::string BasicSource::generateDirectiveName = "#generate"; class CDefine{ stdext::hash_set names; public: // void Free(); void Init( bool isDebug, bool isDll, bool isUnicode, int majorVer ); bool add(char const *name); bool undef(char const *name); bool check(char const *name); void preprocessor_ifdef(char *buffer,bool isNot); void DirectiveIfdef(char *buffer); }; CDefine objDefine; ////////////////////////////////////// // #requireの管理 ////////////////////////////////////// namespace { class CRequireFiles{ stdext::hash_set filepaths; public: void clear(){ filepaths.clear(); } //既に存在するものを追加しようとするとfalseを返す(旧IsIncludedと逆なことに注意) bool TryAdd( const std::string &includeFilePath ){ char tempPath[MAX_PATH]; DWORD len = GetShortPathName(includeFilePath.c_str(), tempPath, MAX_PATH); if (len >= MAX_PATH){ return false; } for( DWORD i = 0; i < len; ++i ){ char c = toupper(tempPath[i]); if (c == '/'){ tempPath[i] = '\\'; } else{ tempPath[i] = c; } } return filepaths.insert( tempPath ).second; } }; CRequireFiles requireFiles; } //namespace ////////////////////////////////////// // #define間するクラス ////////////////////////////////////// void CDefine::Init( bool isDebug, bool isDll, bool isUnicode, int majorVer ) { names.clear(); if( isDebug ) { add("_DEBUG"); } #ifdef _AMD64_ add("_WIN64"); #endif if( isDll ) { add("_DLL"); } if( isUnicode ) { add( "UNICODE" ); } char temporary[255]; sprintf(temporary,"_AB_VER%d",majorVer); add(temporary); } bool CDefine::add(char const *name) { return names.insert(name).second; } bool CDefine::undef(char const *name){ return names.erase(name) > 0; } bool CDefine::check(char const *name){ return names.find(name) != names.end(); } int Search_endif(char const *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=strlen("#ifndef"); else i=strlen("#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の行を消去 memset(buffer,' ',static_cast(i)); 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); //ディレクティブを消去 memset(buffer+i,' ',static_cast(i2-i)); i=i2; } if(memicmp(buffer+i,"#undef",6)==0){ i2=i+6; 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); //ディレクティブを消去 memset(buffer+i,' ',static_cast(i2-i)); i=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 std::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; } //改行コードのCRLFをLFに変換 int ChangeReturnCodeImpl(char *buffer) { int i; for(i=0;buffer[i]!='\0';i++){ if(buffer[i]=='\r'&&buffer[i+1]=='\n'){ buffer[i]=' '; } } return i; } void BasicSource::ChangeReturnLineChar(){ int i; 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 ChangeReturnCodeImpl(buffer); length = i; } void BasicSource::RemoveComments(){ int i,i2,i3,IsStr; char *temporary=static_cast(malloc(strlen(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; } std::swap(buffer,temporary); free(temporary); } bool BasicSource::ReadFile_InIncludeDirective( const std::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( const std::string &mainSourceFilePath, const std::string &includeDirPath ) { 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( mainSourceFilePath ); //参照ディレクトリ std::string mainSourceFileDir = Jenga::Common::Path::ExtractDirPath( mainSourceFilePath ); LayerDir[0]=(char *)malloc(mainSourceFileDir.size()+1); strcpy(LayerDir[0],mainSourceFileDir.c_str()); 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; int includeDirectiveLength; char findStr[1024]; 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++; includeDirectiveLength = i2 - i; if(sw1){ sprintf(temp2,"%s\\%s", includeDirPath.c_str(), temporary ); strcpy(findStr,temp2); } else{ Jenga::Common::Directory dir( LayerDir[layer] ); strcpy( findStr, dir.GetFullPath( temporary ).c_str() ); } } else if(memcmp(buffer+i+1,"prompt",6)==0){ includeDirectiveLength = 7; sprintf(findStr,"%s\\basic\\prompt.sbp", includeDirPath.c_str() ); } else if(memcmp(buffer+i+1,"N88BASIC",8)==0){ includeDirectiveLength = 9; sprintf(findStr,"%s\\basic\\prompt.sbp", includeDirPath.c_str() ); } else if(memcmp(buffer+i+1,"console",7)==0){ //サブシステム タイプをCUIに変更 extern unsigned short TypeOfSubSystem; TypeOfSubSystem=IMAGE_SUBSYSTEM_WINDOWS_CUI; includeDirectiveLength = 8; sprintf(findStr,"%s\\basic\\dos_console.sbp", includeDirPath.c_str() ); } else continue; // インクルードファイルを列挙(ワイルドカード指定を想定) Jenga::Common::Strings resultOfFullPath; Jenga::Common::FileSystem::SearchFiles( resultOfFullPath, findStr ); if( resultOfFullPath.empty() ) { this->cannotIncludePath = findStr; this->cannotIncludeSourcePos = i; includedFilesRelation.AddLine( FileLayer[layer] ); break; } for( int j=static_cast(resultOfFullPath.size()-1); j>=0; j-- ) { const std::string &sourceFilePath = resultOfFullPath[j]; const int headIndex = i; if( headIndex == 0 && Jenga::Common::Path( sourceFilePath ).GetFileName() == "basic" ) { // basic.sbpインクルード時は何もしない // ワイルドカードで複数ファイルを指定した場合、2つ目以上のファイルの場合もこちら } else { //ディレクティブが消えるため、一行減ってしまうのを防ぐ(basic.sbpを除く) Text::SlideString( buffer + headIndex + includeDirectiveLength, 1 ); buffer[headIndex+includeDirectiveLength]='\n'; for(i3=0;i3<=layer;i3++) LastFileByte[i3]++; } layer++; FileLayer[layer] = includedFilesRelation.AddFile( sourceFilePath ); //#requireの場合では、既に読み込まれているファイルは読み込まないようにする BasicSource source; if( !requireFiles.TryAdd( sourceFilePath ) && isRequire ){ //既に読み込まれているときは空データ source.SetBuffer( "" ); } else{ //インクルードファイルを読み込む if( !source.ReadFile_InIncludeDirective( sourceFilePath ) ) { _ASSERTE( false ); } } Realloc( strlen(buffer) + source.GetLength() ); Text::SlideString( buffer + headIndex + includeDirectiveLength, source.GetLength() - includeDirectiveLength ); memcpy( buffer + headIndex, source.GetBuffer(), source.GetLength() ); //新しい参照ディレクトリをセット char temp4[MAX_PATH]; _splitpath(sourceFilePath.c_str(),temp2,temp4,0,0); strcat(temp2,temp4); LayerDir[layer]=(char *)malloc(strlen(temp2)+1); strcpy(LayerDir[layer],temp2); //ファイル範囲をスライド LastFileByte[layer] = headIndex + source.GetLength() - 1; for(i3=0;i30 && buffer[strlen(buffer)-1] != '\n' ) { Realloc( length + 1 ); strcat( buffer, "\n" ); } // アンダーバーによる改行を正規表現に戻す RemoveReturnLineUnderbar(); } // 指定したインデックスが何行目かを取得 bool BasicSource::GetLineFromIndex( int index, int &result ) const { result = 0; for( int i=2; ibuffer[i] == '\n' ) { result ++; } if( this->buffer[i] == '\0' ) { return false; } } return true; } void BasicSource::SetBuffer( const char *buffer ){ this->buffer = (char *)calloc( strlen(buffer) + 1, 1 ); strcpy( this->buffer, buffer ); length = strlen(buffer); // ダミー改行をセット Realloc( length + 2 ); Text::SlideString( this->buffer, 2 ); this->buffer[0] = '\n'; this->buffer[1] = '\n'; } bool BasicSource::ReadFile( const std::string &filePath, bool isDebug, bool isDll, bool isUnicode, int majorVer, const std::string &mainSourceFilePath, const std::string &includeDirPath ) { if( !Text::ReadFile( filePath ) ){ return false; } // 改行コードをCRLFからLFに変換 ChangeReturnLineChar(); // #defineと#requireを初期化 // TODO: バージョン番号の識別子defineが未完成 objDefine.Init( isDebug, isDll, isUnicode, majorVer ); requireFiles.clear(); // コメントを削除 RemoveComments(); // #ifdefディレクティブを処理 objDefine.DirectiveIfdef( buffer ); //最終行には文字を含ませないようにする Realloc( length + 1 ); strcat( buffer, "\n" ); // #include / #require ディレクティブを処理 DirectiveIncludeOrRequire( mainSourceFilePath, includeDirPath ); // アンダーバーによる改行を正規表現に戻す RemoveReturnLineUnderbar(); // ダミー改行をセット Realloc( length + 2 ); Text::SlideString( buffer, 2 ); buffer[0] = '\n'; buffer[1] = '\n'; extern char *basbuf; basbuf = GetBuffer(); return true; } void BasicSource::Addition( const char *buffer ){ Realloc( length + strlen(buffer) ); strcat( this->buffer, buffer ); } bool BasicSource::GetLineInfo( int sourceCodePos, int &line, std::string &filePath ) const { const char *buffer = this->GetBuffer(); if( this->GetLength() < sourceCodePos ) { char temp[256]; strncpy( temp, buffer, 100 ); strcat( temp, "..." ); MyAssertMsg( false, ( (std::string)"下記ソースコードの" + Jenga::Common::ToString( sourceCodePos ) + "バイト目(存在しない箇所)を参照しようとした。\n\n" + temp ).c_str() ); return false; } int i = sourceCodePos; int i2,i3,i4,i5; if(buffer[i]=='\n') i--; bool result = this->GetLineFromIndex( i, i2 ); MyAssert( result ); if( includedFilesRelation.GetLineCounts() <= i2 ) { MyAssertMsg( false, "BasicSource::GetLineInfoメソッドで不正な行の情報を取得しようとした" ); //ファイル・行番号を特定できなかった場合 line = -1; filePath = ""; return false; } i4=0; while( includedFilesRelation.GetFileNumber( i2 ) != includedFilesRelation.GetFileNumber( i4 ) ) { i4++; } for(i3=0,i5=0;i5IsNothing() ) { _ASSERTE( false ); throw; } return relationalObjectModuleIndex; } bool SourceCodePosition::IsNothing() const { if( this->relationalObjectModuleIndex == -1 && this->pos == -1 ) { return true; } if( this->relationalObjectModuleIndex == -1 || this->pos == -1 ) { _ASSERTE( false ); throw; } return false; }