diff --git a/PCCcompiler/codegen.cpp b/PCCcompiler/codegen.cpp index 55707e7..36f61a1 100644 --- a/PCCcompiler/codegen.cpp +++ b/PCCcompiler/codegen.cpp @@ -350,27 +350,24 @@ std::string generateAssembly(const CompilerState& state) { case OpType::PRINT: { // Instrukcja PRINT zwykła (liczba) std::string val = getVarLocation(instr.arg1, stackMap); - result += " mov edx, " + val + "\\n"; - result += " lea rcx, [rel fmt_int]\\n"; - result += " xor eax, eax\\n"; // <-- DODAJ TO - result += " call printf\\n"; + result += " mov edx, " + val + "\n"; + result += " lea rcx, [rel fmt_int]\n"; + result += " xor eax, eax\n"; + result += " call printf\n"; break; } case OpType::PRINT_STRING: { - // Instrukcja PRINT_STRING (tekst) std::string target = instr.arg1; - if (target.find("str_") == 0) { - // Literał: print("tekst") - result += " lea rdx, [rel " + target + "]\\n"; + if (target.rfind("str_", 0) == 0) { + result += " lea rdx, [rel " + target + "]\n"; } else { - // Zmienna: print(s) -> s trzyma adres std::string val = getVarLocation(target, stackMap); - result += " mov rdx, " + val + "\\n"; + result += " mov rdx, " + val + "\n"; } - result += " lea rcx, [rel fmt_str]\\n"; - result += " xor eax, eax\\n"; // <-- DODAJ TO - result += " call printf\\n"; + result += " lea rcx, [rel fmt_str]\n"; + result += " xor eax, eax\n"; + result += " call printf\n"; break; } case OpType::CALL: { diff --git a/PCCcompiler/parser.cpp b/PCCcompiler/parser.cpp index de07c3f..aac81f3 100644 --- a/PCCcompiler/parser.cpp +++ b/PCCcompiler/parser.cpp @@ -40,12 +40,29 @@ std::string registerStringLiteral(CompilerState& state, std::string content) { void processSource(const std::string& src, CompilerState& state) { std::istringstream iss(src); - std::string line; + std::vector lines; + { + std::istringstream iss(src); + std::string t; + while (std::getline(iss, t)) lines.push_back(trim(t)); + } - while (std::getline(iss, line)) { - line = trim(line); + for (size_t i = 0; i < lines.size(); i++) { + std::string line = trim(lines[i]); if (line.empty() || line.substr(0, 2) == "//" || line[0] == '#') continue; + if (line.find("} else") != std::string::npos) { + // najpierw obsĹ‚uĹĽ zamkniÄ™cie bloku + std::string saved = line; + line = "}"; + // ... uruchom kod obsĹ‚ugi "}" (najlepiej przenieĹ› go do funkcji pomocniczej) + // potem obsĹ‚uĹĽ else: + line = "else"; + // ... uruchom kod obsĹ‚ugi else + continue; + } + + // ========================================================= // 1. DEFINICJA FUNKCJI (np. void main() { ) // ========================================================= @@ -72,42 +89,79 @@ void processSource(const std::string& src, CompilerState& state) { // ========================================================= // 2. ZAMYKANIE BLOKU '}' (Koniec funkcji, IF‑a lub WHILE‑a) // ========================================================= - if (!line.empty() && line.back() == '}') { + if (line == "}") { + + // lookahead: czy nastÄ™pna sensowna linia to "else" / "else {" + bool nextIsElse = false; + size_t j = i + 1; + while (j < lines.size()) { + std::string nl = trim(lines[j]); + if (nl.empty() || nl.rfind("//", 0) == 0) { j++; continue; } + if (nl.rfind("else", 0) == 0) nextIsElse = true; + break; + } + if (!state.blockStack.empty()) { std::string blockInfo = state.blockStack.top(); - state.blockStack.pop(); - bool isWhile = (blockInfo.length() > 6 && blockInfo.substr(0, 6) == "WHILE|"); + // --- WHILE --- + if (blockInfo.rfind("WHILE|", 0) == 0) { + state.blockStack.pop(); - if (isWhile) { - size_t firstPipe = blockInfo.find('|'); - size_t secondPipe = blockInfo.rfind('|'); - std::string labelStart = blockInfo.substr(firstPipe + 1, secondPipe - firstPipe - 1); - std::string labelEnd = blockInfo.substr(secondPipe + 1); + size_t p1 = blockInfo.find('|'); + size_t p2 = blockInfo.rfind('|'); + std::string labelStart = blockInfo.substr(p1 + 1, p2 - p1 - 1); + std::string labelEnd = blockInfo.substr(p2 + 1); if (state.currentFunction) { state.currentFunction->instructions.push_back({ OpType::JMP, labelStart, "", "" }); state.currentFunction->instructions.push_back({ OpType::LABEL, labelEnd, "", "" }); } - std::cout << " [PARSER] } End WHILE loop\n"; + continue; } - else { - // To zwykĹ‚y blok (if lub else) - if (state.currentFunction) { - state.currentFunction->instructions.push_back({ OpType::LABEL, blockInfo, "", "" }); + + // --- IF (specjalny wpis IF|else|end) --- + if (blockInfo.rfind("IF|", 0) == 0) { + state.blockStack.pop(); + + size_t p1 = blockInfo.find('|'); + size_t p2 = blockInfo.rfind('|'); + std::string labelElse = blockInfo.substr(p1 + 1, p2 - p1 - 1); + std::string labelEnd = blockInfo.substr(p2 + 1); + + if (nextIsElse) { + // zamykamy blok IF, ale zaraz bÄ™dzie ELSE: + // 1) przeskocz ELSE po wykonaniu IF + // 2) wstaw poczÄ…tek ELSE + if (state.currentFunction) { + state.currentFunction->instructions.push_back({ OpType::JMP, labelEnd, "", "" }); + state.currentFunction->instructions.push_back({ OpType::LABEL, labelElse, "", "" }); + } + // Teraz oczekujemy na '}' koĹ„czÄ…ce ELSE -> ma wstawić LABEL labelEnd + state.blockStack.push(labelEnd); } - std::cout << " [PARSER] } End block -> " << blockInfo << "\n"; + else { + // if bez else: labelElse jest po prostu "koniec if" + if (state.currentFunction) { + state.currentFunction->instructions.push_back({ OpType::LABEL, labelElse, "", "" }); + } + } + continue; } + + // --- zwykĹ‚y LABEL na stosie (np. koniec ELSE: labelEnd) --- + state.blockStack.pop(); + if (state.currentFunction) { + state.currentFunction->instructions.push_back({ OpType::LABEL, blockInfo, "", "" }); + } + continue; } - else { - // Koniec funkcji - state.currentFunction = nullptr; - std::cout << " [PARSER] } End Function\n"; - } + + // jeĹ›li stos pusty -> zamykamy funkcjÄ™ + state.currentFunction = nullptr; continue; } - // ========================================================= // JESTEĹšMY W ĹšRODKU FUNKCJI // ========================================================= @@ -193,29 +247,21 @@ void processSource(const std::string& src, CompilerState& state) { } // E. IF STATEMENT (z ulepszonÄ… obsĹ‚ugÄ… else) - else if (line.substr(0, 2) == "if") { + else if (line.rfind("if", 0) == 0) { size_t openParen = line.find("("); size_t closeParen = line.rfind(")"); - if (openParen != std::string::npos && closeParen > openParen) { std::string conditionRaw = trim(line.substr(openParen + 1, closeParen - openParen - 1)); - std::string finalConditionVar = conditionRaw; - // ObsĹ‚uga prostych operacji w warunku - if (conditionRaw.find("==") != std::string::npos) { - size_t eq = conditionRaw.find("=="); - std::string tempRes = "_tmp_eq_" + std::to_string(state.labelCounter++); - f.instructions.push_back({ OpType::EQ, tempRes, trim(conditionRaw.substr(0, eq)), trim(conditionRaw.substr(eq + 2)) }); - finalConditionVar = tempRes; - } - - std::string labelFalse = "L_" + std::to_string(state.labelCounter++); - f.instructions.push_back({ OpType::JMP_FALSE, labelFalse, finalConditionVar, "" }); - state.blockStack.push(labelFalse); + std::string labelElse = "L_" + std::to_string(state.labelCounter++); + std::string labelEnd = "L_" + std::to_string(state.labelCounter++); + f.instructions.push_back({ OpType::JMP_FALSE, labelElse, conditionRaw, "" }); + state.blockStack.push("IF|" + labelElse + "|" + labelEnd); } continue; } + // F. WHILE LOOP else if (line.substr(0, 5) == "while") { size_t openParen = line.find("("); @@ -285,19 +331,7 @@ void processSource(const std::string& src, CompilerState& state) { continue; } - else if (line.substr(0, 4) == "else") { - if (!state.blockStack.empty()) { - std::string labelFalse = state.blockStack.top(); - state.blockStack.pop(); - - // Po bloku `if` skocz do koĹ„ca `if‑else`: - std::string labelEnd = "L_" + std::to_string(state.labelCounter++); - f.instructions.push_back({ OpType::JMP, labelEnd, "", "" }); - f.instructions.push_back({ OpType::LABEL, labelFalse, "", "" }); // poczÄ…tek ELSE - state.blockStack.push(labelEnd); - - std::cout << " [PARSER] else block\n"; - } + else if (line.rfind("else", 0) == 0) { continue; } diff --git a/PCCcompiler/preprocessor.cpp b/PCCcompiler/preprocessor.cpp index e3b4d34..012e681 100644 --- a/PCCcompiler/preprocessor.cpp +++ b/PCCcompiler/preprocessor.cpp @@ -3,13 +3,18 @@ #include #include #include -#include +#include namespace fs = std::filesystem; -// Funkcja pomocnicza do wczytania pliku -std::string loadFileContent(const std::string& path) { - std::ifstream in(path); +static std::string ltrim(std::string s) { + const size_t first = s.find_first_not_of(" \t"); + if (first == std::string::npos) return ""; + return s.substr(first); +} + +static std::string loadFileContent(const std::string& path) { + std::ifstream in(path, std::ios::binary); if (!in) { std::cerr << "[PREPROCESSOR] Error: Could not open included file: " << path << "\n"; return ""; @@ -17,63 +22,109 @@ std::string loadFileContent(const std::string& path) { return std::string((std::istreambuf_iterator(in)), std::istreambuf_iterator()); } -std::string preprocessSource(const std::string& src, const std::string& projectDir, const std::string& compilerDir) { +// Próbuje sparsować #include "x" albo #include +// Zwraca: true jeśli linia to include i udało się wyciągnąć ścieżkę. +static bool parseIncludeLine(const std::string& line, std::string& includePath, bool& isStdLib) { + includePath.clear(); + isStdLib = false; + + std::string t = ltrim(line); + if (t.rfind("#include", 0) != 0) return false; + + const size_t openQuote = t.find('"'); + const size_t closeQuote = t.rfind('"'); + const size_t openAngle = t.find('<'); + const size_t closeAngle = t.rfind('>'); + + if (openQuote != std::string::npos && closeQuote != std::string::npos && closeQuote > openQuote) { + includePath = t.substr(openQuote + 1, closeQuote - openQuote - 1); + isStdLib = false; + return true; + } + + if (openAngle != std::string::npos && closeAngle != std::string::npos && closeAngle > openAngle) { + includePath = t.substr(openAngle + 1, closeAngle - openAngle - 1); + isStdLib = true; + return true; + } + + // To jest #include ale w złym formacie (np. brak cudzysłowu / nawiasów) + return true; +} + +// Wewnętrzna funkcja z guardem na rekurencję. +static std::string preprocessSourceImpl( + const std::string& src, + const std::string& projectDir, + const std::string& compilerDir, + std::unordered_set& includeGuard +) { std::istringstream iss(src); std::string line; std::stringstream output; while (std::getline(iss, line)) { - // Szukamy: #include "..." lub #include <...> - // Używamy prostego find, żeby było szybko - std::string trimLine = line; - // Usuwamy białe znaki z początku - size_t first = trimLine.find_first_not_of(" \t"); - if (first != std::string::npos) trimLine = trimLine.substr(first); + std::string includePath; + bool isStdLib = false; - if (trimLine.rfind("#include", 0) == 0) { - // Mamy include! - size_t openQuote = trimLine.find('"'); - size_t closeQuote = trimLine.rfind('"'); - size_t openAngle = trimLine.find('<'); - size_t closeAngle = trimLine.rfind('>'); + const bool isIncludeLine = parseIncludeLine(line, includePath, isStdLib); - std::string includePath; - bool isStdLib = false; + if (!isIncludeLine) { + output << line << "\n"; + continue; + } - // Wersja: #include "plik.pcc" - if (openQuote != std::string::npos && closeQuote > openQuote) { - includePath = trimLine.substr(openQuote + 1, closeQuote - openQuote - 1); - } - // Wersja: #include - else if (openAngle != std::string::npos && closeAngle > openAngle) { - includePath = trimLine.substr(openAngle + 1, closeAngle - openAngle - 1); - isStdLib = true; - } + if (includePath.empty()) { + output << "\n// [PREPROCESSOR] Invalid include (no path): " << line << "\n"; + continue; + } - if (!includePath.empty()) { - std::string fullPath; - if (isStdLib) { - fullPath = compilerDir + "/std/" + includePath; - std::cout << "[PREPROCESSOR] Including STD lib: " << fullPath << "\n"; - } - else { - // Plik lokalny: Szukamy w folderze projektu - if (projectDir.empty()) fullPath = includePath; - else fullPath = projectDir + "/" + includePath; - std::cout << "[PREPROCESSOR] Including local file: " << fullPath << "\n"; - } - std::string content = loadFileContent(fullPath); - std::string processedContent = preprocessSource(content, projectDir, compilerDir); - - output << "\n// --- BEGIN INCLUDE: " << includePath << " ---\n"; - output << processedContent; - output << "\n// --- END INCLUDE ---\n"; - } + // Złóż fullPath + fs::path fullPath; + if (isStdLib) { + fullPath = fs::path(compilerDir) / "std" / includePath; + std::cout << "[PREPROCESSOR] Including STD lib: " << fullPath.string() << "\n"; } else { - output << line << "\n"; + if (projectDir.empty()) fullPath = fs::path(includePath); + else fullPath = fs::path(projectDir) / includePath; + std::cout << "[PREPROCESSOR] Including local file: " << fullPath.string() << "\n"; } + + // Normalizacja ścieżki (jeśli się da) + std::string guardKey; + try { + guardKey = fs::weakly_canonical(fullPath).string(); + } + catch (...) { + guardKey = fullPath.lexically_normal().string(); + } + + // Guard przeciw include-loop oraz wielokrotnemu includowaniu + if (includeGuard.find(guardKey) != includeGuard.end()) { + output << "\n// [PREPROCESSOR] Skipped include (already included): " << includePath << "\n"; + continue; + } + includeGuard.insert(guardKey); + + // Wczytaj + przetwórz rekurencyjnie + std::string content = loadFileContent(fullPath.string()); + if (content.empty()) { + output << "\n// [PREPROCESSOR] FAILED INCLUDE: " << includePath << "\n"; + continue; + } + + std::string processedContent = preprocessSourceImpl(content, projectDir, compilerDir, includeGuard); + + output << "\n// --- BEGIN INCLUDE: " << includePath << " ---\n"; + output << processedContent; + output << "\n// --- END INCLUDE ---\n"; } return output.str(); } + +std::string preprocessSource(const std::string& src, const std::string& projectDir, const std::string& compilerDir) { + std::unordered_set includeGuard; + return preprocessSourceImpl(src, projectDir, compilerDir, includeGuard); +} diff --git a/PCCcompiler/preprocessor.h b/PCCcompiler/preprocessor.h index 10d129a..11701d8 100644 --- a/PCCcompiler/preprocessor.h +++ b/PCCcompiler/preprocessor.h @@ -2,7 +2,12 @@ #define PREPROCESSOR_H #include -std::string preprocessSource(const std::string& src, const std::string& projectDir, const std::string& compilerDir); +std::string preprocessSource( + const std::string& src, + const std::string& projectDir, + const std::string& compilerDir +); + #endif