diff --git a/bin/example.wasm b/bin/example.wasm index 3692fd9..006dea0 100644 --- a/bin/example.wasm +++ b/bin/example.wasm @@ -3,14 +3,11 @@ subi %A $2 %B; muli $2 %B %C; divi $2 %C %D; -loop: +# Set A to zero addi $1 $0 %A; -addi $1 %A %B; -addi $1 %B %C; -addi $1 %C %D; -subi %D $1 %D; -subi %C $1 %C; -subi %B $1 %B; -subi %A $1 %A; +# Increment A until it is greater than 9 +loop: +addi $1 %A %A; +lti %A $10; jmp loop; \ No newline at end of file diff --git a/design.md b/design.md index a1e0ed8..e80632f 100644 --- a/design.md +++ b/design.md @@ -23,6 +23,17 @@ Divide register A by 5 and store the result in register A: `divi %A $5 %A;` +Increment B until it is 10: +``` +# Set B to zero +addi $0 $0 %B; + +loop: +addi $1 %B %B; +lti %B $10; +jmp loop; +``` + ## Reserved symbols The following whitespace characters are used to separate symbols: @@ -32,15 +43,17 @@ The following whitespace characters are used to separate symbols: - newline (`\n`) The following characters are used as identifiers: -- dollar (`$`) -- percentage (`%`) -- colon (`:`) -- semicolon (`;`) -- hash (`#`) +- dollar (`$`) for immediate (literal) values +- percentage (`%`) for register identifiers +- colon (`:`) for jump labels +- semicolon (`;`) for statement termination +- hash (`#`) for comments -All operands are reserved keywords and can therefore NOT be used as labels. +All symbols are reserved keywords and can therefore NOT be used as labels. -## Operands +## Symbols + +### Operands - `addi` add the first to the second argument and store the result in the third argument - `subi` subtract the first from the second argument and store the result in the third argument @@ -48,4 +61,10 @@ All operands are reserved keywords and can therefore NOT be used as labels. - `muli` multiply the first by the second argument and store the result in the third argument - `shli` shift left the first argument by the number of positions given by the second argument and store the result in the third argument - `shri` shift right the first argument by the number of positions given by the second argument and store the result in the third argument + +### Control Flow + - `jmp` jump to the label given by the first argument +- `lti` execute next statement if argument 1 is less than argument 2 else skip the next statement +- `gti` execute next statement if argument 1 is greater than argument 2 else skip the next statement +- `eqi` execute the next statement if argument 1 is equal to argument 2 else skip the next statement diff --git a/include/interpret/statement.hpp b/include/interpret/statement.hpp index 6aaa8d8..b7be3b1 100644 --- a/include/interpret/statement.hpp +++ b/include/interpret/statement.hpp @@ -25,18 +25,18 @@ namespace Interpret void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; }; - struct TwoArgumentStatement : Statement + struct ControlFlowStatement : Statement { - void (* function)(Execute::Flags & flags, int argument1, int argument2); + 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; }; - struct ThreeArgumentStatement : Statement + struct ArithmeticStatement : Statement { - void (* function)(Execute::Flags & flags, int argument1, int argument2, int & argument3); + void (* function)(int argument1, int argument2, int & argument3); Value firstArgument; Value secondArgument; Value thirdArgument; diff --git a/include/token/operandtype.hpp b/include/token/operandtype.hpp index 03bf098..d50bce8 100644 --- a/include/token/operandtype.hpp +++ b/include/token/operandtype.hpp @@ -12,7 +12,10 @@ namespace Token MultiplyInteger, ShiftIntegerLeft, ShiftIntegerRight, - Jump + Jump, + LessThanInteger, + GreaterThanInteger, + EqualInteger }; OperandType GetOperandType(std::string const & op); diff --git a/src/interpret/operanddefinitions.cpp b/src/interpret/operanddefinitions.cpp index 7b0d848..832c8a3 100644 --- a/src/interpret/operanddefinitions.cpp +++ b/src/interpret/operanddefinitions.cpp @@ -45,13 +45,19 @@ namespace Interpret throw ExpectedRegister(token); } - void AddArithmeticArguments(ThreeArgumentStatement & statement, unsigned const operandIndex, std::vector const & tokens) + void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector const & tokens) { statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens); statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens); statement.thirdArgument = GetRegisterArgument(operandIndex + 3u, tokens); } + void AddLogicArguments(ControlFlowStatement & statement, unsigned const operandIndex, std::vector const & tokens) + { + statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens); + statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens); + } + std::unique_ptr ExtractStatement(unsigned const operandIndex, std::vector const & tokens) { auto const & token = tokens[operandIndex]; @@ -59,8 +65,8 @@ namespace Interpret { case Token::OperandType::AddInteger: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 + argument2; }; @@ -70,8 +76,8 @@ namespace Interpret case Token::OperandType::SubtractInteger: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 - argument2; }; @@ -81,8 +87,8 @@ namespace Interpret case Token::OperandType::DivideInteger: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 / argument2; }; @@ -92,8 +98,8 @@ namespace Interpret case Token::OperandType::MultiplyInteger: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 * argument2; }; @@ -103,8 +109,8 @@ namespace Interpret case Token::OperandType::ShiftIntegerLeft: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 << argument2; }; @@ -114,8 +120,8 @@ namespace Interpret case Token::OperandType::ShiftIntegerRight: { - auto statement = std::make_unique(); - statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) + auto statement = std::make_unique(); + statement->function = [](int argument1, int argument2, int & argument3) { argument3 = argument1 >> argument2; }; @@ -133,6 +139,60 @@ namespace Interpret return std::make_unique(std::get(labelToken.data)); } + case Token::OperandType::LessThanInteger: + { + auto statement = std::make_unique(); + statement->function = [](Execute::State & state, int argument1, int argument2) + { + if (argument1 < argument2) + { + state.nextStatement = state.currentStatement + 1u; + } + else + { + state.nextStatement = state.currentStatement + 2u; + } + }; + AddLogicArguments(*statement, operandIndex, tokens); + return statement; + } + + case Token::OperandType::GreaterThanInteger: + { + auto statement = std::make_unique(); + statement->function = [](Execute::State & state, int argument1, int argument2) + { + if (argument1 > argument2) + { + state.nextStatement = state.currentStatement + 1u; + } + else + { + state.nextStatement = state.currentStatement + 2u; + } + }; + AddLogicArguments(*statement, operandIndex, tokens); + return statement; + } + + case Token::OperandType::EqualInteger: + { + auto statement = std::make_unique(); + statement->function = [](Execute::State & state, int argument1, int argument2) + { + if (argument1 == argument2) + { + state.nextStatement = state.currentStatement + 1u; + } + else + { + state.nextStatement = state.currentStatement + 2u; + } + }; + AddLogicArguments(*statement, operandIndex, tokens); + return statement; + } + default: { auto statement = std::make_unique(); @@ -155,6 +215,11 @@ namespace Interpret case Token::OperandType::ShiftIntegerRight: return 3; + case Token::OperandType::LessThanInteger: + case Token::OperandType::GreaterThanInteger: + case Token::OperandType::EqualInteger: + return 2; + case Token::OperandType::Jump: return 1; diff --git a/src/interpret/statement.cpp b/src/interpret/statement.cpp index 59e1af3..fcf1a68 100644 --- a/src/interpret/statement.cpp +++ b/src/interpret/statement.cpp @@ -12,14 +12,14 @@ namespace Interpret function(flags, firstArgument.GetValue(registers)); } - void TwoArgumentStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) + void ControlFlowStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) { - function(flags, firstArgument.GetValue(registers), secondArgument.GetValue(registers)); + function(state, firstArgument.GetValue(registers), secondArgument.GetValue(registers)); } - void ThreeArgumentStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) + void ArithmeticStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) { - function(flags, firstArgument.GetValue(registers), secondArgument.GetValue(registers), thirdArgument.GetValue(registers)); + function(firstArgument.GetValue(registers), secondArgument.GetValue(registers), thirdArgument.GetValue(registers)); } void JumpStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) diff --git a/src/main.cpp b/src/main.cpp index 5472085..8d6a9a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -114,13 +114,11 @@ int main(int argc, char ** argv) std::puts("\n*** Execution ***"); Execute::VirtualMachine vm(code); - for(unsigned i = 0u; i < 900000; ++i) + while(!vm.IsTerminated()) { vm.SingleStep(); auto const & registers = vm.GetRegisters(); std::printf("A=%i B=%i C=%i D=%i\n", registers.A, registers.B, registers.C, registers.D); - auto const & flags = vm.GetFlags(); - std::printf("-\n"); // TODO auto const & state = vm.GetState(); std::printf("current_statement=%i\n", state.currentStatement); diff --git a/src/token/operandtype.cpp b/src/token/operandtype.cpp index 3a71aa9..2ce3228 100644 --- a/src/token/operandtype.cpp +++ b/src/token/operandtype.cpp @@ -13,7 +13,10 @@ namespace Token { "muli", OperandType::MultiplyInteger }, { "shri", OperandType::ShiftIntegerRight }, { "shli", OperandType::ShiftIntegerLeft }, - { "jmp", OperandType::Jump } + { "jmp", OperandType::Jump }, + { "lti", OperandType::LessThanInteger }, + { "gti", OperandType::GreaterThanInteger }, + { "eqi", OperandType::EqualInteger }, }; auto const & result = operations.find(op); diff --git a/src/token/tokenizer.cpp b/src/token/tokenizer.cpp index fae22c6..42cd56a 100644 --- a/src/token/tokenizer.cpp +++ b/src/token/tokenizer.cpp @@ -48,6 +48,7 @@ namespace Token char const postfix = string[string.size() - 1]; if (postfix == ':') { + // TODO check if label is an Operand? return Token(lineNumber, lineColumn, string.substr(0, string.size() - 1), true); }