Memory added plus basic memory operations

This commit is contained in:
2019-11-23 14:53:56 +01:00
parent 99f616e1e4
commit 22bb974a05
17 changed files with 232 additions and 68 deletions

6
src/execute/error.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include <execute/error.hpp>
namespace Execute
{
}

View File

@@ -2,11 +2,13 @@
namespace Execute
{
State::State(std::unordered_map<std::string, unsigned> const & _labelStatementIndice)
State::State(std::unordered_map<std::string, unsigned> const & _labelStatementIndice, unsigned const memorySize)
: currentStatement(0u),
nextStatement(1u),
labelStatementIndice(_labelStatementIndice),
interrupts(GetInterrupts())
interrupts(GetInterrupts()),
memory(memorySize),
stackPointer(0u)
{
}
}

View File

@@ -15,6 +15,15 @@ namespace Execute
}
}
VirtualMachine::VirtualMachine(Interpret::Code const & _code, unsigned const memorySize)
: flags(),
registers(),
state(_code.labelStatementIndice, memorySize),
terminated(false),
code(_code)
{
}
void VirtualMachine::Run()
{
while(!IsTerminated())
@@ -41,12 +50,16 @@ namespace Execute
bool VirtualMachine::IsTerminated() const { return terminated; }
VirtualMachine::VirtualMachine(Interpret::Code const & _code)
: flags(),
registers(),
state(_code.labelStatementIndice),
terminated(false),
code(_code)
VirtualMachine VirtualMachine::CreateFromCode(Interpret::Code const & code)
{
unsigned memorySize = 1024;
auto const & userMemorySizeDeclared = code.declarations.find("MEMORY_SIZE");
if (userMemorySizeDeclared != code.declarations.end() && userMemorySizeDeclared->second >= 0)
{
memorySize = userMemorySizeDeclared->second;
}
std::printf("Creating Wassembly virtual machine with %u bytes of memory.\n", memorySize);
return VirtualMachine(code, memorySize);
}
}

View File

@@ -67,7 +67,19 @@ namespace Interpret
}
else
{
code.statements.emplace_back(ExtractStatement(operatorTokenIndex, tokens));
switch(std::get<Token::OperandType>(tokens[operatorTokenIndex].data))
{
case Token::OperandType::Declaration:
{
auto const tuple = ExtractDeclaration(operatorTokenIndex, tokens);
code.declarations[std::get<0>(tuple)] = std::get<1>(tuple);
}
break;
default:
code.statements.emplace_back(ExtractStatement(operatorTokenIndex, tokens));
break;
}
state = InterpreterState::FindOperand;
}
break;

View File

@@ -210,6 +210,22 @@ namespace Interpret
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 = GetImmediateOrRegisterArgument(operandIndex + 1u, tokens);
return statement;
}
default:
{
auto statement = std::make_unique<NoArgumentStatement>();
@@ -221,6 +237,22 @@ namespace Interpret
}
}
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)
@@ -237,10 +269,13 @@ namespace Interpret
case Token::OperandType::GreaterThanInteger:
case Token::OperandType::EqualInteger:
case Token::OperandType::SetInteger:
case Token::OperandType::Declaration:
return 2;
case Token::OperandType::Jump:
case Token::OperandType::Interrupt:
case Token::OperandType::PushInteger:
case Token::OperandType::PopInteger:
return 1;
default:

View File

@@ -1,3 +1,4 @@
#include <execute/error.hpp>
#include <interpret/statement.hpp>
namespace Interpret
@@ -49,4 +50,29 @@ namespace Interpret
{
state.interrupts[firstArgument.GetValue(registers)](registers);
}
void PopStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
if (state.stackPointer < sizeof(int))
{
throw Execute::StackUnderflow();
}
auto const value = *(reinterpret_cast<int const *>(state.memory.data() + (state.stackPointer - 1u)));
firstArgument.GetValue(registers) = value;
state.stackPointer -= sizeof(int);
}
void PushStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
if ((state.memory.size() - state.stackPointer) < sizeof(int))
{
throw Execute::StackOverflow();
}
*(reinterpret_cast<int *>(state.memory.data() + state.stackPointer + (sizeof(int) - 1))) = firstArgument.GetValue(registers);
state.stackPointer += sizeof(int);
}
}

