Refactor main.cpp functions into separate class

This commit is contained in:
2020-05-22 20:33:17 +02:00
parent 057a9411e6
commit e7a5cfa327
13 changed files with 252 additions and 185 deletions

13
include/configuration.hpp Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <utility>
#include <vector>
struct Configuration
{
unsigned memorySize;
std::vector<std::pair<unsigned, std::string>> strings;
void PrepareMemory(std::vector<std::uint8_t> & memory) const;
Configuration();
};

View File

@@ -9,12 +9,10 @@ namespace Execute
{
unsigned currentStatement;
unsigned nextStatement;
std::unordered_map<std::string, unsigned> const & labelStatementIndice;
std::vector<InterruptFn> const interrupts;
std::unordered_map<std::string, unsigned> const * labelStatementIndice;
std::vector<InterruptFn> interrupts;
std::vector<std::uint8_t> memory;
unsigned stackPointer;
bool terminated;
State(std::unordered_map<std::string, unsigned> const & labelStatementIndice, unsigned const memorySize);
};
}

View File

@@ -1,7 +1,9 @@
#include <configuration.hpp>
#include <execute/flags.hpp>
#include <execute/registers.hpp>
#include <execute/state.hpp>
#include <interpret/code.hpp>
#include <memory>
namespace Execute
{
@@ -11,17 +13,16 @@ namespace Execute
Flags flags;
Registers registers;
State state;
bool terminated;
Interpret::Code const & code;
std::unique_ptr<Interpret::Code const> codePtr;
void Step();
VirtualMachine(Interpret::Code const & code, unsigned const memorySize);
public:
void Run();
void SingleStep();
void LoadConfiguration(Configuration const & c);
void LoadCode(std::unique_ptr<Interpret::Code> code);
Flags const & GetFlags() const;
Registers const & GetRegisters() const;
@@ -30,6 +31,6 @@ namespace Execute
bool IsTerminated() const;
static VirtualMachine CreateFromCode(Interpret::Code const & code);
VirtualMachine();
};
}

View File

@@ -12,5 +12,10 @@ namespace Interpret
std::vector<std::unique_ptr<Statement>> statements;
std::unordered_map<std::string, unsigned> labelStatementIndice;
std::unordered_map<std::string, int> declarations;
Code() = default;
~Code() = default;
Code(const Code&) = delete;
Code& operator=(const Code&) = delete;
};
}

View File

@@ -3,6 +3,7 @@
#include <token/registertype.hpp>
#include <token/tokentype.hpp>
#include <variant>
#include <vector>
namespace Token
{
@@ -46,4 +47,6 @@ namespace Token
void DebugPrint() const;
};
void PrintTokens(std::vector<Token> const & tokens);
}

22
include/wassembler.hpp Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <configuration.hpp>
#include <execute/virtualmachine.hpp>
#include <preprocessor/preprocessor.hpp>
#include <interpret/interpreter.hpp>
#include <token/tokenizer.hpp>
class Wassembler
{
private:
Execute::VirtualMachine vm;
bool LoadLinesFromFile(std::string const & filePath, std::vector<std::string> & lines) const;
bool LoadTokens(std::vector<std::string> const & lines, std::vector<Token::Token> & tokens) const;
public:
bool LoadFromFile(std::string const & filePath);
void Run();
Wassembler() = default;
};

25
src/configuration.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <configuration.hpp>
void Configuration::PrepareMemory(std::vector<std::uint8_t> & memory) const
{
memory.resize(memorySize);
for(auto const & pair : strings)
{
for(std::size_t i = 0; i < pair.second.size(); ++i)
{
auto const index = i + pair.first;
if (index >= memory.size())
{
break;
}
memory[index] = pair.second[i];
}
}
}
Configuration::Configuration()
: memorySize(1024)
{
}

View File

@@ -1,15 +0,0 @@
#include <execute/state.hpp>
namespace Execute
{
State::State(std::unordered_map<std::string, unsigned> const & _labelStatementIndice, unsigned const memorySize)
: currentStatement(0u),
nextStatement(1u),
labelStatementIndice(_labelStatementIndice),
interrupts(GetInterrupts()),
memory(memorySize),
stackPointer(0u),
terminated(false)
{
}
}

View File

