added "jalr" command
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user