Files
PCCCompiler/PCCcompiler/parser.cpp
mmichlol 0dff8628ac Bug Fix
2026-02-09 20:00:25 +01:00

411 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "parser.h"
#include "utils.h"
#include <iostream>
#include <sstream>
#include <vector>
std::vector<std::string> parseArgs(const std::string& line) {
std::vector<std::string> args;
size_t open = line.find('(');
size_t close = line.find(')');
if (open == std::string::npos || close == std::string::npos) return args;
std::string inside = line.substr(open + 1, close - open - 1);
if (inside.empty()) return args;
std::stringstream ss(inside);
std::string segment;
while (std::getline(ss, segment, ',')) {
segment = trim(segment);
// segment to np. "int a". Szukamy ostatniej spacji, by wziąć nazwę "a"
size_t space = segment.find_last_of(" \t");
if (space != std::string::npos) {
args.push_back(trim(segment.substr(space + 1)));
}
}
return args;
}
// Funkcja wyciągająca "tekst" i rejestrująca go w state
// Rejestruje tekst i zwraca jego etykietę (np. str_5)
std::string registerStringLiteral(CompilerState& state, std::string content) {
// Używamy stringCounter z CompilerState
std::string label = "str_" + std::to_string(state.stringCounter++);
// Dodajemy do WEKTORA (push_back działa tylko na wektorze/liście)
state.stringLiterals.push_back({ label, content });
return label;
}
void processSource(const std::string& src, CompilerState& state) {
std::istringstream iss(src);
std::string line;
while (std::getline(iss, line)) {
line = trim(line);
if (line.empty() || line.substr(0, 2) == "//" || line[0] == '#') continue;
// =========================================================
// 1. DEFINICJA FUNKCJI (np. void main() { )
// =========================================================
bool startsWithType = (line.rfind("int ", 0) == 0 || line.rfind("void ", 0) == 0 || line.rfind("bool ", 0) == 0);
if (startsWithType && line.find("(") != std::string::npos && line.find("{") != std::string::npos && line.find("=") == std::string::npos) {
size_t openParen = line.find('(');
std::string typeRaw = line.substr(0, line.find(' '));
std::string nameRaw = line.substr(typeRaw.length(), openParen - typeRaw.length());
std::string funcName = trim(nameRaw);
Function newFunc;
newFunc.name = funcName;
newFunc.returnType = typeRaw;
newFunc.args = parseArgs(line);
state.functions[funcName] = newFunc;
state.currentFunction = &state.functions[funcName];
std::cout << "[PARSER] New Function: " << funcName << "\n";
continue;
}
// =========================================================
// 2. ZAMYKANIE BLOKU '}' (Koniec funkcji, IFa lub WHILEa)
// =========================================================
if (!line.empty() && line.back() == '}') {
if (!state.blockStack.empty()) {
std::string blockInfo = state.blockStack.top();
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);
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 blok (if lub else)
if (state.currentFunction) {
state.currentFunction->instructions.push_back({ OpType::LABEL, blockInfo, "", "" });
}
std::cout << " [PARSER] } End block -> " << blockInfo << "\n";
}
}
else {
// Koniec funkcji
state.currentFunction = nullptr;
std::cout << " [PARSER] } End Function\n";
}
continue;
}
// =========================================================
// JESTEŚMY W ŚRODKU FUNKCJI
// =========================================================
if (state.currentFunction) {
Function& f = *state.currentFunction;
// A. RETURN
if (line.substr(0, 6) == "return") {
std::string val = trim(line.substr(6));
if (!val.empty() && val.back() == ';') val.pop_back();
f.instructions.push_back({ OpType::RETURN, val, "", "" });
continue;
}
// B. DEKLARACJA STRINGA: string s = "hello";
else if (line.substr(0, 6) == "string") {
size_t eqPos = line.find("=");
if (eqPos != std::string::npos) {
std::string name = trim(line.substr(7, eqPos - 7));
size_t quoteStart = line.find("\"", eqPos);
size_t quoteEnd = line.rfind("\"");
if (quoteStart != std::string::npos && quoteEnd > quoteStart) {
std::string content = line.substr(quoteStart + 1, quoteEnd - quoteStart - 1);
std::string label = registerStringLiteral(state, content);
state.varTypes[name] = "string";
f.instructions.push_back({ OpType::ASSIGN, name, label, "" });
}
}
continue;
}
// C. DEKLARACJA TABLICY: int t[10];
else if (line.substr(0, 3) == "int" && line.find("[") != std::string::npos && line.find("=") == std::string::npos) {
size_t openBracket = line.find("[");
size_t closeBracket = line.find("]");
if (openBracket != std::string::npos && closeBracket > openBracket) {
std::string name = trim(line.substr(3, openBracket - 3));
std::string sizeStr = trim(line.substr(openBracket + 1, closeBracket - openBracket - 1));
state.varTypes[name] = "array";
f.instructions.push_back({ OpType::ARRAY_DECLARE, name, sizeStr, "" });
std::cout << " [PARSER] Array Decl: " << name << "[" << sizeStr << "]\n";
}
continue;
}
// D. DRUKOWANIE (PRINT)
else if (line.substr(0, 5) == "print") {
size_t open = line.find("(");
size_t close = line.rfind(")");
if (open != std::string::npos && close > open) {
std::string content = trim(line.substr(open + 1, close - open - 1));
// Czy to element tablicy? print(t[0])
if (content.find("[") != std::string::npos && content.back() == ']') {
size_t opIdx = content.find("[");
std::string arrName = content.substr(0, opIdx);
std::string arrIdx = content.substr(opIdx + 1, content.length() - opIdx - 2);
// Hack: Używamy tymczasowej zmiennej do wydruku
std::string tmp = "_p_tmp_" + std::to_string(state.labelCounter++);
f.instructions.push_back({ OpType::ASSIGN, tmp, arrName, "ARRAY_IDX:" + arrIdx });
f.instructions.push_back({ OpType::PRINT, tmp, "", "" });
}
// Literał tekstowy
else if (content.front() == '"' && content.back() == '"') {
std::string text = content.substr(1, content.length() - 2);
std::string label = registerStringLiteral(state, text);
f.instructions.push_back({ OpType::PRINT_STRING, label, "", "" });
}
// Zmienna string
else if (state.varTypes.count(content) && state.varTypes[content] == "string") {
f.instructions.push_back({ OpType::PRINT_STRING, content, "", "" });
}
// Liczba
else {
f.instructions.push_back({ OpType::PRINT, content, "", "" });
}
}
continue;
}
// E. IF STATEMENT (z ulepszoną obsługą else)
else if (line.substr(0, 2) == "if") {
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);
}
continue;
}
// F. WHILE LOOP
else if (line.substr(0, 5) == "while") {
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));
// 1. Generujemy etykiety
std::string labelStart = "L_" + std::to_string(state.labelCounter++);
std::string labelEnd = "L_" + std::to_string(state.labelCounter++);
// 2. Wstawiamy etykietę START (tu będziemy wracać)
f.instructions.push_back({ OpType::LABEL, labelStart, "", "" });
// 3. OBLICZANIE WARUNKU (Tu był błąd - brakowało tego!)
// Jeśli warunek to np. "j - 3", musimy to policzyć do zmiennej tymczasowej
std::string finalCondVar = conditionRaw;
// Prosta obsługa odejmowania w warunku (np. while (i - 10))
if (conditionRaw.find("-") != std::string::npos) {
size_t opPos = conditionRaw.find("-");
std::string a = trim(conditionRaw.substr(0, opPos));
std::string b = trim(conditionRaw.substr(opPos + 1));
std::string tmp = "_while_tmp_" + std::to_string(state.labelCounter);
f.instructions.push_back({ OpType::SUB, tmp, a, b });
finalCondVar = tmp;
}
// Prosta obsługa "==" (np. while (i == 10))
else if (conditionRaw.find("==") != std::string::npos) {
size_t opPos = conditionRaw.find("==");
std::string a = trim(conditionRaw.substr(0, opPos));
std::string b = trim(conditionRaw.substr(opPos + 2));
std::string tmp = "_while_tmp_" + std::to_string(state.labelCounter);
f.instructions.push_back({ OpType::EQ, tmp, a, b });
finalCondVar = tmp;
}
// 4. Skaczemy do END jeśli warunek (obliczona zmienna) jest fałszywy
f.instructions.push_back({ OpType::JMP_FALSE, labelEnd, finalCondVar, "" });
// 5. Wrzucamy info na stos
state.blockStack.push("WHILE|" + labelStart + "|" + labelEnd);
}
continue;
}
// G. MSGBOX
else if (line.substr(0, 6) == "msgbox") {
// ... (Twoja logika msgbox, jest OK) ...
size_t open = line.find("(");
size_t close = line.rfind(")");
if (open != std::string::npos && close > open) {
std::string args = line.substr(open + 1, close - open - 1);
size_t comma = args.find(",");
if (comma != std::string::npos) {
std::string arg1 = trim(args.substr(0, comma));
std::string arg2 = trim(args.substr(comma + 1));
std::string l1 = (arg1.front() == '"') ? registerStringLiteral(state, arg1.substr(1, arg1.size() - 2)) : arg1;
std::string l2 = (arg2.front() == '"') ? registerStringLiteral(state, arg2.substr(1, arg2.size() - 2)) : arg2;
f.instructions.push_back({ OpType::MSGBOX, l1, l2, "" });
}
}
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 `ifelse`:
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";
}
continue;
}
// =========================================================
// H. PRZYPISANIE / OPERACJE (Linie z "=")
// =========================================================
else if (line.find("=") != std::string::npos) {
size_t eqPos = line.find('=');
std::string leftSide = trim(line.substr(0, eqPos));
std::string rightSide = trim(line.substr(eqPos + 1));
if (!rightSide.empty() && rightSide.back() == ';') rightSide.pop_back();
// 1. CZY TO ZAPIS DO TABLICY? t[0] = 5
if (leftSide.find("[") != std::string::npos) {
size_t open = leftSide.find("[");
size_t close = leftSide.find("]");
std::string arrName = trim(leftSide.substr(0, open));
std::string index = trim(leftSide.substr(open + 1, close - open - 1));
f.instructions.push_back({ OpType::ARRAY_SET, arrName, index, rightSide });
continue;
}
// Pobieramy nazwę zmiennej (usuwamy "int ", "bool ")
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) varName = trim(leftSide.substr(7));
// 2. CZY TO ODCZYT Z TABLICY? x = t[0]
if (rightSide.find("[") != std::string::npos && rightSide.back() == ']') {
size_t open = rightSide.find("[");
size_t close = rightSide.find("]");
std::string arrName = trim(rightSide.substr(0, open));
std::string index = trim(rightSide.substr(open + 1, close - open - 1));
// Specjalna flaga w arg3: ARRAY_IDX:indeks
f.instructions.push_back({ OpType::ASSIGN, varName, arrName, "ARRAY_IDX:" + index });
}
// 3. Wywołanie funkcji: x = func()
else if (rightSide.find("(") != std::string::npos && rightSide.find(")") != std::string::npos) {
size_t open = rightSide.find('(');
std::string funcName = trim(rightSide.substr(0, open));
std::string argsContent = rightSide.substr(open + 1, rightSide.find(')') - open - 1);
f.instructions.push_back({ OpType::CALL, funcName, argsContent, "" });
f.instructions.push_back({ OpType::ASSIGN, varName, "RAX", "" });
}
// 4. Operacje arytmetyczne
else if (rightSide.find("+") != std::string::npos) {
size_t opPos = rightSide.find("+");
f.instructions.push_back({ OpType::ADD, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 1)) });
}
else if (rightSide.find("-") != std::string::npos) {
size_t opPos = rightSide.find("-");
f.instructions.push_back({ OpType::SUB, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 1)) });
}
else if (rightSide.find("*") != std::string::npos) {
size_t opPos = rightSide.find("*");
f.instructions.push_back({ OpType::MUL, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 1)) });
}
else if (rightSide.find("/") != std::string::npos) {
size_t opPos = rightSide.find("/");
f.instructions.push_back({ OpType::DIV, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 1)) });
}
else if (rightSide.find("%") != std::string::npos) {
size_t opPos = rightSide.find("%");
f.instructions.push_back({ OpType::MOD, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 1)) });
}
// 5. Logika
else if (rightSide.find("&&") != std::string::npos) {
size_t opPos = rightSide.find("&&");
f.instructions.push_back({ OpType::LOGIC_AND, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 2)) });
}
else if (rightSide.find("||") != std::string::npos) {
size_t opPos = rightSide.find("||");
f.instructions.push_back({ OpType::LOGIC_OR, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 2)) });
}
else if (rightSide.find("==") != std::string::npos) {
size_t opPos = rightSide.find("==");
f.instructions.push_back({ OpType::EQ, varName, trim(rightSide.substr(0, opPos)), trim(rightSide.substr(opPos + 2)) });
}
// 6. Zwykłe przypisanie stringa
else if (rightSide.size() >= 2 && rightSide.front() == '"') {
std::string content = rightSide.substr(1, rightSide.size() - 2);
std::string label = registerStringLiteral(state, content);
state.varTypes[varName] = "string";
f.instructions.push_back({ OpType::ASSIGN, varName, label, "" });
}
// 7. Zwykłe przypisanie wartości
else {
f.instructions.push_back({ OpType::ASSIGN, varName, rightSide, "" });
}
continue;
}
// I. SAMODZIELNE WYWOŁANIE FUNKCJI (np. input(); )
else if (line.find("(") != std::string::npos && line.find(")") != std::string::npos) {
size_t open = line.find('(');
std::string funcName = trim(line.substr(0, open));
std::string argsContent = line.substr(open + 1, line.find(')') - open - 1);
f.instructions.push_back({ OpType::CALL, funcName, argsContent, "" });
std::cout << " [PARSER] Call void: " << funcName << "\n";
}
}
}
}
void calculateExpressions(CompilerState& state) {}