@@ -9,11 +9,11 @@ namespace Execute
try
{
code.statements[state.currentStatement]->Execute(flags, state, registers);
codePtr->statements[state.currentStatement]->Execute(flags, state, registers);
}
catch(RuntimeError & ex)
{
terminated = true;
state.terminated = true;
std::puts("\nA fatal error occurred and execution has been halted:");
std::printf("%s\n", ex.GetMessage().c_str());
@@ -21,21 +21,12 @@ namespace Execute
}
state.currentStatement = state.nextStatement;
if (state.currentStatement >= code.statements.size() || state.terminated)
if (state.currentStatement >= codePtr->statements.size())
{
terminated = true;
state.terminated = true;
}
}
VirtualMachine::VirtualMachine(Interpret::Code const & _code, unsigned const memorySize)
: flags(),
registers(),
state(_code.labelStatementIndice, memorySize),
terminated(false),
code(_code)
{
}
void VirtualMachine::Run()
{
while(!IsTerminated())
@@ -52,26 +43,29 @@ namespace Execute
}
}
void VirtualMachine::LoadConfiguration(Configuration const & c)
{
c.PrepareMemory(state.memory);
}
void VirtualMachine::LoadCode(std::unique_ptr<Interpret::Code> code)
{
codePtr = std::move(code);
state.labelStatementIndice = &(codePtr->labelStatementIndice);
}
Flags const & VirtualMachine::GetFlags() const { return flags; }
Registers const & VirtualMachine::GetRegisters() const { return registers; }
State const & VirtualMachine::GetState() const { return state; }
Interpret::Statement const * const VirtualMachine::GetCurrentStatement() const
{
return code.statements[state.currentStatement].get();
return codePtr->statements[state.currentStatement].get();
}
bool VirtualMachine::IsTerminated() const { return terminated; }
bool VirtualMachine::IsTerminated() const { return state.terminated; }
VirtualMachine VirtualMachine::CreateFromCode(Interpret::Code const & code)
VirtualMachine::VirtualMachine()
{
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);
state.interrupts = GetInterrupts();
}
}

View File

@@ -26,8 +26,8 @@ namespace Interpret
void JumpStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
auto const & elem = state.labelStatementIndice.find(label);
if (elem != state.labelStatementIndice.end())
auto const & elem = state.labelStatementIndice->find(label);
if (elem != state.labelStatementIndice->end())
{
state.nextStatement = elem->second;
}
@@ -44,8 +44,8 @@ namespace Interpret
void FunctionCallStatement::Execute(Execute::Flags & flags, Execute::State & state, Execute::Registers & registers)
{
auto const & elem = state.labelStatementIndice.find(label);
if (elem == state.labelStatementIndice.end())
auto const & elem = state.labelStatementIndice->find(label);
if (elem == state.labelStatementIndice->end())
{
throw Execute::MissingLabel(label);
}

View File

@@ -1,133 +1,5 @@
#include <cstdio>
#include <execute/virtualmachine.hpp>
#include <fstream>
#include <interpret/errors.hpp>
#include <interpret/interpreter.hpp>
#include <token/errors.hpp>
#include <token/tokenizer.hpp>
void PrintBadToken(Token::Token const & token, std::vector<std::string> const & lines)
{
std::printf("at line number %i, column %i:\n",
token.lineNumber + 1,
token.lineColumn + 1);
std::printf("%s\n", lines[token.lineNumber].c_str());
for(int i = 0; i < token.lineColumn; ++i)
{
std::putc(' ', stdout);
}
std::puts("^");
}
void PrintTokenError(Interpret::InterpretationError const & err, std::vector<std::string> const & lines)
{
std::printf("%s ", err.errorMsg.c_str());
PrintBadToken(err.errorToken, lines);
}
void PrintTokenError(Token::TokenizationError const & err, std::vector<std::string> const & lines)
{
std::printf("%s ", err.errorMsg.c_str());
PrintBadToken(err.errorToken, lines);
}
void PrintTokens(std::vector<Token::Token> const & tokens)
{
std::puts("*** Tokenization result ***");
unsigned statementNumber = 0u;
std::printf("%02u - ", statementNumber);
for(unsigned i = 0u; i < tokens.size(); ++i)
{
auto const & token = tokens[i];
token.DebugPrint();
if (token.type == Token::TokenType::StatementEnd)
{
++statementNumber;
if (i + 1 < tokens.size())
{
std::printf("\n%02u - ", statementNumber);
}
else
{
std::puts("");
}
}
}
}
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;
bool tokenizationError = false;
while(std::getline(input, line))
{
try
{
tokenizer.Tokenize(line, lineNumber, tokens);
}
catch(Token::TokenizationError & err)
{
tokenizationError = true;
PrintTokenError(err, lines);
}
++lineNumber;
lines.push_back(line);
}
input.close();
// Validate the syntax
bool syntaxError = false;
for(auto const & token : tokens)
{
if (!token.isValid)
{
std::printf("Syntax error ");
PrintBadToken(token, lines);
syntaxError = true;
}
}
if (tokenizationError || syntaxError)
{
std::puts("Aborting due to syntax error(s)");
exit(1);
}
Interpret::Interpreter interpreter;
Interpret::Code code;
try
{
interpreter.Interpret(tokens, code);
}
catch(Interpret::InterpretationError & e)
{
PrintTokenError(e, lines);
exit(1);
}
return code;
}
#include <wassembler.hpp>
int main(int argc, char ** argv)
{
@@ -137,9 +9,13 @@ int main(int argc, char ** argv)
return 1;
}
auto const code = GetCodeFromFile(argv[1]);
auto vm = Execute::VirtualMachine::CreateFromCode(code);
vm.Run();
Wassembler wassembler;
if (!wassembler.LoadFromFile(argv[1]))
{
exit(1);
}
wassembler.Run();
return 0;
}