View File

@@ -24,35 +24,8 @@ void PrintTokenError(Interpret::TokenError const & err, std::vector<std::string>
PrintBadToken(err.errorToken, lines);
}
int main(int argc, char ** argv)
void PrintTokens(std::vector<Token::Token> const & tokens)
{
if (argc != 2)
{
std::puts("Usage: wassembly [filename.wasm]");
return 1;
}
std::ifstream input(argv[1]);
if (!input.is_open())
{
std::printf("Error: Cannot open file %s for reading", argv[1]);
return 1;
}
std::vector<Token::Token> tokens;
Token::Tokenizer tokenizer;
std::vector<std::string> lines; // DEBUG
std::string line;
unsigned lineNumber = 0;
while(std::getline(input, line))
{
tokenizer.Tokenize(line, lineNumber, tokens);
++lineNumber;
lines.push_back(line); // DEBUG
}
input.close();
// DEBUG
std::puts("*** Tokenization result ***");
unsigned statementNumber = 0u;
std::printf("%02u - ", statementNumber);
@@ -73,7 +46,38 @@ int main(int argc, char ** argv)
}
}
}
// END DEBUG
}
void PrintLabels(Interpret::Code const & code)
{
std::puts("\n*** Labels ***");
for(auto const & labelIndice : code.labelStatementIndice)
{
std::printf("Label %s points to statement %u\n", labelIndice.first.c_str(), labelIndice.second);
}
}
Interpret::Code GetCodeFromFile(std::string const & filePath)
{
std::ifstream input(filePath);
if (!input.is_open())
{
std::printf("Error: Cannot open file %s for reading", filePath.c_str());
exit(1);
}
std::vector<Token::Token> tokens;
Token::Tokenizer tokenizer;
std::vector<std::string> lines;
std::string line;
unsigned lineNumber = 0;
while(std::getline(input, line))
{
tokenizer.Tokenize(line, lineNumber, tokens);
++lineNumber;
lines.push_back(line);
}
input.close();
// Validate the syntax
bool syntaxOk = true;
@@ -90,7 +94,7 @@ int main(int argc, char ** argv)
if (!syntaxOk)
{
std::puts("Aborting due to syntax error(s)");
return 1;
exit(1);
}
Interpret::Interpreter interpreter;
@@ -102,33 +106,23 @@ int main(int argc, char ** argv)
catch(Interpret::TokenError & e)
{
PrintTokenError(e, lines);
exit(1);
}
return code;
}
int main(int argc, char ** argv)
{
if (argc != 2)
{
std::puts("Usage: wassembly [filename.wasm]");
return 1;
}
// DEBUG
std::puts("\n*** Labels ***");
for(auto const & labelIndice : code.labelStatementIndice)
{
std::printf("Label %s points to statement %u\n", labelIndice.first.c_str(), labelIndice.second);
}
std::puts("\n*** Execution ***");
Execute::VirtualMachine vm(code);
auto const code = GetCodeFromFile(argv[1]);
auto vm = Execute::VirtualMachine::CreateFromCode(code);
vm.Run();
/*
while(!vm.IsTerminated())
{
vm.SingleStep();
auto const & registers = vm.GetRegisters();
std::printf("A=%i B=%i C=%i D=%i\n", registers.A, registers.B, registers.C, registers.D);
auto const & state = vm.GetState();
std::printf("current_statement=%i\n", state.currentStatement);
std::puts("Press any key to step...");
std::getchar();
}
*/
// END DEBUG
return 0;
}

View File

@@ -18,7 +18,10 @@ namespace Token
{ "gti", OperandType::GreaterThanInteger },
{ "eqi", OperandType::EqualInteger },
{ "seti", OperandType::SetInteger },
{ "int", OperandType::Interrupt }
{ "int", OperandType::Interrupt },
{ "DECLARE", OperandType::Declaration },
{ "pushi", OperandType::PushInteger},
{ "popi", OperandType::PopInteger},
};
auto const & result = operations.find(op);