Added direct memory access
This commit is contained in:
13
README.md
13
README.md
@@ -14,6 +14,7 @@
|
||||
- `;` for end of statement (mandatory)
|
||||
- `[label]:` for labels
|
||||
- `#[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
|
||||
- Good: `add $2 $5 %A;`
|
||||
- Bad: `add $2$5%A;`
|
||||
@@ -34,6 +35,12 @@ lti %B $10;
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
- 0..9 range:
|
||||
- [0..9] Output to 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;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
struct ExpectedImmediateOrMemory : public TokenError
|
||||
{
|
||||
ExpectedImmediateOrMemory(Token::Token const & token);
|
||||
};
|
||||
|
||||
struct ExpectedRegister : public TokenError
|
||||
{
|
||||
ExpectedRegister(Token::Token const & token);
|
||||
};
|
||||
|
||||
struct ExpectedRegisterOrMemory : public TokenError
|
||||
{
|
||||
ExpectedRegisterOrMemory(Token::Token const & token);
|
||||
};
|
||||
|
||||
struct ExpectedOperand : public TokenError
|
||||
{
|
||||
ExpectedOperand(Token::Token const & token);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <execute/registers.hpp>
|
||||
#include <execute/state.hpp>
|
||||
#include <token/token.hpp>
|
||||
|
||||
namespace Interpret
|
||||
@@ -7,19 +7,23 @@ namespace Interpret
|
||||
enum class ValueType
|
||||
{
|
||||
Register,
|
||||
ImmediateInteger
|
||||
ImmediateInteger,
|
||||
MemoryLocation
|
||||
};
|
||||
|
||||
enum class ValueDataType
|
||||
{
|
||||
Register,
|
||||
Immediate
|
||||
};
|
||||
|
||||
struct Value
|
||||
{
|
||||
ValueType type;
|
||||
union
|
||||
{
|
||||
int registerIndex;
|
||||
int integer;
|
||||
};
|
||||
ValueDataType dataType;
|
||||
int data;
|
||||
|
||||
int & GetValue(Execute::Registers & registers);
|
||||
int & GetValue(Execute::State & state, Execute::Registers & registers);
|
||||
|
||||
void CreateFromToken(Token::Token const & token);
|
||||
};
|
||||
|
||||
@@ -6,22 +6,43 @@
|
||||
|
||||
namespace Token
|
||||
{
|
||||
enum class TokenValueType
|
||||
{
|
||||
None = 0,
|
||||
Integer,
|
||||
Operand,
|
||||
Register,
|
||||
String
|
||||
};
|
||||
|
||||
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 lineColumn;
|
||||
TokenType type;
|
||||
TokenValueType const valueType;
|
||||
bool isValid;
|
||||
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);
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Token
|
||||
ImmediateInteger,
|
||||
Register,
|
||||
StatementEnd,
|
||||
Label
|
||||
Label,
|
||||
Memory
|
||||
};
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Interpret
|
||||
}
|
||||
|
||||
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)
|
||||
: 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)
|
||||
: TokenError(token, "Expected an operand")
|
||||
{
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
|
||||
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)
|
||||
{
|
||||
enum class InterpreterState
|
||||
@@ -46,7 +55,7 @@ namespace Interpret
|
||||
break;
|
||||
|
||||
case InterpreterState::FindArguments:
|
||||
if (token.type == Token::TokenType::ImmediateInteger || token.type == Token::TokenType::Register || token.type == Token::TokenType::Label)
|
||||
if (IsArgumentToken(token))
|
||||
{
|
||||
expectedNumberOfArguments -= 1;
|
||||
if (expectedNumberOfArguments < 1)
|
||||
|
||||
@@ -31,10 +31,24 @@ namespace Interpret
|
||||
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];
|
||||
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;
|
||||
v.CreateFromToken(token);
|
||||
@@ -47,15 +61,15 @@ namespace Interpret
|
||||
|
||||
void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & tokens)
|
||||
{
|
||||
statement.firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
||||
statement.secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
|
||||
statement.thirdArgument = GetRegisterArgument(operandIndex + 3u, tokens);
|
||||
statement.firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||
statement.secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
||||
statement.thirdArgument = GetRegisterOrMemoryArgument(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);
|
||||
statement.firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||
statement.secondArgument = GetValueArgument(operandIndex + 2u, 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:
|
||||
{
|
||||
auto statement = std::make_unique<SetStatement>();
|
||||
statement->firstArgument = GetRegisterArgument(operandIndex + 1u, tokens);
|
||||
statement->secondArgument = GetImmediateOrRegisterArgument(operandIndex + 2u, tokens);
|
||||
statement->firstArgument = GetRegisterOrMemoryArgument(operandIndex + 1u, tokens);
|
||||
statement->secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
||||
|
||||
return statement;
|
||||
}
|
||||
@@ -205,7 +219,7 @@ namespace Interpret
|
||||
case Token::OperandType::Interrupt:
|
||||
{
|
||||
auto statement = std::make_unique<InterruptStatement>();
|
||||
statement->firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
||||
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||
|
||||
return statement;
|
||||
}
|
||||
@@ -221,7 +235,7 @@ namespace Interpret
|
||||
case Token::OperandType::PushInteger:
|
||||
{
|
||||
auto statement = std::make_unique<PushStatement>();
|
||||
statement->firstArgument = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
|
||||
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace Interpret
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@@ -43,12 +43,12 @@ namespace Interpret
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@@ -59,7 +59,7 @@ namespace Interpret
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace Interpret
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,74 @@
|
||||
#include <execute/error.hpp>
|
||||
#include <interpret/errors.hpp>
|
||||
#include <interpret/value.hpp>
|
||||
|
||||
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)
|
||||
{
|
||||
if (token.type == Token::TokenType::ImmediateInteger)
|
||||
switch(token.type)
|
||||
{
|
||||
case Token::TokenType::ImmediateInteger:
|
||||
type = ValueType::ImmediateInteger;
|
||||
integer = std::get<int>(token.data);
|
||||
}
|
||||
else if (token.type == Token::TokenType::Register)
|
||||
{
|
||||
dataType = ValueDataType::Immediate;
|
||||
data = std::get<int>(token.data);
|
||||
break;
|
||||
|
||||
case Token::TokenType::Register:
|
||||
type = ValueType::Register;
|
||||
registerIndex = static_cast<int>(std::get<Token::RegisterType>(token.data));
|
||||
}
|
||||
else
|
||||
{
|
||||
dataType = ValueDataType::Register;
|
||||
data = static_cast<int>(std::get<Token::RegisterType>(token.data));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,47 +3,53 @@
|
||||
|
||||
namespace Token
|
||||
{
|
||||
Token::Token(int const _lineNumber, int const _lineColumn)
|
||||
Token::Token(TokenType _type, bool validness, int const _lineNumber, int const _lineColumn)
|
||||
: lineNumber(_lineNumber),
|
||||
lineColumn(_lineColumn),
|
||||
type(TokenType::Unknown),
|
||||
isValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
Token::Token(int const _lineNumber, int const _lineColumn, OperandType _operatorType, bool validness)
|
||||
: lineNumber(_lineNumber),
|
||||
lineColumn(_lineColumn),
|
||||
type(TokenType::Operand),
|
||||
type(_type),
|
||||
valueType(TokenValueType::None),
|
||||
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),
|
||||
lineColumn(_lineColumn),
|
||||
type(TokenType::Register),
|
||||
type(_type),
|
||||
valueType(TokenValueType::String),
|
||||
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),
|
||||
lineColumn(_lineColumn),
|
||||
type(TokenType::ImmediateInteger),
|
||||
type(_type),
|
||||
valueType(TokenValueType::Integer),
|
||||
isValid(validness),
|
||||
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),
|
||||
lineColumn(_lineColumn),
|
||||
type(TokenType::Label),
|
||||
type(_type),
|
||||
valueType(TokenValueType::Register),
|
||||
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),
|
||||
type(other.type),
|
||||
isValid(other.isValid),
|
||||
valueType(other.valueType),
|
||||
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
|
||||
{
|
||||
std::putc(' ', stdout);
|
||||
@@ -122,6 +169,25 @@ namespace Token
|
||||
std::printf("LABEL=%s", std::get<std::string>(data).c_str());
|
||||
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:
|
||||
default:
|
||||
std::printf("UNKNOWN_TOKEN");
|
||||
|
||||
@@ -8,58 +8,87 @@ namespace Token
|
||||
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)
|
||||
{
|
||||
if (string.size() == 0)
|
||||
{
|
||||
return Token(lineNumber, lineColumn);
|
||||
return Token::CreateUnknownToken(lineNumber, lineColumn);
|
||||
}
|
||||
|
||||
char const prefix = string[0];
|
||||
if (prefix == '$')
|
||||
{
|
||||
int value = 0;
|
||||
try
|
||||
{
|
||||
value = std::stoi(string.substr(1, string.size()));
|
||||
}
|
||||
catch(std::invalid_argument &)
|
||||
{
|
||||
return Token(lineNumber, lineColumn, 0, false);
|
||||
}
|
||||
|
||||
return Token(lineNumber, lineColumn, value, true);
|
||||
auto const result = TryParse(string.substr(1, string.size()));
|
||||
return Token::CreateImmediateValueToken(std::get<0>(result), std::get<1>(result), lineNumber, lineColumn);
|
||||
}
|
||||
|
||||
if (prefix == '%')
|
||||
{
|
||||
RegisterType const rtype = GetRegisterType(string.substr(1, string.size()));
|
||||
return Token(lineNumber, lineColumn, rtype, rtype != RegisterType::Unknown);
|
||||
return Token::CreateRegisterToken(GetRegisterType(string.substr(1, string.size())), lineNumber, lineColumn);
|
||||
}
|
||||
|
||||
if (prefix == ';')
|
||||
{
|
||||
Token token(lineNumber, lineColumn);
|
||||
token.type = TokenType::StatementEnd;
|
||||
token.isValid = true;
|
||||
return token;
|
||||
return Token::CreateStatementEndToken(lineNumber, lineColumn);
|
||||
}
|
||||
|
||||
char const postfix = string[string.size() - 1];
|
||||
if (postfix == ':')
|
||||
{
|
||||
// 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);
|
||||
if (opType != OperandType::Unknown)
|
||||
{
|
||||
return Token(lineNumber, lineColumn, opType, true);
|
||||
return Token::CreateOperandToken(opType, lineNumber, lineColumn);
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
Reference in New Issue
Block a user