Add seti and int operators

This commit is contained in:
2019-11-23 12:21:14 +01:00
parent f0e00ff018
commit 99f616e1e4
16 changed files with 153 additions and 66 deletions

View File

@@ -4,10 +4,32 @@ muli $2 %B %C;
divi $2 %C %D; divi $2 %C %D;
# Set A to zero # Set A to zero
addi $1 $0 %A; seti %A $0;
# Increment A until it is greater than 9 # Loop from 0 to 10
loop: loop:
addi $1 %A %A; addi $1 %A %A;
# Print the current value
int $1;
seti %B %A;
seti %A $10; # new line
int $0;
seti %A %B;
lti %A $10; lti %A $10;
jmp loop; jmp loop;
# Hello world
seti %A $72; # H
int $0;
seti %A $101; # e
int $0;
seti %A $108; # l
int $0;
int $0;
seti %A $111; # o
int $0;
seti %A $10; # newline
int $0;

View File

@@ -61,6 +61,8 @@ All symbols 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
- `seti` set the first register argument to the second argument
- `int` calls the interrupt specified by the first (integer) argument
### Control Flow ### Control Flow
@@ -68,3 +70,9 @@ All symbols are reserved keywords and can therefore NOT be used as labels.
- `lti` execute next statement if argument 1 is less than argument 2 else skip the next statement - `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 - `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 - `eqi` execute the next statement if argument 1 is equal to argument 2 else skip the next statement
## Interupts
- 0..9 range:
- `0` put value of register A as ASCII character on stdout
- `1` put value of register A as decimal integer on stdout

View File

@@ -0,0 +1,10 @@
#pragma once
#include <execute/registers.hpp>
#include <vector>
using InterruptFn = void (*)(Execute::Registers & registers);
namespace Execute
{
std::vector<InterruptFn> GetInterrupts();
}

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <execute/interrupts.hpp>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@@ -9,7 +10,7 @@ namespace Execute
unsigned currentStatement; unsigned currentStatement;
unsigned nextStatement; unsigned nextStatement;
std::unordered_map<std::string, unsigned> const & labelStatementIndice; std::unordered_map<std::string, unsigned> const & labelStatementIndice;
std::vector<InterruptFn> const interrupts;
State(std::unordered_map<std::string, unsigned> const & labelStatementIndice); State(std::unordered_map<std::string, unsigned> const & labelStatementIndice);
}; };

View File

@@ -22,6 +22,11 @@ namespace Interpret
ExpectedLabel(Token::Token const & token); ExpectedLabel(Token::Token const & token);
}; };
struct ExpectedValue : public TokenError
{
ExpectedValue(Token::Token const & token);
};
struct ExpectedImmediate : public TokenError struct ExpectedImmediate : public TokenError
{ {
ExpectedImmediate(Token::Token const & token); ExpectedImmediate(Token::Token const & token);

View File

@@ -54,4 +54,19 @@ namespace Interpret
JumpStatement(std::string const & label); JumpStatement(std::string const & label);
}; };
struct SetStatement : Statement
{
Value firstArgument;
Value secondArgument;
void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override;
};
struct InterruptStatement : Statement
{
Value firstArgument;
void Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers) override;
};
} }

View File

@@ -3,7 +3,7 @@
namespace Token namespace Token
{ {
enum class OperandType enum class OperandType : int
{ {
Unknown = -1, Unknown = -1,
AddInteger = 0, AddInteger = 0,
@@ -15,7 +15,9 @@ namespace Token
Jump, Jump,
LessThanInteger, LessThanInteger,
GreaterThanInteger, GreaterThanInteger,
EqualInteger EqualInteger,
SetInteger,
Interrupt
}; };
OperandType GetOperandType(std::string const & op); OperandType GetOperandType(std::string const & op);

View File

@@ -0,0 +1,16 @@
#include <cstdio>
#include <execute/interrupts.hpp>
namespace Execute
{
std::vector<InterruptFn> GetInterrupts()
{
return std::vector<InterruptFn>
{
// 0 print char
[](Execute::Registers & registers) { std::putc(registers.A, stdout); },
// 1 print decimal integer
[](Execute::Registers & registers) { std::printf("%i", registers.A); }
};
}
}

View File

@@ -5,7 +5,8 @@ namespace Execute
State::State(std::unordered_map<std::string, unsigned> const & _labelStatementIndice) State::State(std::unordered_map<std::string, unsigned> const & _labelStatementIndice)
: currentStatement(0u), : currentStatement(0u),
nextStatement(1u), nextStatement(1u),
labelStatementIndice(_labelStatementIndice) labelStatementIndice(_labelStatementIndice),
interrupts(GetInterrupts())
{ {
} }
} }

