Added direct memory access
This commit is contained in:
13
README.md
13
README.md
@@ -14,6 +14,7 @@
|
|||||||
- `;` for end of statement (mandatory)
|
- `;` for end of statement (mandatory)
|
||||||
- `[label]:` for labels
|
- `[label]:` for labels
|
||||||
- `#[text]` for comments: any text is ignored till a newline (`\n`) is found
|
- `#[text]` for comments: any text is ignored till a newline (`\n`) is found
|
||||||
|
- `[[%register|$value]]` for accessing memory
|
||||||
- Elements must be separated by whitespace character
|
- Elements must be separated by whitespace character
|
||||||
- Good: `add $2 $5 %A;`
|
- Good: `add $2 $5 %A;`
|
||||||
- Bad: `add $2$5%A;`
|
- Bad: `add $2$5%A;`
|
||||||
@@ -34,6 +35,12 @@ lti %B $10;
|
|||||||
jmp loop;
|
jmp loop;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Read the integer at memory location `1024` into register A:
|
||||||
|
```
|
||||||
|
seti %A [$1024];
|
||||||
|
```
|
||||||
|
Remember not to use spaces inside the `[` brackets.
|
||||||
|
|
||||||
## Reserved symbols
|
## Reserved symbols
|
||||||
|
|
||||||
The following whitespace characters are used to separate symbols:
|
The following whitespace characters are used to separate symbols:
|
||||||
@@ -82,6 +89,8 @@ All symbols are reserved keywords and can therefore NOT be used as labels.
|
|||||||
|
|
||||||
## Interupts
|
## Interupts
|
||||||
|
|
||||||
- 0..9 range:
|
- [0..9] Output to STDOUT
|
||||||
- `0` put value of register A as ASCII character on stdout
|
- `0` put value of register A as ASCII character on stdout
|
||||||
- `1` put value of register A as decimal integer on stdout
|
- `1` put value of register A as decimal integer on stdout
|
||||||
|
- `2` put value of register A as hexadecimal integer on stdout
|
||||||
|
- `3` put the string pointed at by register A for the amount of characters defined by register B on stdout
|
||||||
@@ -53,4 +53,18 @@ gti %B $0;
|
|||||||
jmp world_loop;
|
jmp world_loop;
|
||||||
|
|
||||||
seti %A $10; # newline
|
seti %A $10; # newline
|
||||||
int $0;
|
int $0;
|
||||||
|
|
||||||
|
seti %B $1024;
|
||||||
|
seti [%B] $50;
|
||||||
|
seti %A $66;
|
||||||
|
seti [$10] %A;
|
||||||
|
|
||||||
|
seti %A [$10];
|
||||||
|
int $1;
|
||||||
|
|
||||||
|
seti %A $10; # newline
|
||||||
|
int $0;
|
||||||
|
|
||||||
|
seti %A [$1024];
|
||||||
|
int $1;
|
||||||
|
|||||||
@@ -16,4 +16,12 @@ namespace Execute
|
|||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Internal
|
||||||
|
{
|
||||||
|
struct BadValueType : RuntimeError
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -32,11 +32,21 @@ namespace Interpret
|
|||||||
ExpectedImmediate(Token::Token const & token);
|
ExpectedImmediate(Token::Token const & token);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExpectedImmediateOrMemory : public TokenError
|
||||||
|
{
|
||||||
|
ExpectedImmediateOrMemory(Token::Token const & token);
|
||||||
|
};
|
||||||
|
|
||||||
struct ExpectedRegister : public TokenError
|
struct ExpectedRegister : public TokenError
|
||||||
{
|
{
|
||||||
ExpectedRegister(Token::Token const & token);
|
ExpectedRegister(Token::Token const & token);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExpectedRegisterOrMemory : public TokenError
|
||||||
|
{
|
||||||
|
ExpectedRegisterOrMemory(Token::Token const & token);
|
||||||
|
};
|
||||||
|
|
||||||
struct ExpectedOperand : public TokenError
|
struct ExpectedOperand : public TokenError
|
||||||
{
|
{
|
||||||
ExpectedOperand(Token::Token const & token);
|
ExpectedOperand(Token::Token const & token);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <execute/registers.hpp>
|
#include <execute/state.hpp>
|
||||||
#include <token/token.hpp>
|
#include <token/token.hpp>
|
||||||
|
|
||||||
namespace Interpret
|
namespace Interpret
|
||||||
@@ -7,19 +7,23 @@ namespace Interpret
|
|||||||
enum class ValueType
|
enum class ValueType
|
||||||
{
|
{
|
||||||
Register,
|
Register,
|
||||||
ImmediateInteger
|
ImmediateInteger,
|
||||||
|
MemoryLocation
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ValueDataType
|
||||||
|
{
|
||||||
|
Register,
|
||||||
|
Immediate
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
{
|
{
|
||||||
ValueType type;
|
ValueType type;
|
||||||
union
|
ValueDataType dataType;
|
||||||
{
|
int data;
|
||||||
int registerIndex;
|
|
||||||
int integer;
|
|
||||||
};
|
|
||||||
|
|
||||||
int & GetValue(Execute::Registers & registers);
|
int & GetValue(Execute::State & state, Execute::Registers & registers);
|
||||||
|
|
||||||
void CreateFromToken(Token::Token const & token);
|
void CreateFromToken(Token::Token const & token);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,22 +6,43 @@
|
|||||||
|
|
||||||
namespace Token
|
namespace Token
|
||||||
{
|
{
|
||||||
|
enum class TokenValueType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Integer,
|
||||||
|
Operand,
|
||||||
|
Register,
|
||||||
|
String
|
||||||
|
};
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
Token(TokenType type, bool validness, int const lineNumber, int const lineColumn);
|
||||||
|
Token(TokenType type, std::string const & string, bool validness, int const lineNumber, int const lineColumn);
|
||||||
|
Token(TokenType type, int value, bool validness, int const lineNumber, int const lineColumn);
|
||||||
|
Token(TokenType type, RegisterType const registerType, bool validness, int const lineNumber, int const lineColumn);
|
||||||
|
Token(TokenType type, OperandType const OperandType, bool validness, int const lineNumber, int const lineColumn);
|
||||||
|
|
||||||
|
public:
|
||||||
int const lineNumber;
|
int const lineNumber;
|
||||||
int const lineColumn;
|
int const lineColumn;
|
||||||
TokenType type;
|
TokenType type;
|
||||||
|
TokenValueType const valueType;
|
||||||
bool isValid;
|
bool isValid;
|
||||||
std::variant<OperandType, RegisterType, int, std::string> data;
|
std::variant<OperandType, RegisterType, int, std::string> data;
|
||||||
|
|
||||||
Token(int const lineNumber, int const lineColumn);
|
|
||||||
Token(int const lineNumber, int const lineColumn, OperandType operatorType, bool validness);
|
|
||||||
Token(int const lineNumber, int const lineColumn, RegisterType registerType, bool validness);
|
|
||||||
Token(int const lineNumber, int const lineColumn, int value, bool validness);
|
|
||||||
Token(int const lineNumber, int const lineColumn, std::string const & value, bool validness);
|
|
||||||
|
|
||||||
Token(Token const & other);
|
Token(Token const & other);
|
||||||
|
|
||||||
|
static Token CreateUnknownToken(int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateStatementEndToken(int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateLabelToken(std::string const & string, bool isValid, int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateImmediateValueToken(int const value, bool isValid, int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn);
|
||||||
|
static Token CreateMemoryToken(int const value, bool isValid, int const lineNumber, int const lineColumn);
|
||||||
|
|
||||||
void DebugPrint() const;
|
void DebugPrint() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace Token
|
|||||||
ImmediateInteger,
|
ImmediateInteger,
|
||||||
Register,
|
Register,
|
||||||
StatementEnd,
|
StatementEnd,
|
||||||
Label
|
Label,
|
||||||
|
Memory
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ namespace Interpret
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExpectedValue::ExpectedValue(Token::Token const & token)
|
ExpectedValue::ExpectedValue(Token::Token const & token)
|
||||||
: TokenError(token, "Expected an immediate value or register")
|
: TokenError(token, "Expected an immediate value, a register or a memory location")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,11 +28,21 @@ namespace Interpret
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpectedImmediateOrMemory::ExpectedImmediateOrMemory(Token::Token const & token)
|
||||||
|
: TokenError(token, "Expected an immediate value or a memory location")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ExpectedRegister::ExpectedRegister(Token::Token const & token)
|
ExpectedRegister::ExpectedRegister(Token::Token const & token)
|
||||||
: TokenError(token, "Expected a register")
|
: TokenError(token, "Expected a register")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpectedRegisterOrMemory::ExpectedRegisterOrMemory(Token::Token const & token)
|
||||||
|
: TokenError(token, "Expected a register or a memory location")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ExpectedOperand::ExpectedOperand(Token::Token const & token)
|
ExpectedOperand::ExpectedOperand(Token::Token const & token)
|
||||||
: TokenError(token, "Expected an operand")
|
: TokenError(token, "Expected an operand")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,15 @@
|
|||||||
|
|
||||||
namespace Interpret
|
namespace Interpret
|
||||||
{
|
{
|
||||||
|
bool IsArgumentToken(Token::Token const & t)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
t.type == Token::TokenType::ImmediateInteger ||
|
||||||
|
t.type == Token::TokenType::Register ||
|
||||||
|
t.type == Token::TokenType::Label ||
|
||||||
|
t.type == Token::TokenType::Memory;
|
||||||
|
}
|
||||||
|
|
||||||
void Interpreter::Interpret(std::vector<Token::Token> const & tokens, Code & code)
|
void Interpreter::Interpret(std::vector<Token::Token> const & tokens, Code & code)
|
||||||
{
|
{
|
||||||
enum class InterpreterState
|
enum class InterpreterState
|
||||||
@@ -46,7 +55,7 @@ namespace Interpret
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case InterpreterState::FindArguments:
|
case InterpreterState::FindArguments:
|
||||||
if (token.type == Token::TokenType::ImmediateInteger || token.type == Token::TokenType::Register || token.type == Token::TokenType::Label)
|
if (IsArgumentToken(token))
|
||||||
{
|
{
|
||||||
expectedNumberOfArguments -= 1;
|
expectedNumberOfArguments -= 1;
|
||||||
if (expectedNumberOfArguments < 1)
|
if (expectedNumberOfArguments < 1)
|
||||||
|
|||||||
@@ -31,10 +31,24 @@ namespace Interpret
|
|||||||
throw ExpectedRegister(token);
|
throw ExpectedRegister(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value GetImmediateOrRegisterArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
Value GetRegisterOrMemoryArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
||||||
{
|
{
|
||||||
auto const & token = tokens[index];
|
auto const & token = tokens[index];
|
||||||
if (token.type == Token::TokenType::ImmediateInteger || token.type == Token::TokenType::Register)
|
if (token.type == Token::TokenType::Register || token.type == Token::TokenType::Memory)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
v.CreateFromToken(token);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ExpectedRegisterOrMemory(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value GetValueArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
||||||
|
{
|
||||||
|
auto const & token = tokens[index];
|
||||||
|
if (token.type == Token::TokenType::ImmediateInteger || token.type == Token::TokenType::Register || token.type == Token::TokenType::Memory)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
v.CreateFromToken(token);
|
v.CreateFromToken(token);
|
||||||
@@ -47,15 +61,15 @@ namespace Interpret
|
|||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
statement.firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||||
statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
|
statement.secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
||||||
statement.thirdArgument = GetRegisterArgument(operandIndex + 3u, tokens);
|
statement.thirdArgument = GetRegisterOrMemoryArgument(operandIndex + 3u, tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddLogicArguments(ControlFlowStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
|
void AddLogicArguments(ControlFlowStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
|
||||||
{
|
{
|
||||||
statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
statement.firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||||
statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
|
statement.secondArgument = GetValueArgument(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)
|
||||||
@@ -196,8 +210,8 @@ namespace Interpret
|
|||||||
case Token::OperandType::SetInteger:
|
case Token::OperandType::SetInteger:
|
||||||
{
|
{
|
||||||
auto statement = std::make_unique<SetStatement>();
|
auto statement = std::make_unique<SetStatement>();
|
||||||
statement->firstArgument = GetRegisterArgument(operandIndex + 1u, tokens);
|
statement->firstArgument = GetRegisterOrMemoryArgument(operandIndex + 1u, tokens);
|
||||||
statement->secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
|
statement->secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
@@ -205,7 +219,7 @@ namespace Interpret
|
|||||||
case Token::OperandType::Interrupt:
|
case Token::OperandType::Interrupt:
|
||||||
{
|
{
|
||||||
auto statement = std::make_unique<InterruptStatement>();
|
auto statement = std::make_unique<InterruptStatement>();
|
||||||
statement->firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
@@ -221,7 +235,7 @@ namespace Interpret
|
|||||||
case Token::OperandType::PushInteger:
|
case Token::OperandType::PushInteger:
|
||||||
{
|
{
|
||||||
auto statement = std::make_unique<PushStatement>();
|
auto statement = std::make_unique<PushStatement>();
|
||||||
statement->firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||||
|
|
||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ namespace Interpret
|
|||||||
|
|
||||||
void OneArgumentStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void OneArgumentStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
function(flags, firstArgument.GetValue(registers));
|
function(flags, firstArgument.GetValue(state, registers));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlFlowStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void ControlFlowStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
function(state, firstArgument.GetValue(registers), secondArgument.GetValue(registers));
|
function(state, firstArgument.GetValue(state, registers), secondArgument.GetValue(state, registers));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArithmeticStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void ArithmeticStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
function(firstArgument.GetValue(registers), secondArgument.GetValue(registers), thirdArgument.GetValue(registers));
|
function(firstArgument.GetValue(state, registers), secondArgument.GetValue(state, registers), thirdArgument.GetValue(state, 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)
|
||||||
@@ -43,12 +43,12 @@ namespace Interpret
|
|||||||
|
|
||||||
void SetStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void SetStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
firstArgument.GetValue(registers) = secondArgument.GetValue(registers);
|
firstArgument.GetValue(state, registers) = secondArgument.GetValue(state, registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterruptStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void InterruptStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
state.interrupts[firstArgument.GetValue(registers)](registers);
|
state.interrupts[firstArgument.GetValue(state, registers)](registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PopStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
void PopStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
|
||||||
@@ -59,7 +59,7 @@ namespace Interpret
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto const value = *(reinterpret_cast<int const *>(state.memory.data() + (state.stackPointer - 1u)));
|
auto const value = *(reinterpret_cast<int const *>(state.memory.data() + (state.stackPointer - 1u)));
|
||||||
firstArgument.GetValue(registers) = value;
|
firstArgument.GetValue(state, registers) = value;
|
||||||
|
|
||||||
state.stackPointer -= sizeof(int);
|
state.stackPointer -= sizeof(int);
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ namespace Interpret
|
|||||||
throw Execute::StackOverflow();
|
throw Execute::StackOverflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
*(reinterpret_cast<int *>(state.memory.data() + state.stackPointer + (sizeof(int) - 1))) = firstArgument.GetValue(registers);
|
*(reinterpret_cast<int *>(state.memory.data() + state.stackPointer + (sizeof(int) - 1))) = firstArgument.GetValue(state, registers);
|
||||||
|
|
||||||
state.stackPointer += sizeof(int);
|
state.stackPointer += sizeof(int);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,74 @@
|
|||||||
|
#include <execute/error.hpp>
|
||||||
#include <interpret/errors.hpp>
|
#include <interpret/errors.hpp>
|
||||||
#include <interpret/value.hpp>
|
#include <interpret/value.hpp>
|
||||||
|
|
||||||
namespace Interpret
|
namespace Interpret
|
||||||
{
|
{
|
||||||
int & Value::GetValue(Execute::Registers & registers)
|
int & Value::GetValue(Execute::State & state, Execute::Registers & registers)
|
||||||
{
|
{
|
||||||
if (type == ValueType::ImmediateInteger)
|
switch(type)
|
||||||
{
|
{
|
||||||
return integer;
|
case ValueType::ImmediateInteger:
|
||||||
}
|
return data;
|
||||||
|
|
||||||
return registers.registers[registerIndex];
|
case ValueType::Register:
|
||||||
|
return registers.registers[data];
|
||||||
|
|
||||||
|
case ValueType::MemoryLocation:
|
||||||
|
if (dataType == ValueDataType::Register)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<int *>(state.memory.data() + registers.registers[data]);
|
||||||
|
}
|
||||||
|
else if (dataType == ValueDataType::Immediate)
|
||||||
|
{
|
||||||
|
return *reinterpret_cast<int *>(state.memory.data() + data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw Execute::Internal::BadValueType();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Execute::Internal::BadValueType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::CreateFromToken(Token::Token const & token)
|
void Value::CreateFromToken(Token::Token const & token)
|
||||||
{
|
{
|
||||||
if (token.type == Token::TokenType::ImmediateInteger)
|
switch(token.type)
|
||||||
{
|
{
|
||||||
|
case Token::TokenType::ImmediateInteger:
|
||||||
type = ValueType::ImmediateInteger;
|
type = ValueType::ImmediateInteger;
|
||||||
integer = std::get<int>(token.data);
|
dataType = ValueDataType::Immediate;
|
||||||
}
|
data = std::get<int>(token.data);
|
||||||
else if (token.type == Token::TokenType::Register)
|
break;
|
||||||
{
|
|
||||||
|
case Token::TokenType::Register:
|
||||||
type = ValueType::Register;
|
type = ValueType::Register;
|
||||||
registerIndex = static_cast<int>(std::get<Token::RegisterType>(token.data));
|
dataType = ValueDataType::Register;
|
||||||
}
|
data = static_cast<int>(std::get<Token::RegisterType>(token.data));
|
||||||
else
|
break;
|
||||||
{
|
|
||||||
|
case Token::TokenType::Memory:
|
||||||
|
type = ValueType::MemoryLocation;
|
||||||
|
if (token.valueType == Token::TokenValueType::Integer)
|
||||||
|
{
|
||||||
|
dataType = ValueDataType::Immediate;
|
||||||
|
data = std::get<int>(token.data);
|
||||||
|
}
|
||||||
|
else if(token.valueType == Token::TokenValueType::Register)
|
||||||
|
{
|
||||||
|
dataType = ValueDataType::Register;
|
||||||
|
data = static_cast<int>(std::get<Token::RegisterType>(token.data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw Internal::BadTokenForValue(token);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
throw Internal::BadTokenForValue(token);
|
throw Internal::BadTokenForValue(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,47 +3,53 @@
|
|||||||
|
|
||||||
namespace Token
|
namespace Token
|
||||||
{
|
{
|
||||||
Token::Token(int const _lineNumber, int const _lineColumn)
|
Token::Token(TokenType _type, bool validness, int const _lineNumber, int const _lineColumn)
|
||||||
: lineNumber(_lineNumber),
|
: lineNumber(_lineNumber),
|
||||||
lineColumn(_lineColumn),
|
lineColumn(_lineColumn),
|
||||||
type(TokenType::Unknown),
|
type(_type),
|
||||||
isValid(false)
|
valueType(TokenValueType::None),
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Token::Token(int const _lineNumber, int const _lineColumn, OperandType _operatorType, bool validness)
|
|
||||||
: lineNumber(_lineNumber),
|
|
||||||
lineColumn(_lineColumn),
|
|
||||||
type(TokenType::Operand),
|
|
||||||
isValid(validness),
|
isValid(validness),
|
||||||
data(_operatorType)
|
data(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(int const _lineNumber, int const _lineColumn, RegisterType _registerType, bool validness)
|
Token::Token(TokenType _type, std::string const & string, bool validness, int const _lineNumber, int const _lineColumn)
|
||||||
: lineNumber(_lineNumber),
|
: lineNumber(_lineNumber),
|
||||||
lineColumn(_lineColumn),
|
lineColumn(_lineColumn),
|
||||||
type(TokenType::Register),
|
type(_type),
|
||||||
|
valueType(TokenValueType::String),
|
||||||
isValid(validness),
|
isValid(validness),
|
||||||
data(_registerType)
|
data(string)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(int const _lineNumber, int const _lineColumn, int value, bool validness)
|
Token::Token(TokenType _type, int value, bool validness, int const _lineNumber, int const _lineColumn)
|
||||||
: lineNumber(_lineNumber),
|
: lineNumber(_lineNumber),
|
||||||
lineColumn(_lineColumn),
|
lineColumn(_lineColumn),
|
||||||
type(TokenType::ImmediateInteger),
|
type(_type),
|
||||||
|
valueType(TokenValueType::Integer),
|
||||||
isValid(validness),
|
isValid(validness),
|
||||||
data(value)
|
data(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Token(int const _lineNumber, int const _lineColumn, std::string const & value, bool validness)
|
Token::Token(TokenType _type, RegisterType const registerType, bool validness, int const _lineNumber, int const _lineColumn)
|
||||||
: lineNumber(_lineNumber),
|
: lineNumber(_lineNumber),
|
||||||
lineColumn(_lineColumn),
|
lineColumn(_lineColumn),
|
||||||
type(TokenType::Label),
|
type(_type),
|
||||||
|
valueType(TokenValueType::Register),
|
||||||
isValid(validness),
|
isValid(validness),
|
||||||
data(value)
|
data(registerType)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Token::Token(TokenType _type, OperandType const operandType, bool validness, int const _lineNumber, int const _lineColumn)
|
||||||
|
: lineNumber(_lineNumber),
|
||||||
|
lineColumn(_lineColumn),
|
||||||
|
type(_type),
|
||||||
|
valueType(TokenValueType::Operand),
|
||||||
|
isValid(validness),
|
||||||
|
data(operandType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +58,51 @@ namespace Token
|
|||||||
lineColumn(other.lineColumn),
|
lineColumn(other.lineColumn),
|
||||||
type(other.type),
|
type(other.type),
|
||||||
isValid(other.isValid),
|
isValid(other.isValid),
|
||||||
|
valueType(other.valueType),
|
||||||
data(other.data)
|
data(other.data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Token Token::CreateUnknownToken(int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Unknown, false, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateStatementEndToken(int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::StatementEnd, true, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateLabelToken(std::string const & string, bool isValid, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Label, string, isValid, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateImmediateValueToken(int const value, bool isValid, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::ImmediateInteger, value, isValid, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateRegisterToken(RegisterType const registerType, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Register, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateOperandToken(OperandType const operandType, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Operand, operandType, operandType != OperandType::Unknown, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateMemoryToken(RegisterType const registerType, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Memory, registerType, registerType != RegisterType::Unknown, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token Token::CreateMemoryToken(int const value, bool isValid, int const lineNumber, int const lineColumn)
|
||||||
|
{
|
||||||
|
return Token(TokenType::Memory, value, isValid, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
void Token::DebugPrint() const
|
void Token::DebugPrint() const
|
||||||
{
|
{
|
||||||
std::putc(' ', stdout);
|
std::putc(' ', stdout);
|
||||||
@@ -122,6 +169,25 @@ namespace Token
|
|||||||
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::Memory:
|
||||||
|
{
|
||||||
|
switch(valueType)
|
||||||
|
{
|
||||||
|
case TokenValueType::Integer:
|
||||||
|
std::printf("[$%i]", std::get<int>(data));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TokenValueType::Register:
|
||||||
|
std::printf("[%%%i]", static_cast<int>(std::get<RegisterType>(data)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::printf("[UNKNOWN_TYPE]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case TokenType::Unknown:
|
case TokenType::Unknown:
|
||||||
default:
|
default:
|
||||||
std::printf("UNKNOWN_TOKEN");
|
std::printf("UNKNOWN_TOKEN");
|
||||||
|
|||||||
@@ -8,58 +8,87 @@ namespace Token
|
|||||||
return c == '\n' || c == ' ' || c == '\t' || c == '\r';
|
return c == '\n' || c == ' ' || c == '\t' || c == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<int, bool> TryParse(std::string const & string)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int value = std::stoi(string);
|
||||||
|
return std::make_tuple(value, true);
|
||||||
|
}
|
||||||
|
catch(std::invalid_argument &)
|
||||||
|
{
|
||||||
|
return std::make_tuple(0, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Token ExtractToken(std::string const & string, int const lineNumber, int const lineColumn)
|
Token ExtractToken(std::string const & string, int const lineNumber, int const lineColumn)
|
||||||
{
|
{
|
||||||
if (string.size() == 0)
|
if (string.size() == 0)
|
||||||
{
|
{
|
||||||
return Token(lineNumber, lineColumn);
|
return Token::CreateUnknownToken(lineNumber, lineColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
char const prefix = string[0];
|
char const prefix = string[0];
|
||||||
if (prefix == '$')
|
if (prefix == '$')
|
||||||
{
|
{
|
||||||
int value = 0;
|
auto const result = TryParse(string.substr(1, string.size()));
|
||||||
try
|
return Token::CreateImmediateValueToken(std::get<0>(result), std::get<1>(result), lineNumber, lineColumn);
|
||||||
{
|
|
||||||
value = std::stoi(string.substr(1, string.size()));
|
|
||||||
}
|
|
||||||
catch(std::invalid_argument &)
|
|
||||||
{
|
|
||||||
return Token(lineNumber, lineColumn, 0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Token(lineNumber, lineColumn, value, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix == '%')
|
if (prefix == '%')
|
||||||
{
|
{
|
||||||
RegisterType const rtype = GetRegisterType(string.substr(1, string.size()));
|
return Token::CreateRegisterToken(GetRegisterType(string.substr(1, string.size())), lineNumber, lineColumn);
|
||||||
return Token(lineNumber, lineColumn, rtype, rtype != RegisterType::Unknown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix == ';')
|
if (prefix == ';')
|
||||||
{
|
{
|
||||||
Token token(lineNumber, lineColumn);
|
return Token::CreateStatementEndToken(lineNumber, lineColumn);
|
||||||
token.type = TokenType::StatementEnd;
|
|
||||||
token.isValid = true;
|
|
||||||
return 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?
|
// TODO check if label is an Operand?
|
||||||
return Token(lineNumber, lineColumn, string.substr(0, string.size() - 1), true);
|
return Token::CreateLabelToken(string.substr(0, string.size() - 1), true, lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix == '[' && postfix == ']')
|
||||||
|
{
|
||||||
|
if(string.size() < 4)
|
||||||
|
{
|
||||||
|
return Token::CreateMemoryToken(0, false, lineNumber, lineColumn + 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
char const memoryPrefix = string[1];
|
||||||
|
std::string const valueString = string.substr(2, string.size() - 3u);
|
||||||
|
if (memoryPrefix == '$')
|
||||||
|
{
|
||||||
|
auto const result = TryParse(valueString);
|
||||||
|
return Token::CreateMemoryToken(std::get<0>(result), std::get<1>(result), lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
else if (memoryPrefix == '%')
|
||||||
|
{
|
||||||
|
return Token::CreateMemoryToken(GetRegisterType(valueString), lineNumber, lineColumn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Token::CreateMemoryToken(0, false, lineNumber, lineColumn + 1u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (prefix == '[' || postfix == ']')
|
||||||
|
{
|
||||||
|
int const errorLineColumn = (prefix == '[') ? lineColumn : (lineColumn + string.size() - 1u);
|
||||||
|
return Token::CreateMemoryToken(0, false, lineNumber, errorLineColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandType const opType = GetOperandType(string);
|
OperandType const opType = GetOperandType(string);
|
||||||
if (opType != OperandType::Unknown)
|
if (opType != OperandType::Unknown)
|
||||||
{
|
{
|
||||||
return Token(lineNumber, lineColumn, opType, true);
|
return Token::CreateOperandToken(opType, lineNumber, lineColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last resort: it must be a label
|
// Last resort: it must be a label
|
||||||
return Token(lineNumber, lineColumn, string, true);
|
return Token::CreateLabelToken(string, true, lineNumber, lineColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tokenizer::Tokenize(std::string const & line, int const lineNumber, std::vector<Token> & tokens)
|
void Tokenizer::Tokenize(std::string const & line, int const lineNumber, std::vector<Token> & tokens)
|
||||||
|
|||||||
Reference in New Issue
Block a user