diff --git a/src/cmd/environment.cpp b/src/cmd/environment.cpp index 4d0e304..7ee502d 100644 --- a/src/cmd/environment.cpp +++ b/src/cmd/environment.cpp @@ -4,6 +4,8 @@ #include #include +#include "core/context.hpp" +#include "core/platform.hpp" #include "error.hpp" #include "object.hpp" #include "token.hpp" @@ -22,6 +24,8 @@ void Environment::define(const std::string& name, Object value) { } Object Environment::get(const Token& name) { + if (name.m_lexeme[0] == '$') return Environment::getRegister(name); + if (m_values.contains(name.m_lexeme)) return m_values[name.m_lexeme]; CmdError::error(name.m_type, std::format("Undefined variable '{}'.", name.m_lexeme), @@ -55,3 +59,20 @@ Environment& Environment::getInstance() { } std::map Environment::getAll() { return m_values; } + +Object Environment::getRegister(const Token& reg) { + auto& target = Context::getTarget(); + + std::string regName = reg.m_lexeme; + regName.erase(0, 1); + + auto regEntry = findRegEntry(regName); + if (!regEntry) { + CmdError::error(reg.m_type, "$ prefix can only be used to access registers", + CmdErrorType::RUNTIME_ERROR); + return std::monostate{}; + } + + return static_cast( + readRegValue(target->getLastKnownThreadState(), *regEntry.value())); +} diff --git a/src/cmd/environment.hpp b/src/cmd/environment.hpp index e9064d2..150a0c2 100644 --- a/src/cmd/environment.hpp +++ b/src/cmd/environment.hpp @@ -12,6 +12,9 @@ class Environment { private: std::map m_values; + + static Object getRegister(const Token& reg); + Environment() : m_values({}) { this->define("print", std::make_shared(PrintFn())); this->define("len", std::make_shared(LenFn())); diff --git a/src/cmd/interpreter.cpp b/src/cmd/interpreter.cpp index f5313b7..385282b 100644 --- a/src/cmd/interpreter.cpp +++ b/src/cmd/interpreter.cpp @@ -123,7 +123,8 @@ Object Interpreter::visitCallStmnt(const CallStmnt& stmnt) { for (const auto& x : stmnt.m_args) { if (auto* id = dynamic_cast(x.get()); - id != nullptr && !(m_env.getAll().contains(id->m_name.m_lexeme))) { + id != nullptr && !(m_env.getAll().contains(id->m_name.m_lexeme)) && + id->m_name.m_lexeme[0] != '$') { argList.emplace_back(id->m_name.m_lexeme); continue; } diff --git a/src/cmd/scanner.cpp b/src/cmd/scanner.cpp index c03beed..27ea380 100644 --- a/src/cmd/scanner.cpp +++ b/src/cmd/scanner.cpp @@ -4,6 +4,7 @@ #include #include +#include "cmd/token_type.hpp" #include "error.hpp" #include "token.hpp" #include "util.hpp" @@ -25,6 +26,9 @@ bool Scanner::isAtEnd() const { return m_current >= m_source.length(); } void Scanner::scanToken() { const char c = advance(); switch (c) { + case '$': + identifier(); + break; case '(': addToken(TokenType::LEFT_PAREN); break; diff --git a/src/cmd/scanner.hpp b/src/cmd/scanner.hpp index e91b653..8be2c0c 100644 --- a/src/cmd/scanner.hpp +++ b/src/cmd/scanner.hpp @@ -35,6 +35,7 @@ class Scanner { void number(); [[nodiscard]] char peekNext() const; void identifier(); + void registerVariable(); public: explicit Scanner(std::string source) noexcept; diff --git a/src/cmd/stdlib.hpp b/src/cmd/stdlib.hpp index 137d637..2ef097f 100644 --- a/src/cmd/stdlib.hpp +++ b/src/cmd/stdlib.hpp @@ -45,7 +45,28 @@ class PrintFn : public Callable { return ""; } - Object call(std::vector args) override { return args[0]; } + Object call(std::vector args) override { + enum class FmtOpt : u8 { DEC, HEX }; + + FmtOpt fmt = FmtOpt::DEC; + + for (const auto& arg : args) { + if (const auto* str = std::get_if(&arg)) { + if (*str == "hex") { + fmt = FmtOpt::HEX; + } + } + } + + switch (fmt) { + case FmtOpt::DEC: + return args[0]; + case FmtOpt::HEX: + auto val = detail::asU64(args[1]); + if (!val) return val.error(); + return detail::toHex(*val); + } + } }; class BreakpointFn : public SubcommandCallable { @@ -282,7 +303,7 @@ class RegisterFn : public SubcommandCallable { if (target->writeRegValue(*entry.value(), *val) != 0) return "Error writing to register!"; - return std::format("{}: {}", *regName, *val); + return std::format("{}: {}", *regName, detail::toHex(*val)); }); public: diff --git a/src/main.cpp b/src/main.cpp index 20adf0c..12cfe3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/test/cmd/test_scanner.cpp b/test/cmd/test_scanner.cpp index 24afd06..d0949ca 100644 --- a/test/cmd/test_scanner.cpp +++ b/test/cmd/test_scanner.cpp @@ -73,3 +73,22 @@ TEST_CASE("Test errors on malformed input", "[scanner]") { REQUIRE(captured == error_message); } } + +TEST_CASE("Test register variable tokenisation", "[scanner]") { + auto [input, expected_lexeme] = GENERATE(table( + {{"$pc", "$pc"}, {"$rax", "$rax"}, {"$sp", "$sp"}, {"$x0", "$x0"}})); + + auto tokens = helpers::scan(input); + REQUIRE(helpers::checkTokensSize(tokens.size(), 1)); + REQUIRE(tokens[0].m_type == TokenType::IDENTIFIER); + REQUIRE(tokens[0].m_lexeme == expected_lexeme); +} + +TEST_CASE("Test register variable in expression", "[scanner]") { + auto tokens = helpers::scan("$pc+4"); + REQUIRE(helpers::checkTokensSize(tokens.size(), 3)); + REQUIRE(tokens[0].m_type == TokenType::IDENTIFIER); + REQUIRE(tokens[0].m_lexeme == "$pc"); + REQUIRE(tokens[1].m_type == TokenType::PLUS); + REQUIRE(tokens[2].m_type == TokenType::NUMBER); +}