View File

@@ -18,6 +18,11 @@ namespace Interpret
{ {
} }
ExpectedValue::ExpectedValue(Token::Token const & token)
: TokenError(token, "Expected an immediate value or register")
{
}
ExpectedImmediate::ExpectedImmediate(Token::Token const & token) ExpectedImmediate::ExpectedImmediate(Token::Token const & token)
: TokenError(token, "Expected an immediate value") : TokenError(token, "Expected an immediate value")
{ {

View File

@@ -42,7 +42,7 @@ namespace Interpret
return v; return v;
} }
throw ExpectedRegister(token); throw ExpectedValue(token);
} }
void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens) void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
@@ -193,9 +193,27 @@ namespace Interpret
return statement; return statement;
} }
case Token::OperandType::SetInteger:
{
auto statement = std::make_unique<SetStatement>();
statement->firstArgument = GetRegisterArgument(operandIndex + 1u, tokens);
statement->secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
return statement;
}
case Token::OperandType::Interrupt:
{
auto statement = std::make_unique<InterruptStatement>();
statement->firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
return statement;
}
default: default:
{ {
auto statement = std::make_unique<NoArgumentStatement>(); auto statement = std::make_unique<NoArgumentStatement>();
// TODO throw error? // 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; return statement;
@@ -218,12 +236,15 @@ namespace Interpret
case Token::OperandType::LessThanInteger: case Token::OperandType::LessThanInteger:
case Token::OperandType::GreaterThanInteger: case Token::OperandType::GreaterThanInteger:
case Token::OperandType::EqualInteger: case Token::OperandType::EqualInteger:
case Token::OperandType::SetInteger:
return 2; return 2;
case Token::OperandType::Jump: case Token::OperandType::Jump:
case Token::OperandType::Interrupt:
return 1; return 1;
default: default:
std::printf("WARNING: returning default argument length of 0 for operand type %i\n", static_cast<int>(type));
return 0; return 0;
} }
} }

View File

@@ -39,4 +39,14 @@ namespace Interpret
: label(_label) : label(_label)
{ {
} }
void SetStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
firstArgument.GetValue(registers) = secondArgument.GetValue(registers);
}
void InterruptStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
state.interrupts[firstArgument.GetValue(registers)](registers);
}
} }

View File

@@ -114,6 +114,8 @@ int main(int argc, char ** argv)
std::puts("\n*** Execution ***"); std::puts("\n*** Execution ***");
Execute::VirtualMachine vm(code); Execute::VirtualMachine vm(code);
vm.Run();
/*
while(!vm.IsTerminated()) while(!vm.IsTerminated())
{ {
vm.SingleStep(); vm.SingleStep();
@@ -125,6 +127,7 @@ int main(int argc, char ** argv)
std::puts("Press any key to step..."); std::puts("Press any key to step...");
std::getchar(); std::getchar();
} }
*/
// END DEBUG // END DEBUG
return 0; return 0;

View File

@@ -17,6 +17,8 @@ namespace Token
{ "lti", OperandType::LessThanInteger }, { "lti", OperandType::LessThanInteger },
{ "gti", OperandType::GreaterThanInteger }, { "gti", OperandType::GreaterThanInteger },
{ "eqi", OperandType::EqualInteger }, { "eqi", OperandType::EqualInteger },
{ "seti", OperandType::SetInteger },
{ "int", OperandType::Interrupt }
}; };
auto const & result = operations.find(op); auto const & result = operations.find(op);

View File

