// // Created by black on 12.06.25. // #include "Manager.h" #include #include #include "components/Alu.h" #include "components/Memory.h" #include "components/Register.h" namespace fs = std::filesystem; Manager::~Manager() { std::cout << "Schließe Quellcode Datei: '" << m_path << "'" << "\n" << std::flush; m_programFile.close(); } Manager &Manager::getInstance() { static Manager instance; return instance; } [[noreturn]] void Manager::run() { if (!m_programFile.is_open()) { std::cerr << "Bitte zuerst die init() Methode aufrufen!" << "\n" << std::flush; return; } ProgramLoader::getInstance().indexFile(m_programFile); // Die Position des Streams (virtueller Lesekopf) muss nach dem Indexen wieder zurückgesetzt werden m_programFile.clear(); m_programFile.seekg(0); bool runAll = false; // Bearbeite jede Zeile des Quellcodes in der ALU std::string line; while (std::getline(m_programFile, line)) { auto lineVector = ProgramLoader::parseLine(line); // Sollte die aktuelle Zeile leer sein, überspringe die ALU if (lineVector.empty()) continue; Alu::calculate(lineVector); // Frage nach und reagiere auf Nutzereingaben if (!runAll) { std::cout << "\n" << "Bearbeitete Codezeile: \033[34m" << line << "\033[0m"; runAll = handleUserInput(); } } // Beende das Program erst, wenn der Nutzer das tut std::cout << "\nDer Quellcode ist nun \033[33mfertig\033[0m bearbeitet. Sie können noch auf den RAM und die Register zugreifen."; while (true) handleExitInput(); } void Manager::setStreamPosition(const std::streampos pos) { m_programFile.seekg(pos); } std::streampos Manager::getStreamPosition() { return m_programFile.tellg(); } void Manager::init(const std::string &program_path) { m_path = program_path; std::cout << "Öffne Quellcode Datei: '" << m_path << "'" << "\n" << std::flush; //Überprüfe, ob die Datei existiert if (!fs::exists(m_path)) { std::cerr << "Datei existiert nicht: " << m_path << "\n" << std::flush; return; } m_programFile.open(m_path); // Sollte die Datei nicht geöffnet worden sein, gib den Fehler aus if (!m_programFile.is_open()) { std::cerr << "Datei konnte nicht geöffnet werden: " << m_path << "\n" << std::flush; std::cerr << "fail (z.B. Zugriffsrechte): " << m_programFile.fail() << "\n" << std::flush; std::cerr << "bad (schwerwiegender Fehler): " << m_programFile.bad() << "\n" << std::flush; return; } constexpr auto COLOR_GREEN = "\033[32m"; constexpr auto COLOR_YELLOW = "\033[33m"; constexpr auto COLOR_BLUE = "\033[34m"; constexpr auto COLOR_RESET = "\033[0m"; std::cout << COLOR_GREEN << "=== Herzlich willkommen beim RISC-V Emulator! ===" << COLOR_RESET << "\n"; std::cout << "Nachfolgend wird nun die angegebene Quellcodedatei eingelesen und von der ALU bearbeitet.\n" << COLOR_YELLOW << "Nach" << COLOR_RESET << " jeder bearbeiteten Codezeile wird " << COLOR_BLUE << "diese" << COLOR_RESET << " ausgegeben und Sie werden " << "nach dem " << COLOR_GREEN << "nächsten Schritt" << COLOR_RESET << " gefragt. Tätigen Sie Ihre Eingabe und bestätigen Sie mit " << COLOR_GREEN << "ENTER" << COLOR_RESET << ".\nAnforderungen und Hinweise entnehmen Sie bitte der README.\n\n"; } std::streampos Manager::getNextStreamLineOffset() { // Speichert das aktuelle stream offset const auto positionBefore = m_programFile.tellg(); // Geht eine Zeile nach vorne zum nächsten Befehl (PC+4) und speichert den offset gotoNextStreamLine(); const auto positionAfter = m_programFile.tellg(); // Geht zum offset vom Anfang zurück und gibt die nächste Adresse (PC+4) zurück m_programFile.seekg(positionBefore); return positionAfter; } std::string Manager::gotoNextStreamLine() { std::string line; do { getline(m_programFile, line); } while (line.empty()); return line; } bool Manager::handleUserInput() { constexpr auto COLOR_GREEN = "\033[32m"; constexpr auto COLOR_RESET = "\033[0m"; std::cout << "\nOptionen: (" << COLOR_GREEN << "s" << COLOR_RESET << ") Programm durchlaufen lassen, (" << COLOR_GREEN << "l" << COLOR_RESET << ") nächste Zeile, (" << COLOR_GREEN << "e" << COLOR_RESET << ") beenden, (" << COLOR_GREEN << "m" << COLOR_RESET << ") Memory Dump, (" << COLOR_GREEN << "r" << COLOR_RESET << ") Register Dump\n"; char input = '\0'; while (true) { std::cout << "Eingabe: "; std::cin >> input; // ignoriere die Groß- und Kleinschreibung input = std::tolower(input); if (input == 's') { return true; } else if (input == 'l') { return false; } else if (input == 'e') { std::cout << "Programm wird beendet.\n"; exit(0); } else if (input == 'm') { std::cout << "Wie viele Speicherzellen sollen gedumpt werden? "; int dumpSize = 0; while (!(std::cin >> dumpSize) || dumpSize == 0) { std::cout << "Ungültige Eingabe. Bitte eine positive Zahl eingeben: "; std::cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); } Memory::getInstance().dump(dumpSize); } else if (input == 'r') { Register::getInstance().dump(); } else { std::cout << "Ungültige Eingabe. Bitte erneut versuchen.\n"; } } } void Manager::handleExitInput() { constexpr auto COLOR_GREEN = "\033[32m"; constexpr auto COLOR_RESET = "\033[0m"; std::cout << "\nOptionen: (" << COLOR_GREEN << "e" << COLOR_RESET << ") beenden, (" << COLOR_GREEN << "m" << COLOR_RESET << ") Memory Dump, (" << COLOR_GREEN << "r" << COLOR_RESET << ") Register Dump\n"; char input = '\0'; while (true) { std::cout << "Eingabe: "; std::cin >> input; input = std::tolower(input); if (input == 'e') { std::cout << "Programm wird beendet. :pepeExit:\n"; exit(0); // oder andere Beendigung } else if (input == 'm') { std::cout << "Wie viele Speicherzellen sollen gedumpt werden? "; int dumpSize = 0; while (!(std::cin >> dumpSize) || dumpSize == 0) { std::cout << "Ungültige Eingabe. Bitte eine positive Zahl eingeben: "; std::cin.clear(); std::cin.ignore(std::numeric_limits::max(), '\n'); } Memory::getInstance().dump(dumpSize); } else if (input == 'r') { Register::getInstance().dump(); } else { std::cout << "Ungültige Eingabe. Bitte erneut versuchen.\n"; } } }