Add control flow operands

This commit is contained in:
2019-11-21 18:38:02 +01:00
parent 1bac553f4b
commit f0e00ff018
9 changed files with 127 additions and 41 deletions

View File

@@ -3,14 +3,11 @@ subi %A $2 %B;
muli $2 %B %C; muli $2 %B %C;
divi $2 %C %D; divi $2 %C %D;
loop: # Set A to zero
addi $1 $0 %A; addi $1 $0 %A;
addi $1 %A %B;
addi $1 %B %C;
addi $1 %C %D;
subi %D $1 %D; # Increment A until it is greater than 9
subi %C $1 %C; loop:
subi %B $1 %B; addi $1 %A %A;
subi %A $1 %A; lti %A $10;
jmp loop; jmp loop;

View File

@@ -23,6 +23,17 @@
Divide register A by 5 and store the result in register A: Divide register A by 5 and store the result in register A:
`divi %A $5 %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 ## Reserved symbols
The following whitespace characters are used to separate 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`) - newline (`\n`)
The following characters are used as identifiers: The following characters are used as identifiers:
- dollar (`$`) - dollar (`$`) for immediate (literal) values
- percentage (`%`) - percentage (`%`) for register identifiers
- colon (`:`) - colon (`:`) for jump labels
- semicolon (`;`) - semicolon (`;`) for statement termination
- hash (`#`) - 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 - `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 - `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 - `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 - `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 - `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 - `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

View File

@@ -25,18 +25,18 @@ namespace Interpret
void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; 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 firstArgument;
Value secondArgument; Value secondArgument;
void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override; 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 firstArgument;
Value secondArgument; Value secondArgument;
Value thirdArgument; Value thirdArgument;

View File

@@ -12,7 +12,10 @@ namespace Token
MultiplyInteger, MultiplyInteger,
ShiftIntegerLeft, ShiftIntegerLeft,
ShiftIntegerRight, ShiftIntegerRight,
Jump Jump,
LessThanInteger,
GreaterThanInteger,
EqualInteger
}; };
OperandType GetOperandType(std::string const & op); OperandType GetOperandType(std::string const & op);

View File

@@ -45,13 +45,19 @@ namespace Interpret
throw ExpectedRegister(token); throw ExpectedRegister(token);
} }
void AddArithmeticArguments(ThreeArgumentStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens) void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
{ {
statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens); statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens); statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
statement.thirdArgument = GetRegisterArgument(operandIndex + 3u, tokens); statement.thirdArgument = GetRegisterArgument(operandIndex + 3u, tokens);
} }
void AddLogicArguments(ControlFlowStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
{
statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
}
std::unique_ptr<Statement> ExtractStatement(unsigned const operandIndex, std::vector<Token::Token> const & tokens) std::unique_ptr<Statement> ExtractStatement(unsigned const operandIndex, std::vector<Token::Token> const & tokens)
{ {
auto const & token = tokens[operandIndex]; auto const & token = tokens[operandIndex];
@@ -59,8 +65,8 @@ namespace Interpret
{ {
case Token::OperandType::AddInteger: case Token::OperandType::AddInteger:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 + argument2; argument3 = argument1 + argument2;
}; };
@@ -70,8 +76,8 @@ namespace Interpret
case Token::OperandType::SubtractInteger: case Token::OperandType::SubtractInteger:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 - argument2; argument3 = argument1 - argument2;
}; };
@@ -81,8 +87,8 @@ namespace Interpret
case Token::OperandType::DivideInteger: case Token::OperandType::DivideInteger:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 / argument2; argument3 = argument1 / argument2;
}; };
@@ -92,8 +98,8 @@ namespace Interpret
case Token::OperandType::MultiplyInteger: case Token::OperandType::MultiplyInteger:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 * argument2; argument3 = argument1 * argument2;
}; };
@@ -103,8 +109,8 @@ namespace Interpret
case Token::OperandType::ShiftIntegerLeft: case Token::OperandType::ShiftIntegerLeft:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 << argument2; argument3 = argument1 << argument2;
}; };
@@ -114,8 +120,8 @@ namespace Interpret
case Token::OperandType::ShiftIntegerRight: case Token::OperandType::ShiftIntegerRight:
{ {
auto statement = std::make_unique<ThreeArgumentStatement>(); auto statement = std::make_unique<ArithmeticStatement>();
statement->function = [](Execute::Flags & flags, int argument1, int argument2, int & argument3) statement->function = [](int argument1, int argument2, int & argument3)
{ {
argument3 = argument1 >> argument2; argument3 = argument1 >> argument2;
}; };
@@ -133,6 +139,60 @@ namespace Interpret
return std::make_unique<JumpStatement>(std::get<std::string>(labelToken.data)); return std::make_unique<JumpStatement>(std::get<std::string>(labelToken.data));
} }
case Token::OperandType::LessThanInteger:
{
auto statement = std::make_unique<ControlFlowStatement>();
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<ControlFlowStatement>();
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<ControlFlowStatement>();
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: default:
{ {
auto statement = std::make_unique<NoArgumentStatement>(); auto statement = std::make_unique<NoArgumentStatement>();
@@ -155,6 +215,11 @@ namespace Interpret
case Token::OperandType::ShiftIntegerRight: case Token::OperandType::ShiftIntegerRight:
return 3; return 3;
case Token::OperandType::LessThanInteger:
case Token::OperandType::GreaterThanInteger:
case Token::OperandType::EqualInteger:
return 2;
case Token::OperandType::Jump: case Token::OperandType::Jump:
return 1; return 1;

View File

@@ -12,14 +12,14 @@ namespace Interpret
function(flags, firstArgument.GetValue(registers)); 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) void JumpStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)

View File

@@ -114,13 +114,11 @@ int main(int argc, char ** argv)
std::puts("\n*** Execution ***"); std::puts("\n*** Execution ***");
Execute::VirtualMachine vm(code); Execute::VirtualMachine vm(code);
for(unsigned i = 0u; i < 900000; ++i) while(!vm.IsTerminated())
{ {
vm.SingleStep(); vm.SingleStep();
auto const & registers = vm.GetRegisters(); auto const & registers = vm.GetRegisters();
std::printf("A=%i B=%i C=%i D=%i\n", registers.A, registers.B, registers.C, registers.D); 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(); auto const & state = vm.GetState();
std::printf("current_statement=%i\n", state.currentStatement); std::printf("current_statement=%i\n", state.currentStatement);

View File

@@ -13,7 +13,10 @@ namespace Token
{ "muli", OperandType::MultiplyInteger }, { "muli", OperandType::MultiplyInteger },
{ "shri", OperandType::ShiftIntegerRight }, { "shri", OperandType::ShiftIntegerRight },
{ "shli", OperandType::ShiftIntegerLeft }, { "shli", OperandType::ShiftIntegerLeft },
{ "jmp", OperandType::Jump } { "jmp", OperandType::Jump },
{ "lti", OperandType::LessThanInteger },
{ "gti", OperandType::GreaterThanInteger },
{ "eqi", OperandType::EqualInteger },
}; };
auto const & result = operations.find(op); auto const & result = operations.find(op);

View File

@@ -48,6 +48,7 @@ namespace Token
char const postfix = string[string.size() - 1]; char const postfix = string[string.size() - 1];
if (postfix == ':') if (postfix == ':')
{ {
// TODO check if label is an Operand?
return Token(lineNumber, lineColumn, string.substr(0, string.size() - 1), true); return Token(lineNumber, lineColumn, string.substr(0, string.size() - 1), true);
} }