Add control flow operands
This commit is contained in:
@@ -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;
|
||||||
33
design.md
33
design.md
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user