diff --git a/src/Manager.cpp b/src/Manager.cpp index 73df8ad..aa69f85 100644 --- a/src/Manager.cpp +++ b/src/Manager.cpp @@ -24,13 +24,14 @@ int Manager::run() { if (!m_programFile.is_open()) { std::cerr << "Bitte zuerst die init() Methode aufrufen!" << "\n" << std::flush; } - std::string line; 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); + std::string line; while (std::getline(m_programFile, line)) { auto lineVector = ProgramLoader::parseLine(line); + if (lineVector.empty()) continue; Alu::calculate(lineVector); } return 0; @@ -64,10 +65,15 @@ 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 - std::string line; - std::getline(m_programFile, line); + 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; + getline(m_programFile, line); + return line; +} diff --git a/src/Manager.h b/src/Manager.h index 690325e..140706b 100644 --- a/src/Manager.h +++ b/src/Manager.h @@ -74,6 +74,11 @@ public: * @return Die stream offset Position ("Zeilennummer") des nächsten Befehls */ std::streampos getNextStreamLineOffset(); + + /** + * Bewegt das offset (Zeilennummer/"program counter") um 1 Zeile nach vorne + */ + std::string gotoNextStreamLine(); }; diff --git a/src/ProgramLoader.cpp b/src/ProgramLoader.cpp index 4951746..f01e1e9 100644 --- a/src/ProgramLoader.cpp +++ b/src/ProgramLoader.cpp @@ -11,6 +11,7 @@ ProgramLoader *ProgramLoader::getInstance() { } [[nodiscard]] std::vector ProgramLoader::parseLine(const std::string &input) { + if (input.empty()) return std::vector{}; std::vector output{}; /// Konvertiere den Input String in einen IStringStream, damit dieser bei Leerzeichen gesplittet werden kann std::istringstream iss(input); @@ -40,6 +41,7 @@ void ProgramLoader::indexFile(std::ifstream &m_programFile) { /// Parse Zeile für Zeile while (std::getline(m_programFile, line)) { auto lineVector = parseLine(line); + if (lineVector.empty()) continue; /// Sobald ein Label gefunden wurde, speichere die Position des Streams if (const auto first = lineVector.begin(); first->at(first->length() - 1) == ':') { m_labels[first->substr(0, first->length() - 1)] = m_programFile.tellg(); diff --git a/src/components/Alu.cpp b/src/components/Alu.cpp index f9cb21c..6e60b90 100644 --- a/src/components/Alu.cpp +++ b/src/components/Alu.cpp @@ -27,11 +27,15 @@ void Alu::calculate(const std::vector &commandVector) { int arg2 = 0; if (commandVector.at(2).find('(') != std::string::npos) { arg2 = parseAddress(commandVector.at(2)); + } else { + arg2 = parseArgument(commandVector.at(2)); } - /// Wandle Vektor[3] (das dritte Argument) nur um, falls dieser existiert + /// Wandle Vektor[3] (das dritte Argument) nur um, falls dieser existiert und kein immediate Wert ist int arg3 = 0; - if (commandVector.size() > 3 && isdigit(commandVector.at(3).at(1))) { - arg3 = parseArgument(commandVector.at(3)); + if (commandVector.size() > 3) { + if (const std::string &arg = commandVector.at(3); isRegister(arg) || isImmediate(arg)) { + arg3 = parseArgument(arg); + } } if (command == "add") { @@ -138,14 +142,24 @@ void Alu::calculate(const std::vector &commandVector) { Register::getInstance().setRegister(arg1, pos); Manager::getInstance()->setStreamPosition(streamPos); } else if (command == "jalr") { + /// Jump and link register Befehl + /// !!! Aufgrund des casts des stream offsets zu int funktioniert das nicht bei großen Quellcode Dateien + /// und führt zu undefiniertem Verhalten !!! + const auto pos = static_cast(Manager::getInstance()->getNextStreamLineOffset().operator std::streamoff()); + const auto &label = commandVector.at(3); + const auto streamPosLabel = ProgramLoader::getInstance()->getStreamPosition(label); + const auto posOffset = Register::getInstance().getRegister(arg2); + Register::getInstance().setRegister(arg1, pos); + Manager::getInstance()->setStreamPosition(streamPosLabel); + for (int i = 0; i < posOffset; ++i) { + Manager::getInstance()->gotoNextStreamLine(); + } } } int Alu::parseArgument(std::string argument) { /// Falls das erste Argument ein Register ist, entferne das führende "x" - if (argument.at(0) == 'x') { - argument = argument.substr(1, argument.length() - 1); - } + if (argument.at(0) == 'x') argument = argument.substr(1); /// Da das Argument noch als String vorliegt, muss es in ein int umgewandelt werden return std::stoi(argument); } @@ -162,3 +176,28 @@ int Alu::parseAddress(const std::string &argument) { } return 0; } + +bool Alu::isRegister(const std::string &argument) { + /// Überprüfe, ob das nichtleere Argument mit 'x' startet + if (argument.empty() || argument.at(0) != 'x') return false; + /// Entfernt das voranstehende 'x' und checkt, ob darauf etwas folgt + const std::string numberPart = argument.substr(1); + if (numberPart.empty()) return false; + /// Überprüfe, ob alle Zeichen im restlichen Argument Nummern sind + for (const char c: numberPart) { + if (!std::isdigit(c)) return false; + } + /// Konvertiere zu int und überprüfe, ob es ein Register zwischen inklusive x0 und x32 ist + const int regNum = std::stoi(numberPart); + return regNum >= 0 && regNum <= 32; +} + +bool Alu::isImmediate(const std::string &argument) { + if (argument.empty()) return false; + constexpr size_t start = 0; + /// Überprüfe, ob jedes Zeichen im Argument eine Nummer ista + for (size_t i = start; i < argument.size(); ++i) { + if (!std::isdigit(argument.at(i))) return false; + } + return true; +} diff --git a/src/components/Alu.h b/src/components/Alu.h index f9cc929..ddf28d5 100644 --- a/src/components/Alu.h +++ b/src/components/Alu.h @@ -35,6 +35,22 @@ public: * @return Die Adresse des Befehlsargument als int */ static int parseAddress(const std::string &argument); + + /** + * Überprüft, ob es sich bei dem angegebenen Befehlsargument um ein Register handelt + * + * @param argument Das Befehlsargument, welches überprüft werden soll + * @return Ob das Befehlsargument ein Register ist + */ + static bool isRegister(const std::string &argument); + + /** + * Überprüft, ob es sich bei dem angegebenen Befehlsargument um ein immediate Wert handelt + * + * @param argument Das Befehlsargument, welches überprüft werden soll + * @return Ob das Befehlsargument ein immediate Wert ist + */ + static bool isImmediate(const std::string &argument); }; diff --git a/src/components/Register.h b/src/components/Register.h index 44e2a24..bbbf88f 100644 --- a/src/components/Register.h +++ b/src/components/Register.h @@ -5,7 +5,6 @@ #ifndef REGISTER_H #define REGISTER_H #include -#include /// Eine Registerklasse als Singleton implementiert. /// Als Speicher (Registers) wird ein int Array genutzt.