@@ -64,49 +64,26 @@ namespace Token
case TokenType::ImmediateInteger: case TokenType::ImmediateInteger:
if (isValid) if (isValid)
{ {
std::printf("$int=%i", std::get<int>(data)); std::printf("%i", std::get<int>(data));
} }
else else
{ {
std::printf("BAD_IMM_INT"); std::printf("BAD_IMM");
} }
break; break;
case TokenType::Operand: case TokenType::Operand:
if (isValid) if (isValid)
{ {
switch(std::get<OperandType>(data)) OperandType const opType = std::get<OperandType>(data);
switch(opType)
{ {
case OperandType::AddInteger: case OperandType::Unknown:
std::printf("addi"); std::printf("unknown_op");
break;
case OperandType::MultiplyInteger:
std::printf("muli");
break;
case OperandType::SubtractInteger:
std::printf("subi");
break;
case OperandType::DivideInteger:
std::printf("divi");
break;
case OperandType::ShiftIntegerLeft:
std::printf("shli");
break;
case OperandType::ShiftIntegerRight:
std::printf("shri");
break;
case OperandType::Jump:
std::printf("jump");
break; break;
default: default:
std::printf("unknown_op"); std::printf("op%i", static_cast<int>(opType));
break; break;
} }
} }
@@ -119,25 +96,14 @@ namespace Token
case TokenType::Register: case TokenType::Register:
if (isValid) if (isValid)
{ {
switch(std::get<RegisterType>(data)) RegisterType const regType = std::get<RegisterType>(data);
switch(regType)
{ {
case RegisterType::A:
std::printf("%%A");
break;
case RegisterType::B:
std::printf("%%B");
break;
case RegisterType::C:
std::printf("%%C");
break;
case RegisterType::D:
std::printf("%%D");
break;
default: default:
std::printf("%%%i", static_cast<int>(regType));
break;
case RegisterType::Unknown:
std::printf("%%unknown_reg"); std::printf("%%unknown_reg");
break; break;
} }
@@ -153,7 +119,7 @@ namespace Token
break; break;
case TokenType::Label: case TokenType::Label:
std::printf("label=%s", std::get<std::string>(data).c_str()); std::printf("LABEL=%s", std::get<std::string>(data).c_str());
break; break;
case TokenType::Unknown: case TokenType::Unknown:

View File

@@ -70,32 +70,32 @@ namespace Token
LookForTokenEnd, LookForTokenEnd,
}; };
TokenizerState state = TokenizerState::LookForNextToken; TokenizerState state = TokenizerState::LookForNextToken;
unsigned tokenStart = 0; unsigned columnTokenStart = 0;
for(unsigned i = 0u; i < line.size(); ++i) for(unsigned column = 0u; column < line.size(); ++column)
{ {
switch(state) switch(state)
{ {
case TokenizerState::LookForNextToken: case TokenizerState::LookForNextToken:
if (!IsWhiteSpace(line[i])) if (!IsWhiteSpace(line[column]))
{ {
if (line[i] == '#') if (line[column] == '#')
{ {
// Ignore comments // Ignore comments
return; return;
} }
tokenStart = i; columnTokenStart = column;
state = TokenizerState::LookForTokenEnd; state = TokenizerState::LookForTokenEnd;
} }
break; break;
case TokenizerState::LookForTokenEnd: case TokenizerState::LookForTokenEnd:
if (IsWhiteSpace(line[i]) || line[i] == ';') if (IsWhiteSpace(line[column]) || line[column] == ';')
{ {
tokens.push_back(ExtractToken(line.substr(tokenStart, i - tokenStart), lineNumber, tokenStart)); tokens.push_back(ExtractToken(line.substr(columnTokenStart, column - columnTokenStart), lineNumber, columnTokenStart));
if (line[i] == ';') if (line[column] == ';')
{ {
tokens.push_back(ExtractToken(line.substr(i, 1), lineNumber, tokenStart)); tokens.push_back(ExtractToken(line.substr(column, 1), lineNumber, column));
} }
state = TokenizerState::LookForNextToken; state = TokenizerState::LookForNextToken;
} }
@@ -104,7 +104,7 @@ namespace Token
} }
if (state == TokenizerState::LookForTokenEnd) if (state == TokenizerState::LookForTokenEnd)
{ {
tokens.push_back(ExtractToken(line.substr(tokenStart, line.size()), lineNumber, tokenStart)); tokens.push_back(ExtractToken(line.substr(columnTokenStart, line.size()), lineNumber, columnTokenStart));
} }
} }
} }