#include #include #include #include #include #include #include void PrintBadToken(Token::Token const & token, std::vector 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 const & lines) { std::printf("%s ", err.errorMsg.c_str()); PrintBadToken(err.errorToken, lines); } bool Wassembler::LoadTextFile(std::string const & filePath, std::vector & 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 & lines) const { Preprocessor preprocessor; preprocessor.process(lines); if (printSubstitutions) { preprocessor.printSubstitutions(); } return true; } bool Wassembler::Tokenize(std::vector const & lines, std::vector & 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 const & tokens, std::vector const & lines, std::vector & 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 const & bytes) { vm.LoadCode(bytes, printTranslatedBytes); // TODO clear memory? vm.Run(); } bool Wassembler::CompileFile( std::string const & filePath, std::vector & bytes) const { std::vector 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 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 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(&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 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(bytes.data()), bytes.size())) { std::printf("Error: An error occurred whilst writing to %s", outputFilePath.c_str()); return false; } return true; }