Refactor main.cpp functions into separate class
This commit is contained in:
13
include/configuration.hpp
Normal file
13
include/configuration.hpp
Normal 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();
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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
22
include/wassembler.hpp
Normal 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
25
src/configuration.cpp
Normal 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)
|
||||
{
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
140
src/main.cpp
140
src/main.cpp
@@ -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;
|
||||
}
|
||||
@@ -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
121
src/wassembler.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user