Files
wassembly/src/wassembler.cpp

262 lines
5.3 KiB
C++

#include <compile/compiler.hpp>
#include <compile/errors.hpp>
#include <execute/error.hpp>
#include <fstream>
#include <preprocessor/preprocessor.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: ",
token.lineNumber + 1,
token.lineColumn + 1);
std::puts(token.errorMessage.c_str());
std::printf("%s\n", lines[token.lineNumber].c_str());
for(int i = 0; i < token.lineColumn; ++i)
{
std::putc(' ', stdout);
}
std::puts("^");
}
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::LoadTextFile(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::Preprocess(std::vector<std::string> & lines) const
{
Preprocessor preprocessor;
preprocessor.process(lines);
if (printSubstitutions)
{
preprocessor.printSubstitutions();
}
return true;
}
bool Wassembler::Tokenize(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);
}
}
if (printTokens && tokens.size() > 0)
{
int previousLine = tokens[0].lineNumber;
std::printf("Line %04i: ", previousLine);
for(auto const & token : tokens)
{
if (token.lineNumber != previousLine)
{
std::putc('\n', stdout);
previousLine = token.lineNumber;
std::printf("Line %04i: ", previousLine);
}
token.Print();
}
std::putc('\n', stdout);
}
// 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::CompileToBytes(
std::vector<Token::Token> const & tokens,
std::vector<std::string> const & lines,
std::vector<std::uint8_t> & bytes) const
{
Compile::Compiler compiler;
try
{
compiler.Compile(tokens, bytes);
}
catch(Compile::CompilationError & e)
{
std::printf("Semantic error ");
PrintBadToken(e.errorToken, lines);
return false;
}
return true;
}
void Wassembler::ExecuteCode(std::vector<uint8_t> const & bytes)
{
vm.LoadCode(bytes, printTranslatedBytes);
// TODO clear memory?
vm.Run();
}
bool Wassembler::CompileFile(
std::string const & filePath,
std::vector<std::uint8_t> & bytes) const
{
std::vector<std::string> lines;
if (!LoadTextFile(filePath, lines))
{
std::printf("Error: Cannot open file %s for reading", filePath.c_str());
return false;
}
if(!Preprocess(lines))
{
std::puts("Aborting due to preprocessor error(s)");
return false;
}
std::vector<Token::Token> tokens;
if (!Tokenize(lines, tokens) || !CompileToBytes(tokens, lines, bytes))
{
std::puts("Aborting due to syntax error(s)");
return false;
}
return true;
}
void Wassembler::SetMemorySize(unsigned const size)
{
vm.SetMemorySize(size);
}
void Wassembler::EnableSubstitutionsLogging()
{
printSubstitutions = true;
}
void Wassembler::EnableTokensLogging()
{
printTokens = true;
}
void Wassembler::EnableByteTranslationLogging()
{
printTranslatedBytes = true;
}
bool Wassembler::CompileAndRun(std::string const & filePath)
{
std::vector<std::uint8_t> bytes;
if (filePath.size() > 4 && filePath.compare(filePath.size() - 4, 4, ".bin") == 0)
{
std::ifstream inputFile(filePath);
if (!inputFile.is_open())
{
std::printf("Error: Cannot open file %s for reading", filePath.c_str());
return false;
}
std::size_t previousSize = 0;
bytes.resize(100);
while(inputFile.read(reinterpret_cast<char*>(&bytes[previousSize]), 100))
{
previousSize = bytes.size();
bytes.resize(bytes.size() + 100);
}
bytes.resize(bytes.size() - (100 - inputFile.gcount()));
}
else if (filePath.size() > 5 &&
filePath.compare(filePath.size() - 5, 5, ".wasm") == 0)
{
if (!CompileFile(filePath, bytes))
{
return false;
}
}
else
{
std::printf(
"Error: unrecognized file extension on input file %s",
filePath.c_str());
return false;
}
try
{
ExecuteCode(bytes);
}
catch (Execute::RuntimeError const & e)
{
std::puts(e.GetMessage().c_str());
std::puts("Aborting due to runtime error(s)");
return false;
}
return true;
}
bool Wassembler::CompileToFile(
std::string const & inputFilePath,
std::string const & outputFilePath)
{
std::vector<std::uint8_t> bytes;
if (!CompileFile(inputFilePath, bytes))
{
return false;
}
std::ofstream output(outputFilePath, std::ios::binary | std::ios::trunc);
if (!output.is_open())
{
std::printf("Error: Cannot open file %s for writing", outputFilePath.c_str());
return false;
}
if (!output.write(reinterpret_cast<char*>(bytes.data()), bytes.size()))
{
std::printf("Error: An error occurred whilst writing to %s", outputFilePath.c_str());
return false;
}
return true;
}