ELSE update
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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<std::string> 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,41 +89,78 @@ 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();
|
||||
|
||||
// --- WHILE ---
|
||||
if (blockInfo.rfind("WHILE|", 0) == 0) {
|
||||
state.blockStack.pop();
|
||||
|
||||
bool isWhile = (blockInfo.length() > 6 && blockInfo.substr(0, 6) == "WHILE|");
|
||||
|
||||
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 (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::LABEL, blockInfo, "", "" });
|
||||
}
|
||||
std::cout << " [PARSER] } End block -> " << blockInfo << "\n";
|
||||
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);
|
||||
}
|
||||
else {
|
||||
// Koniec funkcji
|
||||
state.currentFunction = nullptr;
|
||||
std::cout << " [PARSER] } End Function\n";
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,18 @@
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
#include <unordered_set>
|
||||
|
||||
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<char>(in)), std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
std::string preprocessSource(const std::string& src, const std::string& projectDir, const std::string& compilerDir) {
|
||||
// Próbuje sparsowaæ #include "x" albo #include <x>
|
||||
// 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<std::string>& 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);
|
||||
|
||||
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('>');
|
||||
|
||||
std::string includePath;
|
||||
bool isStdLib = false;
|
||||
|
||||
// Wersja: #include "plik.pcc"
|
||||
if (openQuote != std::string::npos && closeQuote > openQuote) {
|
||||
includePath = trimLine.substr(openQuote + 1, closeQuote - openQuote - 1);
|
||||
}
|
||||
// Wersja: #include <plik.pcc>
|
||||
else if (openAngle != std::string::npos && closeAngle > openAngle) {
|
||||
includePath = trimLine.substr(openAngle + 1, closeAngle - openAngle - 1);
|
||||
isStdLib = true;
|
||||
const bool isIncludeLine = parseIncludeLine(line, includePath, isStdLib);
|
||||
|
||||
if (!isIncludeLine) {
|
||||
output << line << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!includePath.empty()) {
|
||||
std::string fullPath;
|
||||
if (includePath.empty()) {
|
||||
output << "\n// [PREPROCESSOR] Invalid include (no path): " << line << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Z³ó¿ fullPath
|
||||
fs::path fullPath;
|
||||
if (isStdLib) {
|
||||
fullPath = compilerDir + "/std/" + includePath;
|
||||
std::cout << "[PREPROCESSOR] Including STD lib: " << fullPath << "\n";
|
||||
fullPath = fs::path(compilerDir) / "std" / includePath;
|
||||
std::cout << "[PREPROCESSOR] Including STD lib: " << fullPath.string() << "\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";
|
||||
if (projectDir.empty()) fullPath = fs::path(includePath);
|
||||
else fullPath = fs::path(projectDir) / includePath;
|
||||
std::cout << "[PREPROCESSOR] Including local file: " << fullPath.string() << "\n";
|
||||
}
|
||||
std::string content = loadFileContent(fullPath);
|
||||
std::string processedContent = preprocessSource(content, projectDir, compilerDir);
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
else {
|
||||
output << line << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::string preprocessSource(const std::string& src, const std::string& projectDir, const std::string& compilerDir) {
|
||||
std::unordered_set<std::string> includeGuard;
|
||||
return preprocessSourceImpl(src, projectDir, compilerDir, includeGuard);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
#define PREPROCESSOR_H
|
||||
|
||||
#include <string>
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user