Add seti and int operators
This commit is contained in:
@@ -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;
|
||||||
@@ -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
|
||||||
10
include/execute/interrupts.hpp
Normal file
10
include/execute/interrupts.hpp
Normal 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();
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|||||||
16
src/execute/interrupts.cpp
Normal file
16
src/execute/interrupts.cpp
Normal 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); }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user