From c37a1228502f13d54c4e1aae95a9e89371bf2f20 Mon Sep 17 00:00:00 2001 From: mmichlol Date: Sat, 7 Feb 2026 18:47:07 +0100 Subject: [PATCH] Loop Update --- PCCcompiler/codegen.cpp | 64 ++++++++++++- PCCcompiler/compiler_types.h | 4 +- PCCcompiler/main.cpp | 2 +- PCCcompiler/parser.cpp | 170 ++++++++++++++++++++++++++++++++--- 4 files changed, 225 insertions(+), 15 deletions(-) diff --git a/PCCcompiler/codegen.cpp b/PCCcompiler/codegen.cpp index 6198a47..fe91189 100644 --- a/PCCcompiler/codegen.cpp +++ b/PCCcompiler/codegen.cpp @@ -89,7 +89,9 @@ std::string generateAssembly(const CompilerState& state) { instr.type == OpType::SUB || instr.type == OpType::MUL || instr.type == OpType::DIV || - instr.type == OpType::MOD); + instr.type == OpType::MOD || + instr.type == OpType::LOGIC_AND || + instr.type == OpType::LOGIC_OR); if (isWriteOp && stackMap.find(instr.arg1) == stackMap.end() && instr.arg1 != "RAX") { stackMap[instr.arg1] = currentStack; @@ -182,6 +184,11 @@ std::string generateAssembly(const CompilerState& state) { } break; } + case OpType::JMP: { + // Skok bezwarunkowy (u¿ywany na koñcu pêtli while) + result += " jmp " + instr.arg1 + "\n"; + break; + } case OpType::LABEL: { result += instr.arg1 + ":\n"; break; @@ -318,6 +325,61 @@ std::string generateAssembly(const CompilerState& state) { result += " mov " + dst + ", edx\n"; // EDX to reszta z dzielenia! break; } + case OpType::LOGIC_AND: { + // a && b + // Algorytm: result = (op1 != 0) * (op2 != 0) + // Ale w ASM ³atwiej: + // cmp op1, 0 -> setne al + // cmp op2, 0 -> setne bl + // and al, bl + + std::string op1 = getVarLocation(instr.arg2, stackMap); + std::string op2 = getVarLocation(instr.arg3, stackMap); + std::string dst = getVarLocation(instr.arg1, stackMap); + + // Sprawdzamy op1 + result += " mov eax, " + op1 + "\n"; + result += " cmp eax, 0\n"; + result += " setne al\n"; // al = 1 jeœli eax != 0 + + // Sprawdzamy op2 (u¿ywamy ECX jako pomocniczy) + if (isdigit(op2[0])) result += " mov ecx, " + op2 + "\n"; + else result += " mov ecx, " + op2 + "\n"; + + result += " cmp ecx, 0\n"; + result += " setne cl\n"; // cl = 1 jeœli ecx != 0 + + // Logiczne AND na bajtach + result += " and al, cl\n"; + + // Zapisujemy wynik (rozszerzamy bajt do dword) + result += " movzx eax, al\n"; + result += " mov " + dst + ", eax\n"; + break; + } + case OpType::LOGIC_OR: { + // a || b + std::string op1 = getVarLocation(instr.arg2, stackMap); + std::string op2 = getVarLocation(instr.arg3, stackMap); + std::string dst = getVarLocation(instr.arg1, stackMap); + + result += " mov eax, " + op1 + "\n"; + result += " cmp eax, 0\n"; + result += " setne al\n"; + + if (isdigit(op2[0])) result += " mov ecx, " + op2 + "\n"; + else result += " mov ecx, " + op2 + "\n"; + + result += " cmp ecx, 0\n"; + result += " setne cl\n"; + + // Logiczne OR + result += " or al, cl\n"; + + result += " movzx eax, al\n"; + result += " mov " + dst + ", eax\n"; + break; + } } } diff --git a/PCCcompiler/compiler_types.h b/PCCcompiler/compiler_types.h index c211d0b..ed63c22 100644 --- a/PCCcompiler/compiler_types.h +++ b/PCCcompiler/compiler_types.h @@ -16,6 +16,8 @@ enum class OpType { PRINT, // print(a) JMP_FALSE, // if (false) skocz... JMP, // else / pêtla + LOGIC_AND, // && + LOGIC_OR, // || LABEL, // miejsce skoku CALL, // wywo³anie funkcji RETURN, // return x @@ -55,7 +57,7 @@ struct CompilerState { std::stack blockStack; std::map stringLiterals; - int stringCounter = 0; // Licznik do generowania nazw str_1, str_2... + int stringCounter = 0; }; #endif diff --git a/PCCcompiler/main.cpp b/PCCcompiler/main.cpp index 7e84a52..c42562a 100644 --- a/PCCcompiler/main.cpp +++ b/PCCcompiler/main.cpp @@ -19,7 +19,7 @@ std::string getExecutablePath() { int main(int argc, char* argv[]) { std::string inputFile, outputName; - std::string Version = "v0.0.5-beta"; + std::string Version = "v0.0.7-beta"; bool showHelp = false, showVersion = false, showCredits = false; // --- PARSOWANIE ARGUMENTÓW --- diff --git a/PCCcompiler/parser.cpp b/PCCcompiler/parser.cpp index 10a0e9a..d485c9b 100644 --- a/PCCcompiler/parser.cpp +++ b/PCCcompiler/parser.cpp @@ -56,18 +56,40 @@ void processSource(const std::string& src, CompilerState& state) { continue; } // --- 2. ZAMYKANIE BLOKU '}' --- + // --- 2. ZAMYKANIE BLOKU '}' --- if (line == "}") { - // Najpierw sprawdzamy, czy zamykamy IF-a (czy jest coÅ› na stosie bloków) if (!state.blockStack.empty()) { - std::string label = state.blockStack.top(); + std::string blockInfo = state.blockStack.top(); state.blockStack.pop(); - if (state.currentFunction) { - state.currentFunction->instructions.push_back({ OpType::LABEL, label, "", "" }); + + // Sprawdzamy czy to WHILE (czy zaczyna siÄ™ od "WHILE|") + // Bezpieczniejsza metoda: + bool isWhile = (blockInfo.length() > 6 && blockInfo.substr(0, 6) == "WHILE|"); + + if (isWhile) { + // To jest pÄ™tla! + 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); + + 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"; + } + else { + // To zwykÅ‚y IF + if (state.currentFunction) { + state.currentFunction->instructions.push_back({ OpType::LABEL, blockInfo, "", "" }); + } + std::cout << " [PARSER] } End IF block -> " << blockInfo << "\n"; } - std::cout << " [PARSER] } End IF block -> " << label << "\n"; } else { - // JeÅ›li stos pusty, to koniec funkcji + // Koniec funkcji state.currentFunction = nullptr; std::cout << " [PARSER] } End Function\n"; } @@ -118,18 +140,128 @@ void processSource(const std::string& src, CompilerState& state) { } // C. IF STATEMENT + // --- IF (ZAAWANSOWANY) --- else if (line.substr(0, 2) == "if") { + size_t openParen = line.find("("); + size_t closeParen = line.rfind(")"); // rfind! Å»eby Å‚apać ostatni nawias + + if (openParen != std::string::npos && closeParen > openParen) { + std::string conditionRaw = trim(line.substr(openParen + 1, closeParen - openParen - 1)); + + // Zmienna, która bÄ™dzie trzymać ostateczny wynik warunku + std::string finalConditionVar = conditionRaw; + + // Sprawdzamy czy sÄ… operatory logiczne && lub || + // (Na razie obsÅ‚użymy jeden poziom: A && B) + size_t andPos = conditionRaw.find("&&"); + size_t orPos = conditionRaw.find("||"); + + if (andPos != std::string::npos) { + // Mamy AND: "partA && partB" + std::string partA = trim(conditionRaw.substr(0, andPos)); + std::string partB = trim(conditionRaw.substr(andPos + 2)); + + // Generujemy nazwy zmiennych pomocniczych + std::string tempA = "_tmp_and_a_" + std::to_string(state.labelCounter); + std::string tempB = "_tmp_and_b_" + std::to_string(state.labelCounter); + std::string tempRes = "_tmp_and_res_" + std::to_string(state.labelCounter); + + // Część A + if (partA.find("==") != std::string::npos) { + size_t eq = partA.find("=="); + std::string l = trim(partA.substr(0, eq)); + std::string r = trim(partA.substr(eq + 2)); + f.instructions.push_back({ OpType::EQ, tempA, l, r }); + } + else { + // JeÅ›li to po prostu zmienna "a" + f.instructions.push_back({ OpType::ASSIGN, tempA, partA, "" }); + } + + // Część B + if (partB.find("==") != std::string::npos) { + size_t eq = partB.find("=="); + std::string l = trim(partB.substr(0, eq)); + std::string r = trim(partB.substr(eq + 2)); + f.instructions.push_back({ OpType::EQ, tempB, l, r }); + } + else { + f.instructions.push_back({ OpType::ASSIGN, tempB, partB, "" }); + } + + // Wykonujemy AND + f.instructions.push_back({ OpType::LOGIC_AND, tempRes, tempA, tempB }); + finalConditionVar = tempRes; + } + else if (orPos != std::string::npos) { + // To samo dla OR + std::string partA = trim(conditionRaw.substr(0, orPos)); + std::string partB = trim(conditionRaw.substr(orPos + 2)); + + std::string tempA = "_tmp_or_a_" + std::to_string(state.labelCounter); + std::string tempB = "_tmp_or_b_" + std::to_string(state.labelCounter); + std::string tempRes = "_tmp_or_res_" + std::to_string(state.labelCounter); + + // A + if (partA.find("==") != std::string::npos) { + size_t eq = partA.find("=="); + f.instructions.push_back({ OpType::EQ, tempA, trim(partA.substr(0, eq)), trim(partA.substr(eq + 2)) }); + } + else f.instructions.push_back({ OpType::ASSIGN, tempA, partA, "" }); + + // B + if (partB.find("==") != std::string::npos) { + size_t eq = partB.find("=="); + f.instructions.push_back({ OpType::EQ, tempB, trim(partB.substr(0, eq)), trim(partB.substr(eq + 2)) }); + } + else f.instructions.push_back({ OpType::ASSIGN, tempB, partB, "" }); + + f.instructions.push_back({ OpType::LOGIC_OR, tempRes, tempA, tempB }); + finalConditionVar = tempRes; + } + else if (conditionRaw.find("==") != std::string::npos) { + size_t eq = conditionRaw.find("=="); + std::string l = trim(conditionRaw.substr(0, eq)); + std::string r = trim(conditionRaw.substr(eq + 2)); + std::string tempRes = "_tmp_eq_" + std::to_string(state.labelCounter); + + f.instructions.push_back({ OpType::EQ, tempRes, l, r }); + finalConditionVar = tempRes; + } + + // --- GENEROWANIE SKOKU --- + std::string labelName = "L_" + std::to_string(state.labelCounter++); + + // Teraz JMP_FALSE dostaje zawsze już obliczonÄ… zmiennÄ… (finalConditionVar) + f.instructions.push_back({ OpType::JMP_FALSE, labelName, finalConditionVar, "" }); + state.blockStack.push(labelName); + + std::cout << " [PARSER] IF (" << finalConditionVar << ") -> Jump to " << labelName << "\n"; + } + } + + // --- PĘTLA WHILE --- + else if (line.substr(0, 5) == "while") { size_t openParen = line.find("("); size_t closeParen = line.find(")"); if (openParen != std::string::npos && closeParen > openParen) { std::string condition = trim(line.substr(openParen + 1, closeParen - openParen - 1)); - std::string labelName = "L_" + std::to_string(state.labelCounter++); - // Skok warunkowy - f.instructions.push_back({ OpType::JMP_FALSE, labelName, condition, "" }); - state.blockStack.push(labelName); + // 1. Generujemy etykiety + std::string labelStart = "L_" + std::to_string(state.labelCounter++); + std::string labelEnd = "L_" + std::to_string(state.labelCounter++); - std::cout << " [PARSER] IF (" << condition << ") -> Jump to " << labelName << "\n"; + // 2. Wstawiamy etykietÄ™ START (tu bÄ™dziemy wracać) + f.instructions.push_back({ OpType::LABEL, labelStart, "", "" }); + + // 3. Sprawdzamy warunek -> jak faÅ‚sz, skaczemy do END + f.instructions.push_back({ OpType::JMP_FALSE, labelEnd, condition, "" }); + + // 4. Wrzucamy info na stos, żeby '}' wiedziaÅ‚o co robić + // Format specjalny: "WHILE|Start|End" + state.blockStack.push("WHILE|" + labelStart + "|" + labelEnd); + + std::cout << " [PARSER] WHILE (" << condition << ") -> Loop between " << labelStart << " and " << labelEnd << "\n"; } } // D. PRZYPISANIE ZMIENNEJ (LUB DEKLARACJA) @@ -146,7 +278,7 @@ void processSource(const std::string& src, CompilerState& state) { std::string varName = leftSide; if (leftSide.rfind("int ", 0) == 0) varName = trim(leftSide.substr(4)); else if (leftSide.rfind("bool ", 0) == 0) varName = trim(leftSide.substr(5)); - else if (leftSide.rfind("string ", 0) == 0) { // NOWOŚĆ + else if (leftSide.rfind("string ", 0) == 0) { varName = trim(leftSide.substr(7)); isStringDecl = true; } @@ -198,6 +330,20 @@ void processSource(const std::string& src, CompilerState& state) { std::string b = trim(rightSide.substr(opPos + 1)); f.instructions.push_back({ OpType::MOD, varName, a, b }); } + // LOGICZNE AND: a && b + else if (rightSide.find("&&") != std::string::npos) { + size_t opPos = rightSide.find("&&"); + std::string a = trim(rightSide.substr(0, opPos)); + std::string b = trim(rightSide.substr(opPos + 2)); // +2 bo && ma 2 znaki + f.instructions.push_back({ OpType::LOGIC_AND, varName, a, b }); + } + // LOGICZNE OR: a || b + else if (rightSide.find("||") != std::string::npos) { + size_t opPos = rightSide.find("||"); + std::string a = trim(rightSide.substr(0, opPos)); + std::string b = trim(rightSide.substr(opPos + 2)); + f.instructions.push_back({ OpType::LOGIC_OR, varName, a, b }); + } // 3. Czy to porównanie? a == b (Ważne: == może być w IFie, ale tu jesteÅ›my w linii z '=') // UWAGA: To rzadkie w C++ (bool x = a == b), ale obsÅ‚użmy proste przypisanie wartoÅ›ci logicznej else if (rightSide.find("==") != std::string::npos) {