262 lines
5.3 KiB
C++
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;
|
|
} |