327 lines
9.1 KiB
C++
327 lines
9.1 KiB
C++
#include <interpret/operanddefinitions.hpp>
|
|
#include <interpret/errors.hpp>
|
|
|
|
namespace Interpret
|
|
{
|
|
Value GetImmediateArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
|
{
|
|
auto const & token = tokens[index];
|
|
if (token.type == Token::TokenType::ImmediateInteger)
|
|
{
|
|
Value v;
|
|
v.CreateFromToken(token);
|
|
|
|
return v;
|
|
}
|
|
|
|
throw ExpectedImmediate(token);
|
|
}
|
|
|
|
Value GetRegisterArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
|
{
|
|
auto const & token = tokens[index];
|
|
if (token.type == Token::TokenType::Register)
|
|
{
|
|
Value v;
|
|
v.CreateFromToken(token);
|
|
|
|
return v;
|
|
}
|
|
|
|
throw ExpectedRegister(token);
|
|
}
|
|
|
|
Value GetRegisterOrMemoryArgument(unsigned const index, std::vector<Token::Token> const & tokens)
|
|
{
|
|
auto const & token = tokens[index];
|
|
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);
|
|
|
|
return v;
|
|
}
|
|
|
|
throw ExpectedValue(token);
|
|
}
|
|
|
|
void AddArithmeticArguments(ArithmeticStatement & statement, unsigned const operandIndex, std::vector<Token::Token> const & 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 = GetValueArgument(operandIndex + 1u, tokens);
|
|
statement.secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
|
}
|
|
|
|
std::unique_ptr<Statement> ExtractStatement(unsigned const operandIndex, std::vector<Token::Token> const & tokens)
|
|
{
|
|
auto const & token = tokens[operandIndex];
|
|
switch(std::get<Token::OperandType>(token.data))
|
|
{
|
|
case Token::OperandType::AddInteger:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 + argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::SubtractInteger:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 - argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::DivideInteger:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 / argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::MultiplyInteger:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 * argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::ShiftIntegerLeft:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 << argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::ShiftIntegerRight:
|
|
{
|
|
auto statement = std::make_unique<ArithmeticStatement>();
|
|
statement->function = [](int argument1, int argument2, int & argument3)
|
|
{
|
|
argument3 = argument1 >> argument2;
|
|
};
|
|
AddArithmeticArguments(*statement, operandIndex, tokens);
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::Jump:
|
|
{
|
|
auto labelToken = tokens[operandIndex + 1u];
|
|
if (labelToken.type != Token::TokenType::Label)
|
|
{
|
|
throw ExpectedLabel(labelToken);
|
|
}
|
|
|
|
return std::make_unique<JumpStatement>(std::get<std::string>(labelToken.data));
|
|
}
|
|
|
|
case Token::OperandType::CallFunction:
|
|
{
|
|
auto labelToken = tokens[operandIndex + 1u];
|
|
if (labelToken.type != Token::TokenType::Label)
|
|
{
|
|
throw ExpectedLabel(labelToken);
|
|
}
|
|
|
|
return std::make_unique<FunctionCallStatement>(std::get<std::string>(labelToken.data));
|
|
}
|
|
|
|
case Token::OperandType::ReturnFromFunction:
|
|
{
|
|
return std::make_unique<ReturnFromFunctionStatement>();
|
|
}
|
|
|
|
case Token::OperandType::ExitProgram:
|
|
{
|
|
return std::make_unique<ExitProgramStatement>();
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
case Token::OperandType::SetInteger:
|
|
{
|
|
auto statement = std::make_unique<SetStatement>();
|
|
statement->firstArgument = GetRegisterOrMemoryArgument(operandIndex + 1u, tokens);
|
|
statement->secondArgument = GetValueArgument(operandIndex + 2u, tokens);
|
|
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::Interrupt:
|
|
{
|
|
auto statement = std::make_unique<InterruptStatement>();
|
|
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
|
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::PopInteger:
|
|
{
|
|
auto statement = std::make_unique<PopStatement>();
|
|
statement->firstArgument = GetRegisterArgument(operandIndex + 1u, tokens);
|
|
|
|
return statement;
|
|
}
|
|
|
|
case Token::OperandType::PushInteger:
|
|
{
|
|
auto statement = std::make_unique<PushStatement>();
|
|
statement->firstArgument = GetValueArgument(operandIndex + 1u, tokens);
|
|
|
|
return statement;
|
|
}
|
|
|
|
default:
|
|
{
|
|
auto statement = std::make_unique<NoArgumentStatement>();
|
|
|
|
// TODO throw error?
|
|
statement->function = [](Execute::Flags & flags, Execute::Registers & registers)
|
|
{
|
|
std::puts("ExtractStatement: Extracted unhandled operator type");
|
|
};
|
|
return statement;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::tuple<std::string, int> ExtractDeclaration(unsigned const operatorIndex, std::vector<Token::Token> const & tokens)
|
|
{
|
|
if (tokens[operatorIndex + 1u].type != Token::TokenType::Label)
|
|
{
|
|
throw ExpectedLabel(tokens[operatorIndex + 1u]);
|
|
}
|
|
if (tokens[operatorIndex + 2u].type != Token::TokenType::ImmediateInteger)
|
|
{
|
|
throw ExpectedImmediate(tokens[operatorIndex + 2u]);
|
|
}
|
|
|
|
auto const label = std::get<std::string>(tokens[operatorIndex + 1u].data);
|
|
auto const value = std::get<int>(tokens[operatorIndex + 2u].data);
|
|
return std::make_tuple(label, value);
|
|
}
|
|
|
|
int GetRequiredNumberOfArguments(Token::OperandType const type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case Token::OperandType::AddInteger:
|
|
case Token::OperandType::SubtractInteger:
|
|
case Token::OperandType::DivideInteger:
|
|
case Token::OperandType::MultiplyInteger:
|
|
case Token::OperandType::ShiftIntegerLeft:
|
|
case Token::OperandType::ShiftIntegerRight:
|
|
return 3;
|
|
|
|
case Token::OperandType::LessThanInteger:
|
|
case Token::OperandType::GreaterThanInteger:
|
|
case Token::OperandType::EqualInteger:
|
|
case Token::OperandType::SetInteger:
|
|
return 2;
|
|
|
|
case Token::OperandType::Jump:
|
|
case Token::OperandType::CallFunction:
|
|
case Token::OperandType::Interrupt:
|
|
case Token::OperandType::PushInteger:
|
|
case Token::OperandType::PopInteger:
|
|
return 1;
|
|
|
|
default:
|
|
std::printf("WARNING: returning default argument length of 0 for operand type %i\n", static_cast<int>(type));
|
|
case Token::OperandType::ReturnFromFunction:
|
|
case Token::OperandType::ExitProgram:
|
|
return 0;
|
|
}
|
|
}
|
|
} |