#include "leak_detector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "errors.h" #include "SgUtils.h" #include "../VisualizerCalls/get_information.h" #include "../VisualizerCalls/SendMessage.h" #include "ParseFiles.h" #include "StdCapture.h" #include "FileInfo.h" using namespace std; extern "C" int parse_file(int argc, char* argv[], char* proj_name); extern const char* VISUALIZER_DATA_PATH; static void findModuleDeclInProject(const string& name, const vector& files, map& modDecls) { vector filesList; for (int z = 0; z < files.size(); ++z) filesList.push_back((char*)files[z].c_str()); SgProject* tmpProj = new SgProject(name.c_str(), filesList.data(), files.size()); int numF = tmpProj->numberOfFiles(); for (int z = 0; z < numF; ++z) { vector modules; SgFile* currF = &tmpProj->file(z); string fileName = currF->filename(); convertToLower(fileName); findModulesInFile(currF, modules); for (auto& elem : modules) { if (string(elem->fileName()) == currF->filename()) { const string name = elem->symbol()->identifier(); auto it = modDecls.find(name); if (it != modDecls.end() && it->second != currF->filename()) { __spf_print(1, "found several module declaration of '%s' in files '%s' and '%s'\n", name.c_str(), it->second.c_str(), currF->filename()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else modDecls.insert(it, make_pair(name, currF->filename())); } } } InitializeTable(); } static void createIncludeOrder(vector &toIncl, const map& moduleDelc, const map>& modDirectOrder, set &done, const string &curr) { if (done.find(curr) == done.end()) { for (auto& elem : modDirectOrder.find(curr)->second) createIncludeOrder(toIncl, moduleDelc, modDirectOrder, done, elem); if (done.find(curr) == done.end()) { toIncl.push_back(moduleDelc.find(curr)->second); done.insert(curr); } } } static set applyModuleDeclsForFile(FileInfo *forFile, const map &mapFiles, const map& moduleDelc, const map>& mapModuleDeps, const map>& modDirectOrder, vector &optSplited, bool includeForInline = false) { set retFilesMod; auto itF = mapModuleDeps.find(forFile->fileName); if (itF == mapModuleDeps.end() && !includeForInline) return retFilesMod; vector toIncl; set done; if (itF != mapModuleDeps.end()) { for (auto& mod : itF->second) if (moduleDelc.find(mod) != moduleDelc.end()) createIncludeOrder(toIncl, moduleDelc, modDirectOrder, done, mod); } //rewrite files to the next iter of parse set allFiles; for (auto& incl : toIncl) { if (mapFiles.find(incl) == mapFiles.end()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); allFiles.insert(mapFiles.find(incl)->second); } allFiles.insert(forFile); set toConvert; int mainStyle = forFile->style; for (auto& file : allFiles) if (mainStyle != file->style && file->style != 3) toConvert.insert(file); const string mainText = forFile->text; for (auto& file : toConvert) file->convertToUniform(); string include = ""; int includeCount = 0; set included; for (auto& incl : toIncl) { if (included.find(incl) == included.end()) { include += " include '" + incl + "'\n"; includeCount++; } included.insert(incl); } vector toInclEnds; string includeLast = ""; if (includeForInline) { //find needed modules first vector filesWithModules; for (auto& elem : moduleDelc) filesWithModules.push_back(elem.second); for (auto& file : filesWithModules) { if (file != forFile->fileName && included.find(file) == included.end()) { toInclEnds.push_back(file); included.insert(file); } } for (auto& file : mapFiles) if (file.second != forFile && included.find(file.second->fileName) == included.end()) toInclEnds.push_back(file.second->fileName); if (toInclEnds.size()) includeLast += "!SPF SHADOW FILES\n"; for (auto& incl : toInclEnds) includeLast += " include '" + incl + "'\n"; } if (includeCount) include = "!SPF NUM FILES " + std::to_string(includeCount) + "\n" + include; const string data = include + mainText + includeLast; __spf_print(1, "include to file %s before\n", forFile->fileName.c_str()); __spf_print(1, "%s", include.c_str()); __spf_print(1, "include to file %s after\n", forFile->fileName.c_str()); __spf_print(1, "%s", includeLast.c_str()); writeFileFromStr(forFile->fileName, data); /*static string tmp = "tmp__"; static int id = 0; writeFileFromStr(tmp + to_string(id++) + ".ftn", data);*/ forFile->includesAdded = included.size(); forFile->includes = included; retFilesMod.insert(forFile); return retFilesMod; } static void restoreOriginalText(const vector& listOfProject) { for (auto& elem : listOfProject) writeFileFromStr(elem.fileName, elem.text); fflush(NULL); } static inline void restoreOriginalText(const FileInfo& file) { writeFileFromStr(file.fileName, file.text); } static void checkRetCode(FileInfo& info, const string& errorMessage) { if (info.error != 0) info.lvl++; if (errorMessage.find("Warning 308") != string::npos) if (info.error == 0) info.error = 1; } static vector parseList(vector& listOfProject, bool needToInclude, bool needToIncludeForInline, const map> &mapModuleDeps, const map &moduleDelc, const map> &modDirectOrder, bool isFromConsole = false) { map mapFiles; for (auto& elem : listOfProject) mapFiles[elem.fileName] = &elem; vector errors; int i = 1; int N = listOfProject.size(); for (auto& elem : listOfProject) { sendMessage_progress(std::to_wstring((int)(((double)(i++) / N) * 100))); string file = elem.fileName; string options = elem.options; vector optSplited = splitAndArgvCreate(options); char** toParse = new char* [optSplited.size() + 1]; for (int z = 0; z < optSplited.size(); ++z) { toParse[z] = new char[optSplited[z].size() + 1]; strcpy(toParse[z], optSplited[z].c_str()); } toParse[optSplited.size()] = new char[file.size() + 1]; strcpy(toParse[optSplited.size()], file.c_str()); if (options.find("-FI") != string::npos) elem.style = 0; else if (options.find("-extend_source") != string::npos) elem.style = 1; else if (options.find("-FR") != string::npos || options.find("-f90") != string::npos) elem.style = 2; else { //fdv|f|ftn|for|f90|f95|f03 static set fixed_exts = { "for", "f", "ftn" }; static set free_exts = { "f90", "f95", "f03" }; string ext = OnlyExt(file.c_str()); if (fixed_exts.find(ext) != fixed_exts.end()) elem.style = 0; else if (free_exts.find(ext) != free_exts.end()) elem.style = 2; } for (int z = 0; z < optSplited.size(); ++z) { if (optSplited[z] == "-o") { if (z + 1 == optSplited.size()) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); elem.outDepPath = optSplited[z + 1]; break; } } FILE* depPath = fopen(elem.outDepPath.c_str(), "r"); if (depPath && !isFromConsole && !needToIncludeForInline) { fclose(depPath); if (elem.error <= 0) { elem.error = 0; errors.push_back(""); for (int z = 0; z <= optSplited.size(); ++z) delete toParse[z]; delete[] toParse; continue; } } #ifdef _WIN32 sendMessage_2lvl(L" обработка файла '" + to_wstring(file) + L"'"); #else sendMessage_2lvl(L" processing file '" + to_wstring(file) + L"'"); #endif StdCapture::Init(); string errorMessage = ""; try { set filesModified; StdCapture::BeginCapture(); if (needToInclude) filesModified = applyModuleDeclsForFile(&elem, mapFiles, moduleDelc, mapModuleDeps, modDirectOrder, optSplited, needToIncludeForInline); else if (needToIncludeForInline) filesModified = applyModuleDeclsForFile(&elem, mapFiles, moduleDelc, mapModuleDeps, modDirectOrder, optSplited, needToIncludeForInline); int retCode = parse_file(optSplited.size(), toParse, "dvm.proj"); if (needToInclude || needToIncludeForInline) { for (auto &elem : filesModified) restoreOriginalText(*elem); fflush(NULL); } elem.error = retCode; StdCapture::EndCapture(); errorMessage = StdCapture::GetCapture(); checkRetCode(elem, errorMessage); } catch (int err) { StdCapture::EndCapture(); errorMessage = StdCapture::GetCapture(); if (needToInclude || needToIncludeForInline) restoreOriginalText(listOfProject); } catch (...) { StdCapture::EndCapture(); errorMessage = StdCapture::GetCapture(); if (needToInclude || needToIncludeForInline) restoreOriginalText(listOfProject); } errors.push_back(errorMessage); for (int z = 0; z <= optSplited.size(); ++z) delete toParse[z]; delete[] toParse; createNeededException(); } return errors; } static string shiftLines(const string &in, const map &mapOfFiles, const FileInfo* currF) { int byNum = 0; auto it = in.find("on line "); if (it != string::npos) it += strlen("on line "); int d = 0; sscanf(in.c_str() + it, "%d", &d); auto it1 = in.find("of", it + 1); if (it1 == string::npos) return in; it1 += 3; string fileN = in.substr(it1, in.find(':', it1) - it1); auto itF = mapOfFiles.find(fileN); if (itF == mapOfFiles.end()) return in; if (itF->second != currF) return in; byNum = itF->second->includesAdded; if (byNum == 0) return in; if (d - byNum <= 0) { //return in; printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else d -= byNum; string newStr = in.substr(0, it) + std::to_string(d) + in.substr(in.find(' ', it + 1)); return newStr; } static void addMessage(const string& in, const map& mapOfFiles, const FileInfo* currF, map>& messages, typeMessage type) { int byNum = 0; auto it = in.find("on line "); if (it != string::npos) it += strlen("on line "); int line = 0; sscanf(in.c_str() + it, "%d", &line); auto it1 = in.find("of", it + 1); if (it1 == string::npos) return; it1 += 3; string fileN = in.substr(it1, in.find(':', it1) - it1); auto itF = mapOfFiles.find(fileN); if (itF != mapOfFiles.end() && itF->second != currF) { byNum = itF->second->includesAdded; if (byNum != 0) { if (line - byNum <= 0) { //return in; printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } else line -= byNum; } } const string newStr = in.substr(0, it) + std::to_string(line) + in.substr(in.find(' ', it + 1)); wstring messageE, messageR; __spf_printToLongBuf(messageE, L"%s", to_wstring(newStr).c_str()); __spf_printToLongBuf(messageR, L"%s", to_wstring(newStr).c_str()); messages[fileN].push_back(Messages(type, line, messageR, messageE, 6000)); } static int dumpErrors(const vector& listOfProject, const vector& errors, map>& messages) { int errorsCount = 0; map mapOfFiles; for (auto& elem : listOfProject) mapOfFiles[elem.fileName] = &elem; int z = 0; for (auto& file : listOfProject) { if (errors[z] == "") { FILE* ferr = fopen(file.errPath.c_str(), "w"); if (ferr) fclose(ferr); ++z; continue; } string errS = "", outS = ""; vector splited; splitString(errors[z], '\n', splited); for (auto& elem : splited) { if (elem.find("Warning 308") != string::npos) { addMessage(elem, mapOfFiles, &file, messages, WARR); outS += shiftLines(elem, mapOfFiles, &file) + "\n"; } else if (elem.find("Error") != string::npos) { addMessage(elem, mapOfFiles, &file, messages, ERROR); errS += shiftLines(elem, mapOfFiles, &file) + "\n"; errorsCount++; } } FILE* ferr = fopen(file.errPath.c_str(), "w"); FILE* fout = fopen(file.outPath.c_str(), "w"); if (ferr) { fprintf(ferr, "%s", errS.c_str()); fclose(ferr); } if (fout) { fprintf(fout, "%s", outS.c_str()); fclose(fout); } fflush(NULL); ++z; } return errorsCount; } static int createMapOfUse(const vector& errors, const vector& listOfProject, map> &mapModuleDeps) { int changed = 0; for (int z = 0; z < listOfProject.size(); ++z) { if (listOfProject[z].error >= 0) { vector splited; splitString(errors[z], '\n', splited); for (auto& err : splited) { if (err.find("Warning 308") != string::npos && err.find(listOfProject[z].fileName) != string::npos) { auto pos = err.find("Unknown module"); if (pos != string::npos) { pos += strlen("Unknown module") + 1; string substr = ""; while (err[pos] != ' ' && pos != err.size()) substr += err[pos++]; mapModuleDeps[listOfProject[z].fileName].insert(substr); changed++; } } } } } return changed; } static map> createModuleOrder(const map &moduleDelc, const map> &mapModuleDeps) { map> modDirectOrder; for (auto& elem : moduleDelc) modDirectOrder[elem.first] = set(); for (auto& elem : moduleDelc) { auto itF = mapModuleDeps.find(elem.second); if (itF != mapModuleDeps.end()) { for (auto& inFile : itF->second) { if (moduleDelc.find(inFile) != moduleDelc.end()) modDirectOrder[elem.first].insert(inFile); } } } return modDirectOrder; } static void printDebug(const map>& mapModuleDeps, const map>& modDirectOrder, const vector& listOfProject, bool console = false) { string toPrint = "MODULE DEPS:\n"; for (auto& elem : mapModuleDeps) { toPrint += elem.first + '\n'; for (auto& setEl : elem.second) toPrint += " " + setEl + '\n'; } toPrint += "MODULE DIRECT ORDER:\n"; for (auto& elem : modDirectOrder) { toPrint += elem.first + '\n'; for (auto& setEl : elem.second) toPrint += " " + setEl + '\n'; } toPrint += "FILES LVL:\n"; for (auto& elem : listOfProject) toPrint += elem.fileName + " " + elem.outDepPath + " lvl = " + std::to_string(elem.lvl) + '\n'; if (console) printf("%s\n", toPrint.c_str()); __spf_print(1, "%s\n", toPrint.c_str()); } static void parseFiles(int& iters, vector& errors, vector& listOfProject, map>& mapModuleDeps, map& moduleDelc, map>& modDirectOrder, int parseForInlining, bool isFromConsole) { int changed = 0; int lastChanged = 0; const string projName = (parseForInlining == 0) ? "tmp" : "tmp_inl"; do { #ifdef _WIN32 sendMessage_1lvl(L"выполняется " + std::to_wstring((iters + 1)) + L" итерация синтаксического анализа"); #else sendMessage_1lvl(L"running " + std::to_wstring((iters + 1)) + L" iteration of syntax analisys"); #endif errors = parseList(listOfProject, iters != 0, parseForInlining, mapModuleDeps, moduleDelc, modDirectOrder, isFromConsole); changed = createMapOfUse(errors, listOfProject, mapModuleDeps); if (iters != 0) if (lastChanged <= changed) break; createNeededException(); if (changed) { vector files; for (auto& elem : listOfProject) if (elem.error == 0) files.push_back(elem.outDepPath); if (files.size() == 0) break; findModuleDeclInProject(projName + std::to_string(iters++), files, moduleDelc); modDirectOrder = createModuleOrder(moduleDelc, mapModuleDeps); } lastChanged = changed; //printDebug(mapModuleDeps, modDirectOrder, listOfProject); } while (changed); } static vector finalyzeParsing(const vector& listOfProject, const map> mapModuleDeps, const map moduleDelc) { vector filesCompilationOrder; int added = 0; int iter = 0; vector files; while (added != listOfProject.size()) { for (auto& elem : listOfProject) { if (elem.lvl == iter) { files.push_back(elem.fileName); added++; } } ++iter; } map> fileDeps; for (auto& file : files) { fileDeps[file] = set(); if (mapModuleDeps.find(file) == mapModuleDeps.end()) continue; for (auto& dep : mapModuleDeps.at(file)) { if (moduleDelc.find(dep) == moduleDelc.end()) continue; fileDeps[file].insert(moduleDelc.at(dep)); } } set addedFiles; added = 0; while (added != fileDeps.size()) { for (auto& file : fileDeps) { bool depsAdded = true; for (auto& dep : file.second) if (addedFiles.find(dep) == addedFiles.end()) depsAdded = false; if (depsAdded && addedFiles.find(file.first) == addedFiles.end()) { filesCompilationOrder.push_back(file.first); addedFiles.insert(file.first); added++; } } } __spf_print(1, "files compilation order:\n"); for (auto& file : filesCompilationOrder) __spf_print(1, " %s\n", file.c_str()); return filesCompilationOrder; } static int parseFiles(vector& errors, vector& listOfProject, vector& filesCompilationOrder, int parseForInlining, bool isFromConsole = false) { int rethrow = 0; int iters = 0; map> mapModuleDeps; map moduleDelc; map> modDirectOrder; try { parseFiles(iters, errors, listOfProject, mapModuleDeps, moduleDelc, modDirectOrder, false, isFromConsole); filesCompilationOrder = finalyzeParsing(listOfProject, mapModuleDeps, moduleDelc); if (parseForInlining) parseFiles(iters, errors, listOfProject, mapModuleDeps, moduleDelc, modDirectOrder, true, isFromConsole); } catch (int err) { rethrow = err; } catch (...) { rethrow = -1; } return rethrow; } int parseFiles(const char* proj, vector& filesCompilationOrder, int parseForInlining, map>& messages) { FILE* list = fopen(proj, "r"); if (!list) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); vector pathSplit; if (string(proj).find('\\') != string::npos) splitString(proj, '\\', pathSplit); else splitString(proj, '/', pathSplit); if (pathSplit.size() < 2) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); if (pathSplit[pathSplit.size() - 2] != VISUALIZER_DATA_PATH) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); string fullPath = ""; for (int z = 0; z < pathSplit.size() - 2; ++z) fullPath += pathSplit[z] + "/"; if (fullPath == "") fullPath = "./"; else { //change dir if (chdir(fullPath.c_str()) != 0) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } vector listOfProject; while (!feof(list)) { char buf[1024]; if (fgets(buf, 1024, list) == NULL) continue; string toAdd = buf; if (toAdd[toAdd.size() - 1] == '\n') toAdd = toAdd.erase(toAdd.size() - 1); string fileNameFixed = ""; auto idx = toAdd.find(fullPath); if (idx != string::npos) fileNameFixed = toAdd.substr(idx + fullPath.size()); else fileNameFixed = (toAdd.substr(0, 2) == "./") ? toAdd.substr(2) : toAdd; const string optPath = fullPath + VISUALIZER_DATA_PATH + "/options/" + fileNameFixed + ".opt"; const string errPath = fullPath + VISUALIZER_DATA_PATH + "/options/" + fileNameFixed + ".err"; const string outPath = fullPath + VISUALIZER_DATA_PATH + "/options/" + fileNameFixed + ".out"; const string fileText = readFileToStr(toAdd); FILE* opt = fopen(optPath.c_str(), "r"); if (!opt) { __spf_print(1, "can not open path %s\n", optPath.c_str()); printInternalError(convertFileName(__FILE__).c_str(), __LINE__); } fgets(buf, 1024, opt); string toAddOpt = buf; if (toAddOpt[toAddOpt.size() - 1] == '\n') toAddOpt = toAddOpt.erase(toAddOpt.size() - 1); fclose(opt); listOfProject.push_back(FileInfo(fileNameFixed, toAddOpt, errPath, outPath, "", fileText)); } fclose(list); vector errors; int rethrow = parseFiles(errors, listOfProject, filesCompilationOrder, parseForInlining); int errCount = dumpErrors(listOfProject, errors, messages); if (rethrow != 0) throw rethrow; return -errCount; } void parseFiles(int argc, char** argv) { map> messages; bool isInline = false; auto result = splitCommandLineForParse(argv, argc, isInline); if (result.second.size() == 0) { printf("Nothing to parse\n"); exit(0); } int code = 0; vector errors; vector listOfProject; string toAddOpt = ""; for (auto& opt : result.first) toAddOpt += opt + " "; for (auto& file : result.second) { const string fileText = readFileToStr(file); listOfProject.push_back(FileInfo(file, toAddOpt + "-o " + file + ".dep", "", "", "", fileText, 0)); } vector filesCompilationOrder; if (isInline) printf(" run parsing for inlining\n"); int rethrow = parseFiles(errors, listOfProject, filesCompilationOrder, isInline, true); int errCount = dumpErrors(listOfProject, errors, messages); if (rethrow == 0) { for (auto& err : errors) { vector splited; splitString(err, '\n', splited); for (auto& elem : splited) { if (elem.find("Error") != string::npos) { printf("%s\n", elem.c_str()); code++; } } } } if (code == 0 && rethrow == 0) { FILE* proj = fopen("dvm.proj", "w"); if (proj == NULL) printInternalError(convertFileName(__FILE__).c_str(), __LINE__); for (auto& file : result.second) fprintf(proj, "%s.dep\n", file.c_str()); printf("Parsing was completed successfully\n"); } else printf("Parsing was completed with errors, throw code %d, errors count %d\n", rethrow, code); dumpMessages(false, messages, VISUALIZER_DATA_PATH); exit(0); }