added "jalr" command

This commit is contained in:
black
2025-07-08 20:31:11 +02:00
parent 4fdaf3dafa
commit bc77fae7ee
6 changed files with 77 additions and 10 deletions

View File

@@ -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;
}

View File

@@ -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();
};

View File

@@ -11,6 +11,7 @@ ProgramLoader *ProgramLoader::getInstance() {
}
[[nodiscard]] std::vector<std::string> ProgramLoader::parseLine(const std::string &input) {
if (input.empty()) return std::vector<std::string>{};
std::vector<std::string> 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();

View File

@@ -27,11 +27,15 @@ void Alu::calculate(const std::vector<std::string> &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<std::string> &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<int>(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;
}

View File

@@ -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);
};

View File

@@ -5,7 +5,6 @@
#ifndef REGISTER_H
#define REGISTER_H
#include <array>
#include <cstdint>
/// Eine Registerklasse als Singleton implementiert.
/// Als Speicher (Registers) wird ein int Array genutzt.