diff --git a/bin/example.wasm b/bin/example.wasm index 1eef694..599c73b 100644 --- a/bin/example.wasm +++ b/bin/example.wasm @@ -39,7 +39,7 @@ int $0; pushi $68; # D pushi $76; # L pushi $82; # R -pushi $79; # O +pushi $79; # O pushi $87; # W seti %B $5; @@ -72,17 +72,23 @@ seti %A [$1024]; int $2; # Push the string "hell" into register A -seti %A $108; +seti %A $108; # l shli %A $8 %A; -addi %A $108 %A; +addi %A $108 %A; # l shli %A $8 %A; -addi %A $101 %A; +addi %A $101 %A; # e shli %A $8 %A; -addi %A $104 %A; +addi %A $104 %A; # h -# Store A at 900 +# Store A at memory location 900 seti [$900] %A; + # Setup to print a string from position 900 seti %A $900; seti %B $4; -int $3; \ No newline at end of file +int $3; + +# Jump over the interrupt +call program_exit; +int $3; +program_exit: \ No newline at end of file diff --git a/include/execute/virtualmachine.hpp b/include/execute/virtualmachine.hpp index 68a590f..2fe74dd 100644 --- a/include/execute/virtualmachine.hpp +++ b/include/execute/virtualmachine.hpp @@ -27,7 +27,7 @@ namespace Execute Registers const & GetRegisters() const; State const & GetState() const; Interpret::Statement const * const GetCurrentStatement() const; - + bool IsTerminated() const; static VirtualMachine CreateFromCode(Interpret::Code const & code); diff --git a/include/interpret/statement.hpp b/include/interpret/statement.hpp index 799da5d..d046a0b 100644 --- a/include/interpret/statement.hpp +++ b/include/interpret/statement.hpp @@ -30,7 +30,7 @@ namespace Interpret void (* function)(Execute::State & state, int argument1, int argument2); Value firstArgument; Value secondArgument; - + void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; }; @@ -40,7 +40,7 @@ namespace Interpret Value firstArgument; Value secondArgument; Value thirdArgument; - + void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; }; @@ -55,6 +55,17 @@ namespace Interpret JumpStatement(std::string const & label); }; + struct FunctionCallStatement : Statement + { + private: + std::string const label; + + public: + void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; + + FunctionCallStatement(std::string const & label); + }; + struct SetStatement : Statement { Value firstArgument; diff --git a/include/token/operandtype.hpp b/include/token/operandtype.hpp index 308b0dd..b6f534f 100644 --- a/include/token/operandtype.hpp +++ b/include/token/operandtype.hpp @@ -13,6 +13,7 @@ namespace Token ShiftIntegerLeft, ShiftIntegerRight, Jump, + CallFunction, LessThanInteger, GreaterThanInteger, EqualInteger, diff --git a/src/execute/virtualmachine.cpp b/src/execute/virtualmachine.cpp index 99d8d45..02267e6 100644 --- a/src/execute/virtualmachine.cpp +++ b/src/execute/virtualmachine.cpp @@ -5,9 +5,9 @@ namespace Execute void VirtualMachine::Step() { state.nextStatement = state.currentStatement + 1u; - + code.statements[state.currentStatement]->Execute(flags, state, registers); - + state.currentStatement = state.nextStatement; if (state.currentStatement >= code.statements.size()) { @@ -48,7 +48,7 @@ namespace Execute return code.statements[state.currentStatement].get(); } - bool VirtualMachine::IsTerminated() const { return terminated; } + bool VirtualMachine::IsTerminated() const { return terminated; } VirtualMachine VirtualMachine::CreateFromCode(Interpret::Code const & code) { diff --git a/src/interpret/operanddefinitions.cpp b/src/interpret/operanddefinitions.cpp index 5cdc6a9..7cfaef9 100644 --- a/src/interpret/operanddefinitions.cpp +++ b/src/interpret/operanddefinitions.cpp @@ -150,9 +150,21 @@ namespace Interpret { throw ExpectedLabel(labelToken); } + return std::make_unique(std::get(labelToken.data)); } + case Token::OperandType::CallFunction: + { + auto labelToken = tokens[operandIndex + 1u]; + if (labelToken.type != Token::TokenType::Label) + { + throw ExpectedLabel(labelToken); + } + + return std::make_unique(std::get(labelToken.data)); + } + case Token::OperandType::LessThanInteger: { auto statement = std::make_unique(); @@ -243,9 +255,12 @@ namespace Interpret default: { auto statement = std::make_unique(); - + // TODO throw error? - statement->function = [](Execute::Flags & flags, Execute::Registers & registers) { std::puts("ExtractStatement: Extracted unhandled operator type"); }; + statement->function = [](Execute::Flags & flags, Execute::Registers & registers) + { + std::puts("ExtractStatement: Extracted unhandled operator type"); + }; return statement; } } @@ -287,6 +302,7 @@ namespace Interpret return 2; case Token::OperandType::Jump: + case Token::OperandType::CallFunction: case Token::OperandType::Interrupt: case Token::OperandType::PushInteger: case Token::OperandType::PopInteger: diff --git a/src/interpret/statement.cpp b/src/interpret/statement.cpp index 34227ee..df1655e 100644 --- a/src/interpret/statement.cpp +++ b/src/interpret/statement.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace Interpret { @@ -41,6 +42,30 @@ namespace Interpret { } + void FunctionCallStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) + { + auto const & elem = state.labelStatementIndice.find(label); + if (elem == state.labelStatementIndice.end()) + { + throw std::runtime_error("Attempted call nonexisting function (missing label)"); + } + + if ((state.memory.size() - state.stackPointer) < sizeof(unsigned)) + { + throw Execute::StackOverflow(); + } + + *(reinterpret_cast(state.memory.data() + state.stackPointer + (sizeof(unsigned) - 1))) = state.nextStatement; + + state.stackPointer += sizeof(int); + state.nextStatement = elem->second; + } + + FunctionCallStatement::FunctionCallStatement(std::string const & _label) + : label(_label) + { + } + void SetStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) { firstArgument.GetValue(state, registers) = secondArgument.GetValue(state, registers); diff --git a/src/token/operandtype.cpp b/src/token/operandtype.cpp index ce16c68..fa911ad 100644 --- a/src/token/operandtype.cpp +++ b/src/token/operandtype.cpp @@ -14,6 +14,7 @@ namespace Token { "shri", OperandType::ShiftIntegerRight }, { "shli", OperandType::ShiftIntegerLeft }, { "jmp", OperandType::Jump }, + { "call", OperandType::CallFunction }, { "lti", OperandType::LessThanInteger }, { "gti", OperandType::GreaterThanInteger }, { "eqi", OperandType::EqualInteger }, diff --git a/src/token/token.cpp b/src/token/token.cpp index af09870..b80f1ba 100644 --- a/src/token/token.cpp +++ b/src/token/token.cpp @@ -57,8 +57,8 @@ namespace Token : lineNumber(other.lineNumber), lineColumn(other.lineColumn), type(other.type), - isValid(other.isValid), valueType(other.valueType), + isValid(other.isValid), data(other.data) { } diff --git a/src/token/tokenizer.cpp b/src/token/tokenizer.cpp index 78e798f..62a3c54 100644 --- a/src/token/tokenizer.cpp +++ b/src/token/tokenizer.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace Token