View File

@@ -203,4 +203,28 @@ namespace Token
break;
}
}
void PrintTokens(std::vector<Token> const & tokens)
{
std::puts("*** Tokenization result ***");
unsigned statementNumber = 0u;
std::printf("%02u - ", statementNumber);
for(unsigned i = 0u; i < tokens.size(); ++i)
{
auto const & token = tokens[i];
token.DebugPrint();
if (token.type == TokenType::StatementEnd)
{
++statementNumber;
if (i + 1 < tokens.size())
{
std::printf("\n%02u - ", statementNumber);
}
else
{
std::puts("");
}
}
}
}
}

121
src/wassembler.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include <fstream>
#include <interpret/errors.hpp>
#include <token/errors.hpp>
#include <wassembler.hpp>
void PrintBadToken(Token::Token const & token, std::vector<std::string> const & lines)
{
std::printf("at line number %i, column %i:\n",
token.lineNumber + 1,
token.lineColumn + 1);
std::printf("%s\n", lines[token.lineNumber].c_str());
for(int i = 0; i < token.lineColumn; ++i)
{
std::putc(' ', stdout);
}
std::puts("^");
}
void PrintTokenError(Interpret::InterpretationError const & err, std::vector<std::string> const & lines)
{
std::printf("%s ", err.errorMsg.c_str());
PrintBadToken(err.errorToken, lines);
}
void PrintTokenError(Token::TokenizationError const & err, std::vector<std::string> const & lines)
{
std::printf("%s ", err.errorMsg.c_str());
PrintBadToken(err.errorToken, lines);
}
bool Wassembler::LoadLinesFromFile(std::string const & filePath, std::vector<std::string> & lines) const
{
std::ifstream input(filePath);
if (!input.is_open())
{
return false;
}
std::string line;
while(std::getline(input, line))
{
lines.push_back(line);
}
input.close();
return true;
}
bool Wassembler::LoadTokens(std::vector<std::string> const & lines, std::vector<Token::Token> & tokens) const
{
Token::Tokenizer tokenizer;
bool tokenizationError = false;
for(std::size_t i = 0; i < lines.size(); ++i)
{
try
{
tokenizer.Tokenize(lines[i], i, tokens);
}
catch(Token::TokenizationError & err)
{
tokenizationError = true;
PrintTokenError(err, lines);
}
}
// Validate the syntax
bool syntaxError = false;
for(auto const & token : tokens)
{
if (!token.isValid)
{
std::printf("Syntax error ");
PrintBadToken(token, lines);
syntaxError = true;
}
}
return !(syntaxError || tokenizationError);
}
bool Wassembler::LoadFromFile(std::string const & filePath)
{
std::vector<std::string> lines;
if (!LoadLinesFromFile(filePath, lines))
{
std::printf("Error: Cannot open file %s for reading", filePath.c_str());
return false;
}
std::vector<Token::Token> tokens;
if (!LoadTokens(lines, tokens))
{
std::puts("Aborting due to syntax error(s)");
return false;
}
Interpret::Interpreter interpreter;
auto codePtr = std::make_unique<Interpret::Code>();
try
{
interpreter.Interpret(tokens, *codePtr);
}
catch(Interpret::InterpretationError & e)
{
PrintBadToken(e.errorToken, lines);
return false;
}
vm.LoadCode(std::move(codePtr));
Configuration config;
vm.LoadConfiguration(config);
return true;
}
void Wassembler::Run()
{
vm.Run();
}