From e4ee6e2ab0559176ff021875111158869b827528 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Mon, 6 May 2024 14:36:19 +0200 Subject: MHR-21: Improve ParserKit, as well as C++ compiler for better parsing. Signed-off-by: Amlal El Mahrouss --- Sources/amd64-cplusplus.cc | 397 ----------------------------------------- Sources/cplusplus.cc | 428 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 428 insertions(+), 397 deletions(-) delete mode 100644 Sources/amd64-cplusplus.cc create mode 100644 Sources/cplusplus.cc (limited to 'Sources') diff --git a/Sources/amd64-cplusplus.cc b/Sources/amd64-cplusplus.cc deleted file mode 100644 index 60e6435..0000000 --- a/Sources/amd64-cplusplus.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * ======================================================== - * - * ccplus - * Copyright Mahrouss Logic, all rights reserved. - * - * ======================================================== - */ - -/// bugs: 0 - -#define __PK_USE_STRUCT_INSTEAD__ 1 - -#define kPrintF printf - -#define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Mahrouss C++ Compiler, Copyright Mahrouss Logic.") - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kOk 0 - -/* Mahrouss Logic C++ driver */ -/* This is part of CodeTools C++ compiler. */ -/* (c) Mahrouss Logic */ - -// @author Amlal El Mahrouss (amlel) -// @file cc.cc -// @brief Optimized C++ Compiler. - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail { -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Offset based struct/class -struct CompilerStructMap final { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; - -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) { - std::cout << kRed << "[ ccplus ] " << kWhite - << ((file == "ccplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType { - std::string fName; - std::string fValue; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::vector kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for Mahrouss Logic C++ */ -class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCPlusPlus() = default; - ~CompilerBackendCPlusPlus() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); - - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override; -}; - -/// compiler variables - -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; - -/// detail namespaces - -namespace detail { -union number_cast final { - number_cast(UInt64 raw) : raw(raw) {} - - char number[8]; - UInt64 raw; -}; -} // namespace detail - -const char* CompilerBackendCPlusPlus::Language() { return "C++"; } - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCPlusPlus::Compile(const std::string& text, - const char* file) { - if (text.empty()) return false; - - // if (expr) - // int name = expr; - // expr; - - std::size_t index = 0UL; - - std::vector> keywords_list; - - for (auto& keyword : kKeywords) { - while (text.find(keyword.keyword_name) != std::string::npos) { - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - } - } - - // TODO: sort keywords - - for (auto& keyword : keywords_list) { - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointClang() = default; - ~AssemblyMountpointClang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointClang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArchAMD64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override { - if (arch != AssemblyMountpointClang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - - std::vector exts = kAsmFileExts; - dest += exts[3]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: CodeTools assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; - (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" - << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string source; - - while (std::getline(src_fp, source)) { - // Compile into an AST format. - kCompilerBackend->Compile(source.c_str(), src.data()); - } - - if (kAcceptableErrors > 0) return -1; - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static void cxx_print_help() { - kSplashCxx(); - kPrintF("%s", "No help available, see:\r\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { ".cpp", ".cxx", ".cc", ".c++", ".cp" } - -MPCC_MODULE(CompilerCPlusPlus) { - bool skip = false; - - kFactory.Mount(new AssemblyMountpointClang()); - kCompilerBackend = new CompilerBackendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) { - if (argv[index][0] == '-') { - if (skip) { - skip = false; - continue; - } - - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cxx_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-max-errors") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - detail::print_error(err, "ccplus"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - bool found = false; - - for (std::string ext : exts) { - if (argv_i.find(ext) != std::string::npos) { - found = true; - break; - } - } - - if (!found) { - if (kState.fVerbose) { - detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc new file mode 100644 index 0000000..e729f54 --- /dev/null +++ b/Sources/cplusplus.cc @@ -0,0 +1,428 @@ +/* + * ======================================================== + * + * ccplus + * Copyright Mahrouss Logic, all rights reserved. + * + * ======================================================== + */ + +/// bugs: 0 + +#define __PK_USE_STRUCT_INSTEAD__ 1 + +#define kPrintF printf + +#define kSplashCxx() \ + kPrintF(kWhite "%s\n", "Mahrouss C++ Compiler, Copyright Mahrouss Logic.") + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kOk 0 + +/* Mahrouss Logic C++ driver */ +/* This is part of CodeTools C++ compiler. */ +/* (c) Mahrouss Logic */ + +// @author Amlal El Mahrouss (amlel) +// @file cc.cc +// @brief Optimized C++ Compiler. + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNAL STUFF OF THE C COMPILER + +///////////////////////////////////// + +namespace detail { +struct CompilerRegisterMap final { + std::string fName; + std::string fReg; +}; + +// \brief Offset based struct/class +struct CompilerStructMap final { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector> fOffsets; +}; + +struct CompilerState final { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; +}; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; + +static Int32 kAcceptableErrors = 0; + +namespace detail { +void print_error(std::string reason, std::string file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) { + std::cout << kRed << "[ ccplus ] " << kWhite + << ((file == "ccplus") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank + << std::endl; + + kState.fLastFile = file; + } else { + std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +struct CompilerType { + std::string fName; + std::string fValue; +}; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; + +///////////////////////////////////////// + +// ARGUMENTS REGISTERS (R8, R15) + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::vector kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static size_t kBracesCount = 0UL; + +/* @brief C++ compiler backend for Mahrouss Logic C++ */ +class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { + public: + explicit CompilerBackendCPlusPlus() = default; + ~CompilerBackendCPlusPlus() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); + + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override; +}; + +/// compiler variables + +static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; + +/// detail namespaces + +namespace detail { +union number_cast final { + number_cast(UInt64 raw) : raw(raw) {} + + char number[8]; + UInt64 raw; +}; +} // namespace detail + +const char* CompilerBackendCPlusPlus::Language() { return "C++"; } + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C++ source. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCPlusPlus::Compile(const std::string& text, + const char* file) { + if (text.empty()) return false; + + // if (expr) + // int name = expr; + // expr; + + std::size_t index = 0UL; + std::vector> keywords_list; + + bool found = false; + + for (auto& keyword : kKeywords) { + if (text.find(keyword.keyword_name) != std::string::npos) { + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + + found = true; + } + } + + if (!found) { + detail::print_error("syntax error: " + text, file); + } + + // TODO: sort keywords + + for (auto& keyword : keywords_list) { + auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface { + public: + explicit AssemblyMountpointClang() = default; + ~AssemblyMountpointClang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointClang); + + [[maybe_unused]] static Int32 Arch() noexcept { + return CompilerKit::AssemblyFactory::kArchAMD64; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override { + if (arch != AssemblyMountpointClang::Arch()) return -1; + + if (kCompilerBackend == nullptr) return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) { + if (ch == '.') { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + + std::vector exts = kAsmFileExts; + dest += exts[3]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "; Language: CodeTools assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; + (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" + << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.emplace_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string source; + + while (std::getline(src_fp, source)) { + // Compile into an object file. + kCompilerBackend->Compile(source.c_str(), src.data()); + } + + for (auto& ast : kState.fSyntaxTree->fLeafList) { + (*kState.fOutputAssembly) << ast.fUserValue; + } + + if (kAcceptableErrors > 0) return -1; + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static void cxx_print_help() { + kSplashCxx(); + kPrintF("%s", "No help available, see:\r\n"); + kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExtListCxx \ + { ".cpp", ".cxx", ".cc", ".c++", ".cp" } + +MPCC_MODULE(CompilerCPlusPlus) { + bool skip = false; + + kKeywords.push_back({ .keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass }); + kKeywords.push_back({ .keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass }); + kKeywords.push_back({ .keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace }); + kKeywords.push_back({ .keyword_name = "typedef" , .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({ .keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({ .keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyStart }); + kKeywords.push_back({ .keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyEnd }); + kKeywords.push_back({ .keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable }); + kKeywords.push_back({ .keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign }); + kKeywords.push_back({ .keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant }); + kKeywords.push_back({ .keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess }); + kKeywords.push_back({ .keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess }); + kKeywords.push_back({ .keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator }); + kKeywords.push_back({ .keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr }); + kKeywords.push_back({ .keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier }); + kKeywords.push_back({ .keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); + kKeywords.push_back({ .keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); + kKeywords.push_back({ .keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); + kKeywords.push_back({ .keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier }); + + kFactory.Mount(new AssemblyMountpointClang()); + kCompilerBackend = new CompilerBackendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) { + if (argv[index][0] == '-') { + if (skip) { + skip = false; + continue; + } + + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { + cxx_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) { + if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-max-errors") == 0) { + try { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + detail::print_error(err, "ccplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + bool found = false; + + for (std::string ext : exts) { + if (argv_i.find(ext) != std::string::npos) { + found = true; + break; + } + } + + if (!found) { + if (kState.fVerbose) { + detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); + } + + return 1; + } + + if (kFactory.Compile(argv_i, kMachine) != kOk) return -1; + } + + return kOk; +} + +// Last rev 8-1-24 -- cgit v1.2.3 From aed39642ea46602e16096f93ee163e8dbd53d1b7 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 8 May 2024 23:49:39 +0200 Subject: MHR-21: :boom: refactor. Signed-off-by: Amlal El Mahrouss --- 64asm.rsrc | 4 ++-- 64x0-cc.rsrc | 4 ++-- Headers/AsmKit/AsmKit.hpp | 2 +- Headers/AsmKit/CPU/32x0.hpp | 2 +- Headers/AsmKit/CPU/64x0.hpp | 2 +- Headers/AsmKit/CPU/amd64.hpp | 2 +- Headers/CompilerKit.hpp | 2 +- Headers/Defines.hpp | 2 +- Headers/ParserKit.hpp | 2 +- Headers/StdKit/AE.hpp | 2 +- Headers/StdKit/ErrorID.hpp | 2 +- Headers/StdKit/ErrorOr.hpp | 2 +- Headers/StdKit/PEF.hpp | 2 +- Headers/StdKit/Ref.hpp | 2 +- Headers/StdKit/String.hpp | 2 +- Headers/StdKit/XCOFF.hxx | 2 +- ReadMe.md | 2 +- SDK/__mpcc_alloca.hxx | 2 +- SDK/__mpcc_defines.hxx | 2 +- SDK/__mpcc_exception.hxx | 2 +- SDK/__mpcc_hint.hxx | 2 +- SDK/__mpcc_malloc.hxx | 2 +- Sources/32asm.cc | 2 +- Sources/64asm.cc | 4 ++-- Sources/64x0-cc.cc | 6 +++--- Sources/AsmKit.cc | 4 ++-- Sources/Detail/asmutils.h | 2 +- Sources/Detail/compilerutils.h | 2 +- Sources/String.cc | 4 ++-- Sources/bpp.cc | 6 +++--- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 10 +++++----- Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 6 +++--- Sources/link.cc | 8 ++++---- Sources/ppc-cc.cc | 4 ++-- Sources/ppcasm.cc | 7 +++---- bpp.rsrc | 4 ++-- i64asm.rsrc | 4 ++-- link.rsrc | 4 ++-- posix.make | 4 ++-- ppc-cc.rsrc | 4 ++-- ppcasm.rsrc | 4 ++-- win64.make | 4 ++-- 44 files changed, 72 insertions(+), 73 deletions(-) (limited to 'Sources') diff --git a/64asm.rsrc b/64asm.rsrc index 44ae486..7c84d45 100644 --- a/64asm.rsrc +++ b/64asm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS 64x0 assembler." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "64asm.exe" VALUE "ProductName", "NewAssembler" VALUE "ProductVersion", kDistVersion diff --git a/64x0-cc.rsrc b/64x0-cc.rsrc index afa07df..dcec172 100644 --- a/64x0-cc.rsrc +++ b/64x0-cc.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS 64x0 C compiler." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewC" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "64x0-cc.exe" VALUE "ProductName", "NewC" VALUE "ProductVersion", kDistVersion diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp index 2ea4796..23db830 100644 --- a/Headers/AsmKit/AsmKit.hpp +++ b/Headers/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp index a78a04b..44ddaed 100644 --- a/Headers/AsmKit/CPU/32x0.hpp +++ b/Headers/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp index a72f72f..352e8c6 100644 --- a/Headers/AsmKit/CPU/64x0.hpp +++ b/Headers/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp index 5a8f72a..ee12c8a 100644 --- a/Headers/AsmKit/CPU/amd64.hpp +++ b/Headers/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/CompilerKit.hpp b/Headers/CompilerKit.hpp index 9e37666..3d5cfc2 100644 --- a/Headers/CompilerKit.hpp +++ b/Headers/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/Defines.hpp b/Headers/Defines.hpp index 01230e6..ac8692b 100644 --- a/Headers/Defines.hpp +++ b/Headers/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index 68bc431..60ac892 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp index ca54671..3075017 100644 --- a/Headers/StdKit/AE.hpp +++ b/Headers/StdKit/AE.hpp @@ -2,7 +2,7 @@ * ======================================================== * * MPCC - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Headers/StdKit/ErrorID.hpp b/Headers/StdKit/ErrorID.hpp index 363f4d5..ef1f778 100644 --- a/Headers/StdKit/ErrorID.hpp +++ b/Headers/StdKit/ErrorID.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Headers/StdKit/ErrorOr.hpp b/Headers/StdKit/ErrorOr.hpp index dbd83ce..d61f3e9 100644 --- a/Headers/StdKit/ErrorOr.hpp +++ b/Headers/StdKit/ErrorOr.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp index 6f0602c..ee01852 100644 --- a/Headers/StdKit/PEF.hpp +++ b/Headers/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/Ref.hpp b/Headers/StdKit/Ref.hpp index c4aa2d3..d13f97c 100644 --- a/Headers/StdKit/Ref.hpp +++ b/Headers/StdKit/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp index adc6a9d..20fd16f 100644 --- a/Headers/StdKit/String.hpp +++ b/Headers/StdKit/String.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx index e21a380..b9cc825 100644 --- a/Headers/StdKit/XCOFF.hxx +++ b/Headers/StdKit/XCOFF.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs File: XCOFF.hpp Purpose: XCOFF for NewOS. diff --git a/ReadMe.md b/ReadMe.md index 2dc803a..4c5f385 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,4 +14,4 @@ make all Author: Amlal El Mahrouss -##### Copyright Mahrouss Logic, all rights reserved. +##### Copyright SoftwareLabs, all rights reserved. diff --git a/SDK/__mpcc_alloca.hxx b/SDK/__mpcc_alloca.hxx index f56da9f..f15e059 100644 --- a/SDK/__mpcc_alloca.hxx +++ b/SDK/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_defines.hxx b/SDK/__mpcc_defines.hxx index b335d1e..ff91db1 100644 --- a/SDK/__mpcc_defines.hxx +++ b/SDK/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_exception.hxx b/SDK/__mpcc_exception.hxx index d2ca325..d36aba6 100644 --- a/SDK/__mpcc_exception.hxx +++ b/SDK/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_hint.hxx b/SDK/__mpcc_hint.hxx index 843407e..d775f52 100644 --- a/SDK/__mpcc_hint.hxx +++ b/SDK/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_malloc.hxx b/SDK/__mpcc_malloc.hxx index da08b19..56989f8 100644 --- a/SDK/__mpcc_malloc.hxx +++ b/SDK/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/32asm.cc b/Sources/32asm.cc index e5aa500..4c98645 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/64asm.cc b/Sources/64asm.cc index d2568e2..8f42ea2 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ @@ -110,7 +110,7 @@ MPCC_MODULE(NewOSAssembler64000) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 Mahrouss Logic.\n"; + "2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index c23e3c1..e73bf4d 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -27,7 +27,7 @@ /* C driver */ /* This is part of CodeTools C SDK. */ -/* (c) Mahrouss Logic */ +/* (c) SoftwareLabs */ /// @author Amlal El Mahrouss (amlel) /// @file 64x0-cc.cc @@ -1258,7 +1258,7 @@ class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) static void cc_print_help() { kSplashCxx(); } diff --git a/Sources/AsmKit.cc b/Sources/AsmKit.cc index b4af817..38ca551 100644 --- a/Sources/AsmKit.cc +++ b/Sources/AsmKit.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ @@ -14,7 +14,7 @@ * @version 0.1 * @date 2024-01-27 * - * @copyright Copyright (c) 2024, Mahrouss Logic + * @copyright Copyright (c) 2024, SoftwareLabs * */ diff --git a/Sources/Detail/asmutils.h b/Sources/Detail/asmutils.h index 2408998..c0537ad 100644 --- a/Sources/Detail/asmutils.h +++ b/Sources/Detail/asmutils.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/Detail/compilerutils.h b/Sources/Detail/compilerutils.h index 038f3cf..cde8d34 100644 --- a/Sources/Detail/compilerutils.h +++ b/Sources/Detail/compilerutils.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/String.cc b/Sources/String.cc index 449c933..6f7603f 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 Mahrouss Logic + * @copyright Copyright (c) 2024 SoftwareLabs * */ diff --git a/Sources/bpp.cc b/Sources/bpp.cc index 1e15366..a988693 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -2,7 +2,7 @@ * ======================================================== * * bpp - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -812,12 +812,12 @@ MPCC_MODULE(NewOSPreprocessor) { if (argv[index][0] == '-') { if (strcmp(argv[index], "-v") == 0) { - printf("%s\n", "bpp v1.11, (c) Mahrouss Logic"); + printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); return 0; } if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) Mahrouss Logic"); + printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); printf("%s\n", "-working-dir : set directory to working path."); printf("%s\n", "-include-dir : add directory to include path."); printf("%s\n", "-def : def macro."); diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 952be69..4b1545b 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index e729f54..c464b9f 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -2,7 +2,7 @@ * ======================================================== * * ccplus - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Mahrouss C++ Compiler, Copyright Mahrouss Logic.") + kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") #include #include @@ -29,9 +29,9 @@ #define kOk 0 -/* Mahrouss Logic C++ driver */ +/* SoftwareLabs C++ driver */ /* This is part of CodeTools C++ compiler. */ -/* (c) Mahrouss Logic */ +/* (c) SoftwareLabs */ // @author Amlal El Mahrouss (amlel) // @file cc.cc @@ -152,7 +152,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for Mahrouss Logic C++ */ +/* @brief C++ compiler backend for SoftwareLabs C++ */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: explicit CompilerBackendCPlusPlus() = default; diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index 77568dc..5f838be 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 4f5d885..53ca13e 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ @@ -160,11 +160,11 @@ MPCC_MODULE(NewOSAssemblerAMD64) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 Mahrouss Logic.\n"; + "(c) 2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "Mahrouss Logic.\n"; + "SoftwareLabs.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/Sources/link.cc b/Sources/link.cc index c44350a..13e1db1 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ /// @file link.cc /// @author Amlal El Mahrouss (amlel) -/// @brief Mahrouss Linker. +/// @brief SoftwareLabs Linker. /// Last Rev: Sat Feb 24 CET 2024 @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Mahrouss Linker %s, (c) Mahrouss Logic 2024\n" +#define kLinkerVersion "SoftwareLabs Linker %s, (c) SoftwareLabs 2024\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -184,7 +184,7 @@ MPCC_MODULE(NewOSLinker) { pef_container.Count = 0UL; pef_container.Kind = CompilerKit::kPefKindExec; pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Mahrouss Logic Linker + pef_container.Linker = kLinkerId; // SoftwareLabs Linker pef_container.Abi = kAbi; // Multi-Processor UX ABI pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; pef_container.Magic[1] = kPefMagic[1]; diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc index 44489da..5bdb53e 100644 --- a/Sources/ppc-cc.cc +++ b/Sources/ppc-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Mahrouss Logic, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -1272,7 +1272,7 @@ class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) static void cc_print_help() { kSplashCxx(); } diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index fcf0a5d..6c1f367 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright SoftwareLabs ------------------------------------------- */ @@ -114,12 +114,11 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " - "2024 Mahrouss Logic.\n"; + "2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: Copyright (c) 2024 " - "Mahrouss " - "Logic.\n"; + "SoftwareLabs.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/bpp.rsrc b/bpp.rsrc index 255f805..6ed8ac5 100644 --- a/bpp.rsrc +++ b/bpp.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS Assembler Preprocessor." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewPreprocessor" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "bpp.exe" VALUE "ProductName", "NewPreprocessor" VALUE "ProductVersion", kDistVersion diff --git a/i64asm.rsrc b/i64asm.rsrc index 0a76070..2f981a6 100644 --- a/i64asm.rsrc +++ b/i64asm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS AMD64 assembler." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "i64asm.exe" VALUE "ProductName", "NewAssembler" VALUE "ProductVersion", kDistVersion diff --git a/link.rsrc b/link.rsrc index 4a0ad5d..9661b04 100644 --- a/link.rsrc +++ b/link.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS linker." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewLinker" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "link.exe" VALUE "ProductName", "NewLinker" VALUE "ProductVersion", kDistVersion diff --git a/posix.make b/posix.make index e8c877c..9138ae3 100644 --- a/posix.make +++ b/posix.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright Mahrouss Logic, all rights reserved. + # Copyright SoftwareLabs, all rights reserved. # # ======================================================== # @@ -72,7 +72,7 @@ linker: help: @echo "Compiler - Mahrouss Compilers." @echo "Preprocessor - Mahrouss Preprocessors." - @echo "linker - Mahrouss Linkers." + @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." .PHONY: clean diff --git a/ppc-cc.rsrc b/ppc-cc.rsrc index ea941f1..031dd4e 100644 --- a/ppc-cc.rsrc +++ b/ppc-cc.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS POWER C compiler." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewC" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "ppc-cc.exe" VALUE "ProductName", "NewC" VALUE "ProductVersion", kDistVersion diff --git a/ppcasm.rsrc b/ppcasm.rsrc index 552479f..4d3affe 100644 --- a/ppcasm.rsrc +++ b/ppcasm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "Mahrouss-Logic" + VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS POWER assembler." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" + VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "ppcasm.exe" VALUE "ProductName", "NewAssembler" VALUE "ProductVersion", kDistVersion diff --git a/win64.make b/win64.make index 5d49218..297dbb2 100644 --- a/win64.make +++ b/win64.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright Mahrouss Logic, all rights reserved. + # Copyright SoftwareLabs, all rights reserved. # # ======================================================== # @@ -80,7 +80,7 @@ linker: help: @echo "Compiler - Mahrouss Compilers." @echo "Preprocessor - Mahrouss Preprocessors." - @echo "linker - Mahrouss Linkers." + @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." .PHONY: clean -- cgit v1.2.3 From 992764412966eeff4296e086a3717053d86cae5e Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 10 May 2024 06:57:27 +0200 Subject: MHR-21: Refactor compiler code. Signed-off-by: Amlal El Mahrouss --- Sources/64x0-cc.cc | 2643 +++++++++++++++++++++++++++---------------------- Sources/coff2ae.cc | 3 +- Sources/cplusplus.cc | 614 ++++++------ Sources/ppc-cc.cc | 2683 ++++++++++++++++++++++++++++---------------------- 4 files changed, 3277 insertions(+), 2666 deletions(-) (limited to 'Sources') diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index e73bf4d..5566666 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -42,7 +42,7 @@ ///////////////////// #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -51,77 +51,93 @@ ///////////////////////////////////// -namespace detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlel -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList *fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace detail +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -134,11 +150,11 @@ static int kMachine = 0; ///////////////////////////////////////// -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// @@ -146,56 +162,67 @@ static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// -static std::vector kFileList; +static std::vector kFileList; static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; +class CompilerBackendCLang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; - MPCC_COPY_DEFAULT(CompilerBackendCLang); + MPCC_COPY_DEFAULT(CompilerBackendCLang); - std::string Check(const char *text, const char *file); - bool Compile(const std::string &text, const char *file) override; + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; - const char *Language() override { return "64k C"; } + const char* Language() override + { + return "64k C"; + } }; -static CompilerBackendCLang *kCompilerBackend = nullptr; +static CompilerBackendCLang* kCompilerBackend = nullptr; static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; +static std::vector kCompilerFunctions; static std::vector kCompilerTypes; -namespace detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace detail +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -204,892 +231,1090 @@ union double_cast final { ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerBackendCLang::Compile(const std::string &text, const char *file) { - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto &clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (textBuffer.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) { - if (textBuffer[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) { - if (textBuffer[value_index] == ';') break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, import "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword export .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (textBuffer[text_index] == ';' && kInStruct) continue; - - if (textBuffer.find("typedef ") != std::string::npos) continue; - - if (textBuffer[text_index] == '=' && kInStruct) { - detail::print_error("assignement of value in struct " + textBuffer, - file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto &ch : textBuffer) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (textBuffer.find("*") != std::string::npos) { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (textBuffer.find('=') != std::string::npos && !kInBraces) { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) { - if (textBuffer[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) { - if (textBuffer[text_index_2] == '\"') break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; - if (textBuffer[text_index_2] == ';') { - break; - } + if (substr.find('=') != std::string::npos) + { + break; + } - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') { - if (first_encountered != 2) { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; - ++first_encountered; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } - continue; - } + typeFound = true; + break; + } + } - if (textBuffer[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } + break; + } - substr += ","; - continue; - } + match_type += substr[y]; + } + } - substr += textBuffer[text_index_2]; - } + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } - for (auto &clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; + kInBraces = true; + ++kBracesCount; - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, import "; + syntaxLeaf.fUserValue += + kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword export .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error("assignement of value in struct " + textBuffer, + file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } + else + { + substr += "\tldw "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + if (var_to_find == kCompilerVariables.cend()) + { + ++kRegisterCounter; + + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } + + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + if (textBuffer[text_index] == '=') + break; + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); - if (clType.fName == "const") continue; + if (!args_buffer.empty()) + args += "\tldw r6, "; - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } + std::string register_type; + std::size_t index = 7UL; - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "import "); + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } + ++index; - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; + args += args_buffer; + args += "\n\tlda r19, "; + } + } - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; + continue; + } - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } + if (_text_i == '(') + break; - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + substr += _text_i; + } - if (textBuffer[text_index] == '=') break; - } + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; - // function handler. + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); - bool type_crossed = false; + syntaxLeaf.fUserValue += "export .code64 "; - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) { - if (textBuffer[idx] == ',') continue; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; - if (textBuffer[idx] == ' ') continue; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - if (textBuffer[idx] == ')') break; - } + fnFound = true; + } - for (char substr_first_index : textBuffer) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; + kCompilerFunctions.push_back(textBuffer); + } - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - if (!args_buffer.empty()) args += "\tldw r6, "; + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } - std::string register_type; - std::size_t index = 7UL; + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } - ++index; + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } + --kBracesCount; - args += args_buffer; - args += "\n\tlda r19, "; - } - } + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } - for (char _text_i : textBuffer) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } + if (kIfFound) + kIfFound = false; - continue; - } + if (kInStruct) + kInStruct = false; - if (_text_i == '(') break; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } - substr += _text_i; - } + syntaxLeaf.fUserValue.clear(); + } - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; + return true; } -static bool kShouldHaveBraces = false; +static bool kShouldHaveBraces = false; static std::string kFnName; -std::string CompilerBackendCLang::Check(const char *text, const char *file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto &forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto &variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto &var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto &fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } cc_next: - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (ParserKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } skip_braces_check: - for (auto &key : kCompilerTypes) { - if (ParserKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; + for (auto& key : kCompilerTypes) + { + if (ParserKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && + !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && + !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1100,156 +1325,186 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string &src, Int32 arch) override { - if (arch != AssemblyMountpointCLang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto &ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) { - kCompilerBackend->Compile(line_src, src.data()); - } else { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return -1; - - std::vector keywords = {"ldw", "stw", "lda", "sta", - "add", "dec", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - std::vector access_keywords = {"->", "."}; - - for (auto &access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) { - for (auto &struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto &keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto ® : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (ParserKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("import " + needle) != - std::string::npos) { - std::string range = "import " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("import " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArch64x0; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ldw", "stw", "lda", "sta", + "add", "dec", "mv"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (ParserKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (ParserKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (ParserKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import " + needle) != + std::string::npos) + { + std::string range = "import " + needle; + leaf.fUserValue.replace( + leaf.fUserValue.find("import " + needle), range.size(), + needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -1258,97 +1513,115 @@ class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) -static void cc_print_help() { kSplashCxx(); } +static void cc_print_help() +{ + kSplashCxx(); +} ///////////////////////////////////////////////////////////////////////////////////////// #define kExt ".c" -MPCC_MODULE(NewOSCompilerCLang64x0) { - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) return -1; - } - - return kOk; +MPCC_MODULE(NewOSCompilerCLang64x0) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArch64x0; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; } // Last rev 8-1-24 diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 4b1545b..59a99d4 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -15,7 +15,8 @@ ///////////////////////////////////////////////////////////////////////////////////////// -/// @brief COFF To AE entrypoint, the program/module starts here. +/// @file coff2ae.cc +/// @brief COFF To AE, the program/module starts here. ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index c464b9f..23df90e 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") + kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") #include #include @@ -44,7 +44,7 @@ ///////////////////// #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -53,73 +53,89 @@ ///////////////////////////////////// -namespace detail { -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Offset based struct/class -struct CompilerStructMap final { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail +namespace detail +{ + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Offset based struct/class + struct CompilerStructMap final + { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail static detail::CompilerState kState; -static SizeType kErrorLimit = 100; +static SizeType kErrorLimit = 100; static Int32 kAcceptableErrors = 0; -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) { - std::cout << kRed << "[ ccplus ] " << kWhite - << ((file == "ccplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType { - std::string fName; - std::string fValue; -}; -} // namespace detail +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ ccplus ] " << kWhite + << ((file == "ccplus") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank + << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType + { + std::string fName; + std::string fValue; + }; +} // namespace detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -132,10 +148,10 @@ static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; ///////////////////////////////////////// -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; static std::vector kKeywords; ///////////////////////////////////////// @@ -144,45 +160,53 @@ static std::vector kKeywords; ///////////////////////////////////////// -static std::vector kFileList; +static std::vector kFileList; static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static size_t kBracesCount = 0UL; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static size_t kBracesCount = 0UL; /* @brief C++ compiler backend for SoftwareLabs C++ */ -class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCPlusPlus() = default; - ~CompilerBackendCPlusPlus() override = default; +class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCPlusPlus() = default; + ~CompilerBackendCPlusPlus() override = default; - MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); + MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); - bool Compile(const std::string& text, const char* file) override; + bool Compile(const std::string& text, const char* file) override; - const char* Language() override; + const char* Language() override; }; /// compiler variables -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; +static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; +static std::vector kCompilerFunctions; /// detail namespaces -namespace detail { -union number_cast final { - number_cast(UInt64 raw) : raw(raw) {} - - char number[8]; - UInt64 raw; -}; -} // namespace detail - -const char* CompilerBackendCPlusPlus::Language() { return "C++"; } +namespace detail +{ + union number_cast final { + number_cast(UInt64 raw) + : raw(raw) + { + } + + char number[8]; + UInt64 raw; + }; +} // namespace detail + +const char* CompilerBackendCPlusPlus::Language() +{ + return "C++"; +} ///////////////////////////////////////////////////////////////////////////////////////// @@ -192,41 +216,47 @@ const char* CompilerBackendCPlusPlus::Language() { return "C++"; } ///////////////////////////////////////////////////////////////////////////////////////// bool CompilerBackendCPlusPlus::Compile(const std::string& text, - const char* file) { - if (text.empty()) return false; + const char* file) +{ + if (text.empty()) + return false; - // if (expr) - // int name = expr; - // expr; + // if (expr) + // int name = expr; + // expr; - std::size_t index = 0UL; - std::vector> keywords_list; + std::size_t index = 0UL; + std::vector> keywords_list; - bool found = false; + bool found = false; - for (auto& keyword : kKeywords) { - if (text.find(keyword.keyword_name) != std::string::npos) { - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; + for (auto& keyword : kKeywords) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; - found = true; - } - } + found = true; + } + } - if (!found) { - detail::print_error("syntax error: " + text, file); - } + if (!found) + { + detail::print_error("syntax error: " + text, file); + } - // TODO: sort keywords + // TODO: sort keywords - for (auto& keyword : keywords_list) { - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + for (auto& keyword : keywords_list) + { + auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); + } - return true; + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -237,192 +267,222 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointClang() = default; - ~AssemblyMountpointClang() override = default; +class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointClang() = default; + ~AssemblyMountpointClang() override = default; - MPCC_COPY_DEFAULT(AssemblyMountpointClang); + MPCC_COPY_DEFAULT(AssemblyMountpointClang); - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArchAMD64; - } + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchAMD64; + } - Int32 CompileToFormat(std::string& src, Int32 arch) override { - if (arch != AssemblyMountpointClang::Arch()) return -1; + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointClang::Arch()) + return -1; - if (kCompilerBackend == nullptr) return -1; + if (kCompilerBackend == nullptr) + return -1; - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; - for (auto& ch : src_file) { - if (ch == '.') { - break; - } + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } - dest += ch; - } + dest += ch; + } - /* According to PEF ABI. */ + /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[3]; + std::vector exts = kAsmFileExts; + dest += exts[3]; - kState.fOutputAssembly = std::make_unique(dest); + kState.fOutputAssembly = std::make_unique(dest); - auto fmt = CompilerKit::current_date(); + auto fmt = CompilerKit::current_date(); - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: CodeTools assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; - (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" - << "\n\n"; + (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "; Language: CodeTools assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; + (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" + << "\n\n"; - ParserKit::SyntaxLeafList syntax; + ParserKit::SyntaxLeafList syntax; - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + kState.fSyntaxTreeList.emplace_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - std::string source; + std::string source; - while (std::getline(src_fp, source)) { - // Compile into an object file. - kCompilerBackend->Compile(source.c_str(), src.data()); - } + while (std::getline(src_fp, source)) + { + // Compile into an object file. + kCompilerBackend->Compile(source.c_str(), src.data()); + } - for (auto& ast : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << ast.fUserValue; - } + for (auto& ast : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << ast.fUserValue; + } - if (kAcceptableErrors > 0) return -1; + if (kAcceptableErrors > 0) + return -1; - return kOk; - } + return kOk; + } }; ///////////////////////////////////////////////////////////////////////////////////////// -static void cxx_print_help() { - kSplashCxx(); - kPrintF("%s", "No help available, see:\r\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); +static void cxx_print_help() +{ + kSplashCxx(); + kPrintF("%s", "No help available, see:\r\n"); + kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); } ///////////////////////////////////////////////////////////////////////////////////////// -#define kExtListCxx \ - { ".cpp", ".cxx", ".cc", ".c++", ".cp" } - -MPCC_MODULE(CompilerCPlusPlus) { - bool skip = false; - - kKeywords.push_back({ .keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass }); - kKeywords.push_back({ .keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass }); - kKeywords.push_back({ .keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace }); - kKeywords.push_back({ .keyword_name = "typedef" , .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({ .keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({ .keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyStart }); - kKeywords.push_back({ .keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyEnd }); - kKeywords.push_back({ .keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable }); - kKeywords.push_back({ .keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign }); - kKeywords.push_back({ .keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant }); - kKeywords.push_back({ .keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess }); - kKeywords.push_back({ .keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess }); - kKeywords.push_back({ .keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator }); - kKeywords.push_back({ .keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr }); - kKeywords.push_back({ .keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier }); - kKeywords.push_back({ .keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); - kKeywords.push_back({ .keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); - kKeywords.push_back({ .keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier }); - kKeywords.push_back({ .keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier }); - - kFactory.Mount(new AssemblyMountpointClang()); - kCompilerBackend = new CompilerBackendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) { - if (argv[index][0] == '-') { - if (skip) { - skip = false; - continue; - } - - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cxx_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-max-errors") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - detail::print_error(err, "ccplus"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - bool found = false; - - for (std::string ext : exts) { - if (argv_i.find(ext) != std::string::npos) { - found = true; - break; - } - } - - if (!found) { - if (kState.fVerbose) { - detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) return -1; - } - - return kOk; +#define kExtListCxx \ + { \ + ".cpp", ".cxx", ".cc", ".c++", ".cp" \ + } + +MPCC_MODULE(CompilerCPlusPlus) +{ + bool skip = false; + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); + kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + + kFactory.Mount(new AssemblyMountpointClang()); + kCompilerBackend = new CompilerBackendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) + { + if (argv[index][0] == '-') + { + if (skip) + { + skip = false; + continue; + } + + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cxx_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-max-errors") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + detail::print_error(err, "ccplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + bool found = false; + + for (std::string ext : exts) + { + if (argv_i.find(ext) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + if (kState.fVerbose) + { + detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); + } + + return 1; + } + + if (kFactory.Compile(argv_i, kMachine) != kOk) + return -1; + } + + return kOk; } // Last rev 8-1-24 diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc index 5bdb53e..31dc359 100644 --- a/Sources/ppc-cc.cc +++ b/Sources/ppc-cc.cc @@ -33,7 +33,7 @@ ///////////////////// #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -42,75 +42,91 @@ ///////////////////////////////////// -namespace detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlel -struct CompilerStructMap final { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList *fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) file.erase(file.find(".pp"), 3); - - if (kState.fLastFile != file) { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace detail +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + file.erase(file.find(".pp"), 3); + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -123,11 +139,11 @@ static int kMachine = 0; ///////////////////////////////////////// -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// @@ -135,56 +151,67 @@ static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// -static std::vector kFileList; +static std::vector kFileList; static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; +class CompilerBackendCLang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; - MPCC_COPY_DEFAULT(CompilerBackendCLang); + MPCC_COPY_DEFAULT(CompilerBackendCLang); - std::string Check(const char *text, const char *file); - bool Compile(const std::string &text, const char *file) override; + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; - const char *Language() override { return "POWER C"; } + const char* Language() override + { + return "POWER C"; + } }; -static CompilerBackendCLang *kCompilerBackend = nullptr; +static CompilerBackendCLang* kCompilerBackend = nullptr; static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; +static std::vector kCompilerFunctions; static std::vector kCompilerTypes; -namespace detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace detail +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -193,920 +220,1122 @@ union double_cast final { ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerBackendCLang::Compile(const std::string &text, const char *file) { - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto &clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (textBuffer.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) { - if (textBuffer[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) { - if (textBuffer[value_index] == ';') break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("import") != std::string::npos) - value.erase(value.find("import"), strlen("import")); - - bool found = false; - - for (auto ® : kState.kStackFrame) { - if (value.find(reg.fName) != std::string::npos) { - found = true; - syntaxLeaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) syntaxLeaf.fUserValue += "r0"; - } - - syntaxLeaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + - " \ndword export .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (textBuffer[text_index] == ';' && kInStruct) continue; - - if (textBuffer.find("typedef ") != std::string::npos) continue; - - if (textBuffer[text_index] == '=' && kInStruct) { - detail::print_error( - "assignement of value inside a struct " + textBuffer, file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto &ch : textBuffer) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (textBuffer.find("*") != std::string::npos) { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } else { - substr += "\tli "; - } - } else if (textBuffer.find('=') != std::string::npos && !kInBraces) { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) { - if (textBuffer[text_index_2] == '\"') { - ++text_index_2; +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } - for (; text_index_2 < textBuffer.size(); ++text_index_2) { - if (textBuffer[text_index_2] == '\"') break; + match_type += substr[y]; + } + } - substr += textBuffer[text_index_2]; - } - } + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; + std::size_t index = 0UL; + + std::string value; - if (textBuffer[text_index_2] == ';') { - break; - } + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) + value.erase(value.find(' '), 1); + + while (value.find("import") != std::string::npos) + value.erase(value.find("import"), strlen("import")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) + { + if (value.find(reg.fName) != std::string::npos) + { + found = true; + syntaxLeaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) + syntaxLeaf.fUserValue += "r0"; + } + + syntaxLeaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + + " \ndword export .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error( + "assignement of value inside a struct " + textBuffer, file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } + else + { + substr += "\tli "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + kCompilerVariables.push_back({.fName = substr}); + + if (textBuffer[text_index] == ';') + break; + + std::string reg = kAsmRegisterPrefix; + + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); + + auto newSubstr = substr.substr(substr.find(" ")); + + std::string symbol; + + for (size_t start = 0; start < newSubstr.size(); ++start) + { + if (newSubstr[start] == ',') + break; + + if (newSubstr[start] == ' ') + continue; + + symbol += (newSubstr[start]); + } + + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + + syntaxLeaf.fUserValue += + "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') { - if (first_encountered != 2) { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } + // function handler. - ++first_encountered; + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; - continue; - } + bool type_crossed = false; - if (textBuffer[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; - substr += ","; - continue; - } + if (textBuffer[idx] == ' ') + continue; - substr += textBuffer[text_index_2]; - } + if (textBuffer[idx] == ')') + break; + } - for (auto &clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); - if (clType.fName == "const") continue; + if (!args_buffer.empty()) + args += "\tldw r6, "; - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } + std::string register_type; + std::size_t index = 7UL; - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "import "); + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } + ++index; - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } - kCompilerVariables.push_back({.fName = substr}); + args += args_buffer; + args += "\n\tli r31, "; + } + } - if (textBuffer[text_index] == ';') break; + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } - std::string reg = kAsmRegisterPrefix; + continue; + } - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); + if (_text_i == '(') + break; - auto newSubstr = substr.substr(substr.find(" ")); + substr += _text_i; + } - std::string symbol; + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; - for (size_t start = 0; start < newSubstr.size(); ++start) { - if (newSubstr[start] == ',') break; + syntaxLeaf.fUserValue += "\n\tblr\n"; - if (newSubstr[start] == ' ') continue; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - symbol += (newSubstr[start]); - } + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + syntaxLeaf.fUserValue += "export .code64 "; - syntaxLeaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; - // function handler. + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; + fnFound = true; + } - bool type_crossed = false; + kCompilerFunctions.push_back(textBuffer); + } - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) { - if (textBuffer[idx] == ',') continue; + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - if (textBuffer[idx] == ' ') continue; + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } - if (textBuffer[idx] == ')') break; - } + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; - for (char substr_first_index : textBuffer) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; - if (!args_buffer.empty()) args += "\tldw r6, "; + --kBracesCount; - std::string register_type; - std::size_t index = 7UL; + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); + if (kIfFound) + kIfFound = false; - ++index; + if (kInStruct) + kInStruct = false; - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } - args += args_buffer; - args += "\n\tli r31, "; - } - } + syntaxLeaf.fUserValue.clear(); + } - for (char _text_i : textBuffer) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - - syntaxLeaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; + return true; } -static bool kShouldHaveBraces = false; +static bool kShouldHaveBraces = false; static std::string kFnName; -std::string CompilerBackendCLang::Check(const char *text, const char *file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto &forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto &variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto &var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto &fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } cc_next: - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (ParserKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } skip_braces_check: - for (auto &key : kCompilerTypes) { - if (ParserKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; + for (auto& key : kCompilerTypes) + { + if (ParserKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && + !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && + !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1117,153 +1346,183 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string &src, Int32 arch) override { - if (arch != AssemblyMountpointCLang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto &ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) { - kCompilerBackend->Compile(line_src, src.data()); - } else { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return -1; - - std::vector keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - std::vector access_keywords = {"->", "."}; - - for (auto &access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) { - for (auto &struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto &keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto ® : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (ParserKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("import ") != std::string::npos) { - std::string range = "import "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ld", "stw", "add", "sub", "or"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (ParserKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (ParserKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (ParserKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import ") != std::string::npos) + { + std::string range = "import "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), + range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -1272,97 +1531,115 @@ class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) -static void cc_print_help() { kSplashCxx(); } +static void cc_print_help() +{ + kSplashCxx(); +} ///////////////////////////////////////////////////////////////////////////////////////// #define kExt ".c" -MPCC_MODULE(NewOSCompilerCLangPowerPC) { - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) return -1; - } - - return kOk; +MPCC_MODULE(NewOSCompilerCLangPowerPC) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; } // Last rev 8-1-24 -- cgit v1.2.3 From 543b8c7287ac1248453a59cd3d759ce5ffeec4a3 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 11 May 2024 15:10:23 +0200 Subject: MHR-21: Work in progress code generator. Signed-off-by: Amlal El Mahrouss --- Doxyfile | 2 +- Examples/ExampleCPlusPlus.cxx | 11 +++++++ Examples/ExampleCPlusPlus.s | 14 ++++++++ Headers/ParserKit.hpp | 9 ++++-- ReadMe.md | 2 +- SDK/__mpcc_power.inc | 2 +- Sources/64x0-cc.cc | 2 +- Sources/cplusplus.cc | 75 +++++++++++++++++++++++++++++++++++-------- posix.make | 7 ++-- win64.make | 4 +-- 10 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 Examples/ExampleCPlusPlus.cxx create mode 100644 Examples/ExampleCPlusPlus.s (limited to 'Sources') diff --git a/Doxyfile b/Doxyfile index 676281e..d2e6878 100644 --- a/Doxyfile +++ b/Doxyfile @@ -54,7 +54,7 @@ PROJECT_NUMBER = 2.0.0 # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "CodeTools" +PROJECT_BRIEF = "MPCC" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx new file mode 100644 index 0000000..38bf0c5 --- /dev/null +++ b/Examples/ExampleCPlusPlus.cxx @@ -0,0 +1,11 @@ +int main(int argc, char const *argv[]) +{ + struct ExampleCPlusPlus + { + int example_data; + }* example; + + example->example_data = 0; + + return 0; +} diff --git a/Examples/ExampleCPlusPlus.s b/Examples/ExampleCPlusPlus.s new file mode 100644 index 0000000..328bce7 --- /dev/null +++ b/Examples/ExampleCPlusPlus.s @@ -0,0 +1,14 @@ +; Path: Examples/ExampleCPlusPlus.cxx +; Language: MPCC assembly. (Generated from C++) +; Date: 2024-5-11 + +#bits 64 + +#org 0x1000000 + + + +lea %LEFT+%OFFSET + +mov rax, %A0 +ret \ No newline at end of file diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index 60ac892..f14ed69 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -43,11 +43,13 @@ namespace ParserKit struct CompilerKeyword; /// we want to do that because to separate keywords. - enum + enum KeywordKind { eKeywordKindNamespace, - eKeywordKindFunction, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, eKeywordKindVariable, + eKeywordKindType, eKeywordKindExpressionBegin, eKeywordKindExpressionEnd, eKeywordKindArgSeparator, @@ -65,13 +67,14 @@ namespace ParserKit eKeywordKindEndInstr, eKeywordKindSpecifier, eKeywordKindInvalid, + eKeywordKindReturn, }; /// \brief Compiler keyword information struct. struct CompilerKeyword { std::string keyword_name; - int32_t keyword_kind = eKeywordKindInvalid; + KeywordKind keyword_kind = eKeywordKindInvalid; }; struct SyntaxLeafList final { diff --git a/ReadMe.md b/ReadMe.md index 4c5f385..82b3217 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,4 +1,4 @@ -# CodeTools +# MPCC Start by cloning the repo: diff --git a/SDK/__mpcc_power.inc b/SDK/__mpcc_power.inc index 96403a4..9e4928c 100644 --- a/SDK/__mpcc_power.inc +++ b/SDK/__mpcc_power.inc @@ -1,5 +1,5 @@ # Path: SDK/__mpcc_power.inc -# Language: Mahrouss POWER Assembly support for GNU. +# Language: MPCC POWER Assembly support for GNU. # Build Date: 2024-6-4 %ifdef __CODETOOLS__ diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 5566666..b7ea908 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -26,7 +26,7 @@ #define kOk 0 /* C driver */ -/* This is part of CodeTools C SDK. */ +/* This is part of MPCC C SDK. */ /* (c) SoftwareLabs */ /// @author Amlal El Mahrouss (amlel) diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 23df90e..b61b1d2 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -30,7 +30,7 @@ #define kOk 0 /* SoftwareLabs C++ driver */ -/* This is part of CodeTools C++ compiler. */ +/* This is part of MPCC C++ compiler. */ /* (c) SoftwareLabs */ // @author Amlal El Mahrouss (amlel) @@ -94,9 +94,9 @@ static Int32 kAcceptableErrors = 0; namespace detail { - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? void print_error(std::string reason, std::string file) noexcept { if (reason[0] == '\n') @@ -205,7 +205,7 @@ namespace detail const char* CompilerBackendCPlusPlus::Language() { - return "C++"; + return "ISO C++"; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -243,19 +243,58 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (!found) { - detail::print_error("syntax error: " + text, file); + for (size_t i = 0; i < text.size(); i++) + { + if (isalnum(text[i])) + { + detail::print_error("syntax error: " + text, file); + return false; + } + } } - // TODO: sort keywords + static bool shouldEmitWarning = false; for (auto& keyword : keywords_list) { + if (shouldEmitWarning) + { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindBodyEnd) + shouldEmitWarning = false; + + if (shouldEmitWarning) + { + detail::print_error("code after return: " + text, file); + } + } + auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + switch (keyword.first.keyword_kind) + { + case ParserKit::KeywordKind::eKeywordKindAccess: + case ParserKit::KeywordKind::eKeywordKindPtrAccess: + kState.fSyntaxTree->fLeafList[kState.fSyntaxTree->fLeafList.size() - 1].fUserValue = "lea %LEFT+%OFFSET"; // MPCC assembly stipulates this. + break; + case ParserKit::KeywordKind::eKeywordKindEndInstr: + syntax_tree.fUserValue = "\r\n"; + break; + case ParserKit::KeywordKind::eKeywordKindVariableAssign: + syntax_tree.fUserValue = "mov %LEFT, %RIGHT"; + break; + case ParserKit::KeywordKind::eKeywordKindReturn: + syntax_tree.fUserValue = "mov rax, %A0\r\nret"; + shouldEmitWarning = true; + break; + default: + break; + } + syntax_tree.fUserData = keyword.first; kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); } +_MpccOkay: return true; } @@ -303,8 +342,6 @@ public: dest += ch; } - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; dest += exts[3]; @@ -314,7 +351,7 @@ public: (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; (*kState.fOutputAssembly) - << "; Language: CodeTools assembly. (Generated from C++)\n"; + << "; Language: MPCC assembly. (Generated from C++)\n"; (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" << "\n\n"; @@ -330,7 +367,7 @@ public: while (std::getline(src_fp, source)) { // Compile into an object file. - kCompilerBackend->Compile(source.c_str(), src.data()); + kCompilerBackend->Compile(source.c_str(), src.c_str()); } for (auto& ast : kState.fSyntaxTree->fLeafList) @@ -351,7 +388,7 @@ static void cxx_print_help() { kSplashCxx(); kPrintF("%s", "No help available, see:\r\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); + kPrintF("%s", "www.el-mahrouss-logic.com/softwarelabs/developer/newos/cplusplus\r\n"); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -370,9 +407,18 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = ParserKit::eKeywordKindTypedef}); kKeywords.push_back({.keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); @@ -384,6 +430,7 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = ParserKit::eKeywordKindReturn}); kFactory.Mount(new AssemblyMountpointClang()); kCompilerBackend = new CompilerBackendCPlusPlus(); diff --git a/posix.make b/posix.make index 9138ae3..7c937b8 100644 --- a/posix.make +++ b/posix.make @@ -14,6 +14,7 @@ LINK_OUTPUT=Output/link.exec LINK_ALT_OUTPUT=Output/64link.exec LINK_ALT_3_OUTPUT=Output/i64link.exec LINK_ALT_2_OUTPUT=Output/32link.exec +LINK_ALT_4_OUTPUT=Output/ppclink.exec PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exec @@ -67,11 +68,12 @@ linker: cp $(LINK_OUTPUT) $(LINK_ALT_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_2_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_3_OUTPUT) + cp $(LINK_OUTPUT) $(LINK_ALT_4_OUTPUT) .PHONY: help help: - @echo "Compiler - Mahrouss Compilers." - @echo "Preprocessor - Mahrouss Preprocessors." + @echo "Compiler - MPCC Compiler Suite." + @echo "Preprocessor - MPCC Preprocessor Suite." @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." @@ -84,6 +86,7 @@ clean: rm -f $(IASM_OUTPUT) rm -f $(LINK_OUTPUT) rm -rf *.obj + rm -rf Output/*.exec rm -rf *.exec # Last rev 8-1-24 diff --git a/win64.make b/win64.make index 297dbb2..79f46a4 100644 --- a/win64.make +++ b/win64.make @@ -78,8 +78,8 @@ linker: .PHONY: help help: - @echo "Compiler - Mahrouss Compilers." - @echo "Preprocessor - Mahrouss Preprocessors." + @echo "Compiler - MPCC Compiler Suite." + @echo "Preprocessor - MPCC Preprocessor Suite." @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." -- cgit v1.2.3 From 28dc20ee517dbbf98bd741fc2dfa24c82281d754 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sun, 12 May 2024 18:53:08 +0200 Subject: MHR-21: Lots of improvements and changes to the C++ compiler. Signed-off-by: Amlal El Mahrouss --- Examples/ExampleCPlusPlus.cxx | 17 +- Examples/ExampleCPlusPlus.s | 12 +- Headers/AsmKit/CPU/64x0.hpp | 33 ++-- Headers/AsmKit/CPU/amd64.hpp | 29 ++-- Headers/ParserKit.hpp | 7 +- Sources/64asm.cc | 2 +- Sources/64x0-cc.cc | 6 +- Sources/AsmKit.cc | 51 ------ Sources/AssemblyFactory.cxx | 51 ++++++ Sources/cplusplus.cc | 353 ++++++++++++++++++++++++++++++++++++++---- posix.make | 2 +- win64.make | 2 +- 12 files changed, 432 insertions(+), 133 deletions(-) delete mode 100644 Sources/AsmKit.cc create mode 100644 Sources/AssemblyFactory.cxx (limited to 'Sources') diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx index 38bf0c5..b54786d 100644 --- a/Examples/ExampleCPlusPlus.cxx +++ b/Examples/ExampleCPlusPlus.cxx @@ -1,11 +1,14 @@ -int main(int argc, char const *argv[]) +int main(int argc, char const* argv[]) { - struct ExampleCPlusPlus - { - int example_data; - }* example; + int foo = 20; + foo -= 1; - example->example_data = 0; + { + bool bar = false; + bar = true; - return 0; + bool bar2 = bar; + } + + return foo; } diff --git a/Examples/ExampleCPlusPlus.s b/Examples/ExampleCPlusPlus.s index 328bce7..4b69908 100644 --- a/Examples/ExampleCPlusPlus.s +++ b/Examples/ExampleCPlusPlus.s @@ -1,14 +1,16 @@ ; Path: Examples/ExampleCPlusPlus.cxx ; Language: MPCC assembly. (Generated from C++) -; Date: 2024-5-11 +; Date: 2024-5-12 #bits 64 #org 0x1000000 +mov r8, 20 +sub r8, 1 +mov r9, 0 +mov r9, 1 +mov r10, r9 - -lea %LEFT+%OFFSET - -mov rax, %A0 +mov rax, r10 ret \ No newline at end of file diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp index 3f173ef..58ab76d 100644 --- a/Headers/AsmKit/CPU/64x0.hpp +++ b/Headers/AsmKit/CPU/64x0.hpp @@ -42,27 +42,26 @@ inline std::vector kOpcodes64x0 = { kAsmJump) // jump to linked return register kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) // add/sub without carry flag kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("dec", 0b0101011, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) // add/sub with carry flag kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) - kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) - kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs) -}; + kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) + kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) + kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; // \brief 64x0 register prefix // example: r32, r0 diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp index 403583c..be5a657 100644 --- a/Headers/AsmKit/CPU/amd64.hpp +++ b/Headers/AsmKit/CPU/amd64.hpp @@ -38,20 +38,19 @@ struct CpuOpcodeAMD64 #define kJumpLimitStandardLimit 0xEB inline std::vector kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF) -}; + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF)}; #define kAsmRegisterLimit 15 diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index f14ed69..9f04d11 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -62,19 +62,24 @@ namespace ParserKit eKeywordKindElse, eKeywordKindElseIf, eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, eKeywordKindConstant, eKeywordKindTypedef, eKeywordKindEndInstr, eKeywordKindSpecifier, eKeywordKindInvalid, eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, }; /// \brief Compiler keyword information struct. struct CompilerKeyword { std::string keyword_name; - KeywordKind keyword_kind = eKeywordKindInvalid; + KeywordKind keyword_kind = eKeywordKindInvalid; }; struct SyntaxLeafList final { diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 8f42ea2..96bdc90 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -763,7 +763,7 @@ bool CompilerKit::Encoder64x0::WriteLine(std::string &line, "invalid combination of opcode and registers.\nline: " + line, file); throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "dec") { + } else if (found_some == 1 && name == "sub") { detail::print_error( "invalid combination of opcode and registers.\nline: " + line, file); diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index b7ea908..d7b7491 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -736,7 +736,7 @@ bool CompilerBackendCLang::Compile(const std::string& text, const char* file) textBuffer.erase(_text_i, 1); } - syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += "sub "; syntaxLeaf.fUserValue += textBuffer; kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); @@ -1399,7 +1399,7 @@ public: return -1; std::vector keywords = {"ldw", "stw", "lda", "sta", - "add", "dec", "mv"}; + "add", "sub", "mv"}; /// /// Replace, optimize, fix assembly output. @@ -1484,7 +1484,7 @@ public: } if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "dec") + keyword != "sub") { leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); diff --git a/Sources/AsmKit.cc b/Sources/AsmKit.cc deleted file mode 100644 index 38ca551..0000000 --- a/Sources/AsmKit.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#include -#include - -/** - * @file AsmKit.cc - * @author Amlal El Mahrouss (amlal@mahrouss.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, SoftwareLabs - * - */ - -#include - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit { -//! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept { - if (sourceFile.length() < 1 || !fMounted) return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); -} - -//! @brief mount assembly backend. -void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { - if (mountPtr) { - fMounted = mountPtr; - } -} - -AssemblyInterface* AssemblyFactory::Unmount() noexcept { - auto mount_prev = fMounted; - - if (mount_prev) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx new file mode 100644 index 0000000..5a1475f --- /dev/null +++ b/Sources/AssemblyFactory.cxx @@ -0,0 +1,51 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cxx + * @author Amlal El Mahrouss (amlal@mahrouss.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, SoftwareLabs + * + */ + +#include + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit { +//! @brief Compile for specific format (ELF, PEF, ZBIN) +Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept { + if (sourceFile.length() < 1 || !fMounted) return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); +} + +//! @brief mount assembly backend. +void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { + if (mountPtr) { + fMounted = mountPtr; + } +} + +AssemblyInterface* AssemblyFactory::Unmount() noexcept { + auto mount_prev = fMounted; + + if (mount_prev) { + fMounted = nullptr; + } + + return mount_prev; +} +} // namespace CompilerKit diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index b61b1d2..14a7af7 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -33,9 +33,11 @@ /* This is part of MPCC C++ compiler. */ /* (c) SoftwareLabs */ -// @author Amlal El Mahrouss (amlel) -// @file cc.cc -// @brief Optimized C++ Compiler. +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cc +/// @brief Optimized C++ Compiler. +/// @todo Throw error for scoped inside scoped variables when they get referenced outside. +/// @todo Add class/struct/enum support. ///////////////////// @@ -110,8 +112,8 @@ namespace detail if (kState.fLastFile != file) { std::cout << kRed << "[ ccplus ] " << kWhite - << ((file == "ccplus") ? "internal compiler error " - : ("in file, " + file)) + << ((file == "cplusplus") ? "internal compiler error " + : ("in file, " + file)) << kBlank << std::endl; std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank << std::endl; @@ -208,10 +210,25 @@ const char* CompilerBackendCPlusPlus::Language() return "ISO C++"; } +static std::vector kRegisterMap; + +static size_t kLevelFunction = 0UL; + +static std::vector cRegisters = { + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", +}; + ///////////////////////////////////////////////////////////////////////////////////////// -// @name Compile -// @brief Generate MASM from a C++ source. +/// @name Compile +/// @brief Generate MASM from a C++ source. ///////////////////////////////////////////////////////////////////////////////////////// @@ -228,12 +245,39 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, std::size_t index = 0UL; std::vector> keywords_list; - bool found = false; + bool found = false; + static bool commentBlock = false; for (auto& keyword : kKeywords) { if (text.find(keyword.keyword_name) != std::string::npos) { + switch (keyword.keyword_kind) + { + case ParserKit::eKeywordKindCommentMultiLineStart: { + commentBlock = true; + return true; + } + case ParserKit::eKeywordKindCommentMultiLineEnd: { + commentBlock = false; + break; + } + case ParserKit::eKeywordKindCommentInline: { + break; + } + default: + break; + } + + if (text[text.find(keyword.keyword_name) - 1] == '+' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if ( + text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + keywords_list.emplace_back(std::make_pair(keyword, index)); ++index; @@ -241,7 +285,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } } - if (!found) + if (!found && !commentBlock) { for (size_t i = 0; i < text.size(); i++) { @@ -253,39 +297,280 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } } - static bool shouldEmitWarning = false; - for (auto& keyword : keywords_list) { - if (shouldEmitWarning) - { - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindBodyEnd) - shouldEmitWarning = false; - - if (shouldEmitWarning) - { - detail::print_error("code after return: " + text, file); - } - } - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); switch (keyword.first.keyword_kind) { - case ParserKit::KeywordKind::eKeywordKindAccess: - case ParserKit::KeywordKind::eKeywordKindPtrAccess: - kState.fSyntaxTree->fLeafList[kState.fSyntaxTree->fLeafList.size() - 1].fUserValue = "lea %LEFT+%OFFSET"; // MPCC assembly stipulates this. - break; case ParserKit::KeywordKind::eKeywordKindEndInstr: syntax_tree.fUserValue = "\r\n"; break; - case ParserKit::KeywordKind::eKeywordKindVariableAssign: - syntax_tree.fUserValue = "mov %LEFT, %RIGHT"; + case ParserKit::KeywordKind::eKeywordKindFunctionStart: { + ++kLevelFunction; break; - case ParserKit::KeywordKind::eKeywordKindReturn: - syntax_tree.fUserValue = "mov rax, %A0\r\nret"; - shouldEmitWarning = true; + } + case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { + --kLevelFunction; + + if (kRegisterMap.size() > cRegisters.size()) + { + --kLevelFunction; + } + + if (kLevelFunction < 1) + kRegisterMap.clear(); break; + } + case ParserKit::KeywordKind::eKeywordKindVariableInc: + case ParserKit::KeywordKind::eKeywordKindVariableDec: + case ParserKit::KeywordKind::eKeywordKindVariableAssign: { + auto valueOfVar = text.substr(text.find("=") + 1); + + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + valueOfVar = text.substr(text.find("+=") + 2); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + valueOfVar = text.substr(text.find("-=") + 2); + } + + while (valueOfVar.find(";") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find(";")); + } + + if (text.find("float ") != std::string::npos || + text.find("double ") != std::string::npos) + { + detail::print_error("Vector extensions not supported yet.", "cplusplus"); + } + + std::string varName = text; + + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + varName.erase(varName.find("+=")); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + varName.erase(varName.find("-=")); + } + else + { + varName.erase(varName.find("=")); + } + + bool typeFound = false; + + for (auto& keyword : kKeywords) + { + if (keyword.keyword_kind == ParserKit::eKeywordKindType) + { + if (varName.find(keyword.keyword_name) != std::string::npos) + { + typeFound = true; + varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); + } + + /// in case we goot boolX or intX + if (text.find(keyword.keyword_name) != std::string::npos) + { + if (varName[text.find(keyword.keyword_name)] == ' ') + continue; + + typeFound = false; + } + } + } + + std::string instr = "mov "; + + if (typeFound) + { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + detail::print_error("Can't increment variable when it's being created.", file); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + detail::print_error("Can't decrement variable when it's being created.", file); + } + + if (kRegisterMap.size() > cRegisters.size()) + { + ++kLevelFunction; + } + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + if (valueOfVar == "true") + { + valueOfVar = "1"; + } + else if (valueOfVar == "false") + { + valueOfVar = "0"; + } + + std::size_t indexRight = 0UL; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1]; + break; + } + + if (((int)indexRight - 1) < 0) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar; + } + + kRegisterMap.push_back(varName); + } + else + { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + instr = "add "; + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + instr = "sub "; + } + + std::string varErrCpy = varName; + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + std::size_t indxReg = 0UL; + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + /// interpet boolean values. + + if (valueOfVar == "true") + { + valueOfVar = "1"; + } + else if (valueOfVar == "false") + { + valueOfVar = "0"; + } + + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != varName) + continue; + + std::size_t indexRight = 0ul; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1]; + break; + } + + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + varErrCpy, file); + } + } + + break; + } + case ParserKit::KeywordKind::eKeywordKindReturn: { + auto pos = text.find("return") + strlen("return") + 1; + std::string subText = text.substr(pos); + subText = subText.erase(subText.find(";")); + size_t indxReg = 0UL; + + if (subText[0] != '\"' && + subText[0] != '\'') + { + if (!isdigit(subText[0])) + { + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != subText) + continue; + + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret"; + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + subText, file); + } + } + else + { + syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret"; + } + } + else + { + syntax_tree.fUserValue = "mov rcx, " + subText + "\r\n"; + syntax_tree.fUserValue = "mov rax, rcx\r\nret"; + } + + break; + } default: break; } @@ -411,6 +696,7 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); kKeywords.push_back({.keyword_name = "int", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); @@ -420,6 +706,8 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = ParserKit::eKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = ParserKit::eKeywordKindVariableDec}); kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); @@ -431,6 +719,9 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); kKeywords.push_back({.keyword_name = "return", .keyword_kind = ParserKit::eKeywordKindReturn}); + kKeywords.push_back({.keyword_name = "/*", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "*/", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "//", .keyword_kind = ParserKit::eKeywordKindCommentInline}); kFactory.Mount(new AssemblyMountpointClang()); kCompilerBackend = new CompilerBackendCPlusPlus(); diff --git a/posix.make b/posix.make index 7c937b8..42e0ece 100644 --- a/posix.make +++ b/posix.make @@ -19,7 +19,7 @@ LINK_ALT_4_OUTPUT=Output/ppclink.exec PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exec -SRC_COMMON=Sources/String.cc Sources/AsmKit.cc +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) diff --git a/win64.make b/win64.make index 79f46a4..4abac3e 100644 --- a/win64.make +++ b/win64.make @@ -19,7 +19,7 @@ LINK_ALT_2_OUTPUT=Output/32link.exe PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cc Sources/AsmKit.cc +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) -- cgit v1.2.3 From b225a0c3c0e6c286a69356c957c5f9d73a28647c Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 14 May 2024 09:04:23 +0200 Subject: MHR-21: Update doxygen. Signed-off-by: Amlal El Mahrouss --- Doxyfile | 2 +- Examples/ExampleCPlusPlus.cxx | 2 +- Sources/AssemblyFactory.cxx | 59 ++++++++++++++++++++++++------------------- 3 files changed, 35 insertions(+), 28 deletions(-) (limited to 'Sources') diff --git a/Doxyfile b/Doxyfile index d2e6878..2fddb4b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = NewOS Programmer Workshop +PROJECT_NAME = NewOS SDK # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx index b54786d..ebdf7c3 100644 --- a/Examples/ExampleCPlusPlus.cxx +++ b/Examples/ExampleCPlusPlus.cxx @@ -5,7 +5,7 @@ int main(int argc, char const* argv[]) { bool bar = false; - bar = true; + bar = true; bool bar2 = bar; } diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx index 5a1475f..d5c0da7 100644 --- a/Sources/AssemblyFactory.cxx +++ b/Sources/AssemblyFactory.cxx @@ -23,29 +23,36 @@ //! @file AsmKit.cpp //! @brief AssemblyKit source implementation. -namespace CompilerKit { -//! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept { - if (sourceFile.length() < 1 || !fMounted) return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); -} - -//! @brief mount assembly backend. -void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { - if (mountPtr) { - fMounted = mountPtr; - } -} - -AssemblyInterface* AssemblyFactory::Unmount() noexcept { - auto mount_prev = fMounted; - - if (mount_prev) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit +namespace CompilerKit +{ + //! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + //! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit -- cgit v1.2.3 From 583748c67453a62382e0c0e77aa8ca6535900ae0 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 14 May 2024 10:02:08 +0200 Subject: MHR-21: Add function signature to output (C++) Signed-off-by: Amlal El Mahrouss --- Examples/ExampleCDialect.S | 34 ++++--------- Examples/ExampleCDialect.c | 20 -------- Examples/ExampleCDialect.cc | 7 +++ Examples/ExampleCPlusPlus.cxx | 8 ++- Examples/ExampleCPlusPlus.s | 21 ++++---- Headers/ParserKit.hpp | 5 ++ Sources/cplusplus.cc | 111 ++++++++++++++++++++++++++++++------------ 7 files changed, 117 insertions(+), 89 deletions(-) delete mode 100644 Examples/ExampleCDialect.c create mode 100644 Examples/ExampleCDialect.cc (limited to 'Sources') diff --git a/Examples/ExampleCDialect.S b/Examples/ExampleCDialect.S index d937aed..9d90d46 100644 --- a/Examples/ExampleCDialect.S +++ b/Examples/ExampleCDialect.S @@ -1,28 +1,14 @@ -# Path: Examples/ExampleCDialect.c -# Language: POWER Assembly (Generated from C) -# Build Date: 2024-4-28 +; Path: Examples/ExampleCDialect.cc +; Language: MPCC assembly. (Generated from C++) +; Date: 2024-5-14 +#bits 64 +#org 0x1000000 +export .code64 __MPCC_int___ImageStart +mov r8, 0 - - - -dword export .code64 __ImageStart - - - li r3,0x1000 - - cmpw r10, r11 - beq import __MPCC_IF_PROC_6099380296 -dword export .code64 __MPCC_IF_PROC_6099380296 - - - - mr r31, r3 - blr - - - mr r31, r0 - blr - +mov r9, 36 +mov rax, r8 +ret diff --git a/Examples/ExampleCDialect.c b/Examples/ExampleCDialect.c deleted file mode 100644 index e6d92fb..0000000 --- a/Examples/ExampleCDialect.c +++ /dev/null @@ -1,20 +0,0 @@ -struct -{ - int a; - int b; - int c; -}; - -int __ImageStart(int argc, char const* argv[]) -{ - int* foo = 0x1000; - - if (foo == 57) - { - foo = 0x2000; - *foo = 5; - return foo; - } - - return 57; -} diff --git a/Examples/ExampleCDialect.cc b/Examples/ExampleCDialect.cc new file mode 100644 index 0000000..b55dd5f --- /dev/null +++ b/Examples/ExampleCDialect.cc @@ -0,0 +1,7 @@ +int __ImageStart(int argc, char const* argv[]) +{ + int *foo; + *foo = 36; + + return *foo; +} diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx index ebdf7c3..6012b52 100644 --- a/Examples/ExampleCPlusPlus.cxx +++ b/Examples/ExampleCPlusPlus.cxx @@ -1,14 +1,12 @@ int main(int argc, char const* argv[]) { - int foo = 20; - foo -= 1; - { bool bar = false; - bar = true; + bar = 1; bool bar2 = bar; + bar2 = false; } - return foo; + return 0; } diff --git a/Examples/ExampleCPlusPlus.s b/Examples/ExampleCPlusPlus.s index 4b69908..0414858 100644 --- a/Examples/ExampleCPlusPlus.s +++ b/Examples/ExampleCPlusPlus.s @@ -1,16 +1,19 @@ ; Path: Examples/ExampleCPlusPlus.cxx ; Language: MPCC assembly. (Generated from C++) -; Date: 2024-5-12 +; Date: 2024-5-14 #bits 64 #org 0x1000000 -mov r8, 20 -sub r8, 1 -mov r9, 0 -mov r9, 1 -mov r10, r9 - -mov rax, r10 -ret \ No newline at end of file +export .code64 __MPCC_int_main +mov r8, 0 +mov r9, 0 + +mov r10, 1 +mov r10, r8 +mov r11, 0 + +mov r12, 0 +mov rax, 0 +ret diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index 9f04d11..6a53edc 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -73,6 +73,11 @@ namespace ParserKit eKeywordKindCommentInline, eKeywordKindCommentMultiLineStart, eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, }; /// \brief Compiler keyword information struct. diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 14a7af7..592e54c 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -273,8 +273,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) continue; - if ( - text[text.find(keyword.keyword_name) - 1] == '-' && + if (text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) + 1] == '=' && keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) continue; @@ -303,10 +306,18 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, switch (keyword.first.keyword_kind) { - case ParserKit::KeywordKind::eKeywordKindEndInstr: - syntax_tree.fUserValue = "\r\n"; - break; case ParserKit::KeywordKind::eKeywordKindFunctionStart: { + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; + ++kLevelFunction; break; } @@ -322,10 +333,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, kRegisterMap.clear(); break; } + case ParserKit::KeywordKind::eKeywordKindEndInstr: case ParserKit::KeywordKind::eKeywordKindVariableInc: case ParserKit::KeywordKind::eKeywordKindVariableDec: case ParserKit::KeywordKind::eKeywordKindVariableAssign: { - auto valueOfVar = text.substr(text.find("=") + 1); + std::string valueOfVar = ""; if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) { @@ -335,16 +347,19 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, { valueOfVar = text.substr(text.find("-=") + 2); } - - while (valueOfVar.find(";") != std::string::npos) + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) { - valueOfVar.erase(valueOfVar.find(";")); + valueOfVar = text.substr(text.find("=") + 1); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + valueOfVar = "0\n"; } - if (text.find("float ") != std::string::npos || - text.find("double ") != std::string::npos) + while (valueOfVar.find(";") != std::string::npos && + keyword.first.keyword_kind != ParserKit::KeywordKind::eKeywordKindEndInstr) { - detail::print_error("Vector extensions not supported yet.", "cplusplus"); + valueOfVar.erase(valueOfVar.find(";")); } std::string varName = text; @@ -357,10 +372,14 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, { varName.erase(varName.find("-=")); } - else + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) { varName.erase(varName.find("=")); } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + varName.erase(varName.find(";")); + } bool typeFound = false; @@ -421,11 +440,14 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, valueOfVar.erase(i, 1); } - if (valueOfVar == "true") + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + if (valueOfVar == cTrueVal) { valueOfVar = "1"; } - else if (valueOfVar == "false") + else if (valueOfVar == cFalseVal) { valueOfVar = "0"; } @@ -438,23 +460,29 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (pairRight != valueOfVar) { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; continue; } - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1]; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1] + "\n"; break; } if (((int)indexRight - 1) < 0) { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; } kRegisterMap.push_back(varName); } else { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) { instr = "add "; @@ -486,13 +514,16 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, valueOfVar.erase(i, 1); } - /// interpet boolean values. + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + /// interpet boolean values, since we're on C++ - if (valueOfVar == "true") + if (valueOfVar == cTrueVal) { valueOfVar = "1"; } - else if (valueOfVar == "false") + else if (valueOfVar == cFalseVal) { valueOfVar = "0"; } @@ -512,11 +543,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (pairRight != valueOfVar) { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; continue; } - syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1]; + syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1] + "\n"; break; } @@ -549,7 +580,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (pair != subText) continue; - syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret"; + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret\n"; break; } @@ -560,13 +591,13 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } else { - syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret"; + syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; } } else { - syntax_tree.fUserValue = "mov rcx, " + subText + "\r\n"; - syntax_tree.fUserValue = "mov rax, rcx\r\nret"; + syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; + syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; } break; @@ -672,8 +703,8 @@ public: static void cxx_print_help() { kSplashCxx(); - kPrintF("%s", "No help available, see:\r\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/softwarelabs/developer/newos/cplusplus\r\n"); + kPrintF("%s", "No help available, see:\n"); + kPrintF("%s", "www.el-mahrouss-logic.com/softwarelabs/developer/newos/cplusplus\n"); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -699,16 +730,30 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "bool", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); kKeywords.push_back({.keyword_name = "char", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "long", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = ParserKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); kKeywords.push_back({.keyword_name = "+=", .keyword_kind = ParserKit::eKeywordKindVariableInc}); kKeywords.push_back({.keyword_name = "-=", .keyword_kind = ParserKit::eKeywordKindVariableDec}); kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = ParserKit::eKeywordKindPtr}); kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); kKeywords.push_back({.keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator}); @@ -722,6 +767,10 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "/*", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); kKeywords.push_back({.keyword_name = "*/", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); kKeywords.push_back({.keyword_name = "//", .keyword_kind = ParserKit::eKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = ParserKit::eKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = ParserKit::eKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = ParserKit::eKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = ParserKit::eKeywordKindLessEq}); kFactory.Mount(new AssemblyMountpointClang()); kCompilerBackend = new CompilerBackendCPlusPlus(); -- cgit v1.2.3 From f4ee9dd22c91c076ad2bd8ba082f7ad02afac350 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 15 May 2024 14:33:32 +0200 Subject: MHR-21: Update ccplus to cplusplus. Signed-off-by: Amlal El Mahrouss --- Sources/cplusplus.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 592e54c..3622606 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -1,7 +1,7 @@ /* * ======================================================== * - * ccplus + * cplusplus * Copyright SoftwareLabs, all rights reserved. * * ======================================================== @@ -111,18 +111,18 @@ namespace detail if (kState.fLastFile != file) { - std::cout << kRed << "[ ccplus ] " << kWhite + std::cout << kRed << "[ cplusplus ] " << kWhite << ((file == "cplusplus") ? "internal compiler error " : ("in file, " + file)) << kBlank << std::endl; - std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank + std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank << std::endl; kState.fLastFile = file; } else { - std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite + std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite << reason << kBlank << std::endl; } @@ -834,7 +834,7 @@ MPCC_MODULE(CompilerCPlusPlus) std::string err = "Unknown option: "; err += argv[index]; - detail::print_error(err, "ccplus"); + detail::print_error(err, "cplusplus"); continue; } @@ -859,7 +859,7 @@ MPCC_MODULE(CompilerCPlusPlus) { if (kState.fVerbose) { - detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); + detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); } return 1; -- cgit v1.2.3 From 5e49fbae54bd7dcbf2e893acaef699ce9f2587f3 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 21 May 2024 09:12:06 +0200 Subject: MHR-21: Refactor, WiP symbol support in mov. Signed-off-by: Amlal El Mahrouss --- Examples/ExampleAMD64.asm | 2 +- Examples/ExampleCPlusPlus.cxx | 2 +- Headers/AsmKit/AsmKit.hpp | 2 +- Headers/AsmKit/CPU/32x0.hpp | 2 +- Headers/AsmKit/CPU/64x0.hpp | 2 +- Headers/AsmKit/CPU/amd64.hpp | 2 +- Headers/AsmKit/CPU/ppc.hpp | 10 +- Headers/CompilerKit.hpp | 2 +- Headers/Defines.hpp | 2 +- Headers/ParserKit.hpp | 2 +- Headers/StdKit/AE.hpp | 32 +- Headers/StdKit/PEF.hpp | 2 +- Headers/StdKit/String.hpp | 12 +- Headers/StdKit/XCOFF.hxx | 10 +- SDK/__mpcc_alloca.hxx | 2 +- SDK/__mpcc_defines.hxx | 2 +- SDK/__mpcc_exception.hxx | 2 +- SDK/__mpcc_hint.hxx | 2 +- SDK/__mpcc_malloc.hxx | 2 +- Sources/AssemblyFactory.cc | 58 + Sources/AssemblyFactory.cxx | 58 - Sources/Detail/asmutils.h | 111 -- Sources/Detail/asmutils.hxx | 111 ++ Sources/Detail/compilerutils.h | 14 - Sources/Detail/compilerutils.hxx | 14 + Sources/i64asm.cc | 2381 +++++++++++++++++++++----------------- Sources/link.cc | 26 +- Sources/ppcasm.cc | 33 +- posix.make | 2 +- win64.make | 2 +- 30 files changed, 1571 insertions(+), 1333 deletions(-) create mode 100644 Sources/AssemblyFactory.cc delete mode 100644 Sources/AssemblyFactory.cxx delete mode 100644 Sources/Detail/asmutils.h create mode 100644 Sources/Detail/asmutils.hxx delete mode 100644 Sources/Detail/compilerutils.h create mode 100644 Sources/Detail/compilerutils.hxx (limited to 'Sources') diff --git a/Examples/ExampleAMD64.asm b/Examples/ExampleAMD64.asm index cc649be..781934c 100644 --- a/Examples/ExampleAMD64.asm +++ b/Examples/ExampleAMD64.asm @@ -2,5 +2,5 @@ export .code64 __ImageStart -mov rax, rdx +mov rax, 17 ret diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx index 6012b52..3335e1e 100644 --- a/Examples/ExampleCPlusPlus.cxx +++ b/Examples/ExampleCPlusPlus.cxx @@ -5,7 +5,7 @@ int main(int argc, char const* argv[]) bar = 1; bool bar2 = bar; - bar2 = false; + bar2 = false; } return 0; diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp index 23db830..d22ec21 100644 --- a/Headers/AsmKit/AsmKit.hpp +++ b/Headers/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp index 44ddaed..4d66da5 100644 --- a/Headers/AsmKit/CPU/32x0.hpp +++ b/Headers/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp index 58ab76d..974f346 100644 --- a/Headers/AsmKit/CPU/64x0.hpp +++ b/Headers/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp index be5a657..8f7e05c 100644 --- a/Headers/AsmKit/CPU/amd64.hpp +++ b/Headers/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/AsmKit/CPU/ppc.hpp b/Headers/AsmKit/CPU/ppc.hpp index c29286d..c4265da 100644 --- a/Headers/AsmKit/CPU/ppc.hpp +++ b/Headers/AsmKit/CPU/ppc.hpp @@ -242,7 +242,7 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x4c800421, "bfctrl", {{16, 5, BCND}, {11, 2, NUM}}}, /* branch mnemonics incorporating conditions (assember extended mnemonics) - */ + */ {0x41800000, "blt", {{16, 5, CRF}, {2, 14, PCREL}}}, {0x41800000, "blt", {{2, 14, PCREL}}}, {0x41800001, "bltl", {{16, 5, CRF}, {2, 14, PCREL}}}, @@ -1548,10 +1548,10 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x7c000426, "clcs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, /* Added from the POWER 603 book. - * These are really 603 specific instructions but we mark them as OPTIONAL - * so that the -force_cpusubtype_ALL flag as to be used. This makes it so - * only 601 instructions will cause the cputype to be set to other an ALL. - */ + * These are really 603 specific instructions but we mark them as OPTIONAL + * so that the -force_cpusubtype_ALL flag as to be used. This makes it so + * only 601 instructions will cause the cputype to be set to other an ALL. + */ {0x7c0007a4, "tlbld", {{11, 5, GREG}}, OPTIONAL}, {0x7c0007e4, "tlbli", {{11, 5, GREG}}, OPTIONAL}, diff --git a/Headers/CompilerKit.hpp b/Headers/CompilerKit.hpp index 3d5cfc2..b9de089 100644 --- a/Headers/CompilerKit.hpp +++ b/Headers/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/Defines.hpp b/Headers/Defines.hpp index ac8692b..d76620c 100644 --- a/Headers/Defines.hpp +++ b/Headers/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp index 6a53edc..f77dba9 100644 --- a/Headers/ParserKit.hpp +++ b/Headers/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp index 3075017..ebae770 100644 --- a/Headers/StdKit/AE.hpp +++ b/Headers/StdKit/AE.hpp @@ -95,9 +95,9 @@ std::ifstream& operator>>(std::ifstream& fp, namespace CompilerKit::Utils { /** - * @brief AE Reader protocol - * - */ + * @brief AE Reader protocol + * + */ class AEReadableProtocol final { public: @@ -110,12 +110,12 @@ namespace CompilerKit::Utils MPCC_COPY_DELETE(AEReadableProtocol); /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ AERecordHeaderPtr Read(char* raw, std::size_t sz) { if (!raw) @@ -126,13 +126,13 @@ namespace CompilerKit::Utils private: /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ template TypeClass* _Read(char* raw, std::size_t sz) { diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp index ee01852..88c20ea 100644 --- a/Headers/StdKit/PEF.hpp +++ b/Headers/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp index 20fd16f..d4048ee 100644 --- a/Headers/StdKit/String.hpp +++ b/Headers/StdKit/String.hpp @@ -15,9 +15,9 @@ namespace CompilerKit { /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ class StringView final { @@ -76,9 +76,9 @@ namespace CompilerKit }; /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ struct StringBuilder final { static StringView Construct(const CharType* data); diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx index b9cc825..d339daa 100644 --- a/Headers/StdKit/XCOFF.hxx +++ b/Headers/StdKit/XCOFF.hxx @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs - File: XCOFF.hpp - Purpose: XCOFF for NewOS. + File: XCOFF.hpp + Purpose: XCOFF for NewOS. - Revision History: + Revision History: - 04/07/24: Added file (amlel) + 04/07/24: Added file (amlel) ------------------------------------------- */ diff --git a/SDK/__mpcc_alloca.hxx b/SDK/__mpcc_alloca.hxx index f15e059..a1c638e 100644 --- a/SDK/__mpcc_alloca.hxx +++ b/SDK/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_defines.hxx b/SDK/__mpcc_defines.hxx index ff91db1..5560410 100644 --- a/SDK/__mpcc_defines.hxx +++ b/SDK/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_exception.hxx b/SDK/__mpcc_exception.hxx index d36aba6..9366102 100644 --- a/SDK/__mpcc_exception.hxx +++ b/SDK/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_hint.hxx b/SDK/__mpcc_hint.hxx index d775f52..ee14711 100644 --- a/SDK/__mpcc_hint.hxx +++ b/SDK/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/SDK/__mpcc_malloc.hxx b/SDK/__mpcc_malloc.hxx index 56989f8..2731868 100644 --- a/SDK/__mpcc_malloc.hxx +++ b/SDK/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc new file mode 100644 index 0000000..d5c0da7 --- /dev/null +++ b/Sources/AssemblyFactory.cc @@ -0,0 +1,58 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cxx + * @author Amlal El Mahrouss (amlal@mahrouss.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, SoftwareLabs + * + */ + +#include + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit +{ + //! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + //! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx deleted file mode 100644 index d5c0da7..0000000 --- a/Sources/AssemblyFactory.cxx +++ /dev/null @@ -1,58 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#include -#include - -/** - * @file AssemblyFactory.cxx - * @author Amlal El Mahrouss (amlal@mahrouss.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, SoftwareLabs - * - */ - -#include - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit -{ - //! @brief Compile for specific format (ELF, PEF, ZBIN) - Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept - { - if (sourceFile.length() < 1 || !fMounted) - return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); - } - - //! @brief mount assembly backend. - void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept - { - if (mountPtr) - { - fMounted = mountPtr; - } - } - - AssemblyInterface* AssemblyFactory::Unmount() noexcept - { - auto mount_prev = fMounted; - - if (mount_prev) - { - fMounted = nullptr; - } - - return mount_prev; - } -} // namespace CompilerKit diff --git a/Sources/Detail/asmutils.h b/Sources/Detail/asmutils.h deleted file mode 100644 index c0537ad..0000000 --- a/Sources/Detail/asmutils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -using namespace CompilerKit; - -/// @brief Get Number from lineBuffer. -/// @param lineBuffer the lineBuffer to fetch from. -/// @param numberKey where to seek that number. -/// @return -static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) -{ - auto pos = lineBuffer.find(numberKey) + numberKey.size(); - - if (lineBuffer.find(",") != std::string::npos) - lineBuffer.erase(lineBuffer.find(","), 1); - - while (lineBuffer[pos] == ' ') - ++pos; - - switch (lineBuffer[pos + 1]) - { - case 'x': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 16 number here: " << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number:" + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 2 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 8 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) - { - kStdOut << "ppcasm: found a base 10 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - } -} diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx new file mode 100644 index 0000000..36c5901 --- /dev/null +++ b/Sources/Detail/asmutils.hxx @@ -0,0 +1,111 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +using namespace CompilerKit; + +/// @brief Get Number from lineBuffer. +/// @param lineBuffer the lineBuffer to fetch from. +/// @param numberKey where to seek that number. +/// @return +static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) +{ + auto pos = lineBuffer.find(numberKey) + numberKey.size(); + + if (lineBuffer.find(",") != std::string::npos) + lineBuffer.erase(lineBuffer.find(","), 1); + + while (lineBuffer[pos] == ' ') + ++pos; + + switch (lineBuffer[pos + 1]) + { + case 'x': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); + + if (kVerbose) + { + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'b': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number:" + lineBuffer, "asm"); + throw std::runtime_error("invalid_bin"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'o': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_octal"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + default: { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); + + if (kVerbose) + { + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + } +} diff --git a/Sources/Detail/compilerutils.h b/Sources/Detail/compilerutils.h deleted file mode 100644 index cde8d34..0000000 --- a/Sources/Detail/compilerutils.h +++ /dev/null @@ -1,14 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx new file mode 100644 index 0000000..bebdd7f --- /dev/null +++ b/Sources/Detail/compilerutils.hxx @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +#define kZero64Section ".zero64" +#define kCode64Section ".code64" +#define kData64Section ".data64" diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 53ca13e..5f0812c 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright SoftwareLabs ------------------------------------------- */ @@ -25,7 +25,7 @@ #define __ASM_NEED_AMD64__ 1 #define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' +#define kAssemblerPragmaSym '#' #include #include @@ -45,25 +45,25 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) -static char kOutputArch = CompilerKit::kPefArchAMD64; +static char kOutputArch = CompilerKit::kPefArchAMD64; static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; constexpr auto cAMD64IPAlignment = 0x4U; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector> kOriginLabel; /// @brief keep it simple by default. @@ -74,44 +74,53 @@ static bool kVerbose = false; static std::vector kAppBytes; static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector kRecords; -static std::vector kDefinedSymbols; -static std::vector kUndefinedSymbols; +static std::vector kDefinedSymbols; +static std::vector kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; // \brief forward decl. -static bool asm_read_attributes(std::string &line); +static bool asm_read_attributes(std::string& line); -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); +namespace detail +{ + void print_error(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); - kStdErr << kRed << "[ i64asm ] " << kWhite - << ((file == "i64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite + << ((file == "i64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; - if (kAcceptableErrors > kErrorLimit) std::exit(3); + if (kAcceptableErrors > kErrorLimit) + std::exit(3); - ++kAcceptableErrors; -} + ++kAcceptableErrors; + } -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); + void print_warning(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } + if (!file.empty()) + { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } - kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail + kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank + << std::endl; + } +} // namespace detail + +#include ///////////////////////////////////////////////////////////////////////////////////////// @@ -119,237 +128,277 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssemblerAMD64) { - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 SoftwareLabs.\n"; - return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "SoftwareLabs.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "i64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "i64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "i64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; +MPCC_MODULE(NewOSAssemblerAMD64) +{ + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = { + "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", + "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", + "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) + { + CpuOpcodeAMD64 code{ + .fName = opcodes_jump[i], + .fOpcode = static_cast(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) + { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) + { + if (argv[i][0] == '-') + { + if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) + { + kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " + "(c) 2024 SoftwareLabs.\n"; + return 0; + } + else if (strcmp(argv[i], "-h") == 0) + { + kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " + "SoftwareLabs.\n"; + kStdOut << "-version: Print program version.\n"; + kStdOut << "-verbose: Print verbose output.\n"; + kStdOut << "-binary: Output as flat binary.\n"; + + return 0; + } + else if (strcmp(argv[i], "-binary") == 0) + { + kOutputAsBinary = true; + continue; + } + else if (strcmp(argv[i], "-verbose") == 0) + { + kVerbose = true; + continue; + } + + kStdOut << "i64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) + { + kStdOut << "i64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) + { + if (object_output.find(ext) != std::string::npos) + { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) + { + if (kVerbose) + { + kStdOut << "i64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + while (std::getline(file_ptr, line)) + { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) + { + detail::print_error(ln, argv[i]); + continue; + } + + try + { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } + catch (const std::exception& e) + { + if (kVerbose) + { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "i64asm"); + } + + try + { + std::filesystem::remove(object_output); + } + catch (...) + { + } + + goto asm_fail_exit; + } + } - ///////////////////////////////////////////////////////////////////////////////////////// + if (!kOutputAsBinary) + { + if (kVerbose) + { + kStdOut << "i64asm: Writing object file...\n"; + } - // COMPILATION LOOP + // this is the final step, write everything to the file. - ///////////////////////////////////////////////////////////////////////////////////////// + auto pos = file_ptr_out.tellp(); - CompilerKit::EncoderAMD64 asm64; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } + file_ptr_out << hdr; - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "i64asm"); - } + if (kRecords.empty()) + { + kStdErr << "i64asm: At least one record is needed to write an object " + "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; - try { - std::filesystem::remove(object_output); - } catch (...) { - } + std::filesystem::remove(object_output); + return -1; + } - goto asm_fail_exit; - } - } + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "i64asm: Writing object file...\n"; - } + std::size_t record_count = 0UL; - // this is the final step, write everything to the file. + for (auto& rec : kRecords) + { + if (kVerbose) + kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; - auto pos = file_ptr_out.tellp(); + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + file_ptr_out << rec; + } - file_ptr_out << hdr; + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - if (kRecords.empty()) { - kStdErr << "i64asm: At least one record is needed to write an object " - "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; + for (auto& sym : kUndefinedSymbols) + { + CompilerKit::AERecordHeader _record_hdr{0}; - std::filesystem::remove(object_output); - return -1; - } + if (kVerbose) + kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; - std::size_t record_count = 0UL; + ++record_count; - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; + file_ptr_out << _record_hdr; - file_ptr_out << rec; - } + ++kCounter; + } - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + auto pos_end = file_ptr_out.tellp(); - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; + file_ptr_out.seekp(pos); - if (kVerbose) - kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; + hdr.fStartCode = pos_end; + hdr.fCodeSize = kAppBytes.size(); - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + file_ptr_out << hdr; - ++record_count; + file_ptr_out.seekp(pos_end); + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: Write raw binary...\n"; + } + } - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + // byte from byte, we write this. + for (auto& byte : kAppBytes) + { + if (byte == 0) + continue; - file_ptr_out << _record_hdr; + if (byte == 0xFF) + { + byte = 0; + } - ++kCounter; - } + file_ptr_out << reinterpret_cast(&byte)[0]; + } - auto pos_end = file_ptr_out.tellp(); + if (kVerbose) + kStdOut << "i64asm: Wrote file with program in it.\n"; - file_ptr_out.seekp(pos); + file_ptr_out.flush(); + file_ptr_out.close(); - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); + if (kVerbose) + kStdOut << "i64asm: Exit succeeded.\n"; - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "i64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kAppBytes) { - if (byte == 0) continue; - - if (byte == 0xFF) { - byte = 0; - } - - file_ptr_out << reinterpret_cast(&byte)[0]; - } - - if (kVerbose) kStdOut << "i64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "i64asm: Exit succeeded.\n"; - - return 0; - } + return 0; + } asm_fail_exit: - if (kVerbose) kStdOut << "i64asm: Exit failed.\n"; + if (kVerbose) + kStdOut << "i64asm: Exit failed.\n"; - return -1; + return -1; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -359,156 +408,182 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; +static bool asm_read_attributes(std::string& line) +{ + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (ParserKit::find_word(line, "import")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) + { + detail::print_error("Invalid import", "ppcasm"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) + { + if (j == ' ' || j == ',') + j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by i64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (ParserKit::find_word(line, "export")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export") + 1); + + std::string name_copy = name; + + for (char& j : name) + { + if (j == ' ') + j = '$'; + } + + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != + kDefinedSymbols.end()) + { + detail::print_error("Symbol already defined.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + kDefinedSymbols.push_back(name); + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. - kRecords.emplace_back(kCurrentRecord); + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } - return true; - } - // export is a special keyword used by i64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); - auto name = line.substr(line.find("export") + strlen("export") + 1); + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; - std::string name_copy = name; + // now we can tell the code size of the previous kCurrentRecord. - for (char &j : name) { - if (j == ' ') j = '$'; - } + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) { - detail::print_error("Symbol already defined.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - kDefinedSymbols.push_back(name); + ++kCounter; - if (name.find(".code64") != std::string::npos) { - // data is treated as code. + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. + kRecords.emplace_back(kCurrentRecord); - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. + return true; + } - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; + return false; } // \brief algorithms and helpers. -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm +namespace detail::algorithm +{ + // \brief authorize a brief set of characters. + static inline bool is_not_alnum_space(char c) + { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); + } + + bool is_valid(const std::string& str) + { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); + } +} // namespace detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -516,491 +591,588 @@ bool is_valid(const std::string &str) { ///////////////////////////////////////////////////////////////////////////////////////// -std::string CompilerKit::EncoderAMD64::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - ParserKit::find_word(line, kAssemblerPragmaSymStr) || - ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) { - if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nHere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto &opcodeAMD64 : kOpcodesAMD64) { - if (ParserKit::find_word(line, opcodeAMD64.fName)) { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; +std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, + const std::string& file) +{ + std::string err_str; + + if (line.empty() || ParserKit::find_word(line, "import") || + ParserKit::find_word(line, "export") || + ParserKit::find_word(line, kAssemblerPragmaSymStr) || + ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + { + if (line.find(';') != std::string::npos) + { + line.erase(line.find(';')); + } + else + { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non valid characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non alphanumeric characters.\nHere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) + { + if (line.find(',') + 1 == line.size()) + { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } + else + { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto& ch : substr) + { + if (ch != ' ' && ch != '\t') + { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + if (ParserKit::find_word(line, opcodeAMD64.fName)) + { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; } -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1009,239 +1181,304 @@ bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t &pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerKit::EncoderAMD64::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; - - struct RegMapAMD64 { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector REGISTER_LIST{ - {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto &opcodeAMD64 : kOpcodesAMD64) { - // strict check here - if (ParserKit::find_word(line, opcodeAMD64.fName) && - detail::algorithm::is_valid(line)) { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (name.find("mov") != std::string::npos) { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector currentRegList; - - for (auto ® : REGISTER_LIST) { - std::vector regExt = {'e', 'r'}; - - for (auto &ext : regExt) { - std::string registerName; - - if (bits > 16) registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) { - if (registerName[0] == 'r') { - detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) { - /// very tricky to understand. - /// this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x89); - } else if (bits == 16) { - if (hasRBasedRegs) { - detail::print_error( - "Invalid combination of operands and registers.", "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } else { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } else if (name == "int" || name == "into" || name == "intd") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } else if (name == "jmp" || name == "call") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } else { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) { - if (foundInstruction) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) { - kRegisterBitWidth = 64U; - } else if (line.find("bits 32") != std::string::npos) { - kRegisterBitWidth = 32U; - } else if (line.find("bits 16") != std::string::npos) { - kRegisterBitWidth = 16U; - } else if (line.find("org") != std::string::npos) { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) { - if (errno != 0) { - continue; - } else { - if (kVerbose) { - kStdOut << "i64asm: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += cAMD64IPAlignment; - - return true; +bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, + const std::string& file) +{ + if (ParserKit::find_word(line, "export ")) + return true; + + struct RegMapAMD64 + { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector REGISTER_LIST{ + {.fName = "ax", .fModRM = 0x0}, + {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, + {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, + {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, + {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, + {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, + {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, + {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + // strict check here + if (ParserKit::find_word(line, opcodeAMD64.fName) && + detail::algorithm::is_valid(line)) + { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (name.find("mov") != std::string::npos) + { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) + { + detail::print_error("Syntax error.", "i64asm"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector currentRegList; + + for (auto& reg : REGISTER_LIST) + { + std::vector regExt = {'e', 'r'}; + + for (auto& ext : regExt) + { + std::string registerName; + + if (bits > 16) + registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) + { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) + { + if (registerName[0] == 'r') + { + detail::print_error( + "invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back( + {.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) + onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) + { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || + currentRegList[1].fName[0] == 'r') + { + if (isdigit(currentRegList[0].fName[1]) && + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } + else if (isdigit(currentRegList[0].fName[1]) || + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) + { + if (!hasRBasedRegs && bits >= 32) + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x89); + } + else if (bits == 16) + { + if (hasRBasedRegs) + { + detail::print_error( + "Invalid combination of operands and registers.", "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + + if (currentRegList[1].fName[0] == 'r' && + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) + { + if (currentRegList[0].fName[0] == 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + else + { + if (currentRegList[0].fName[0] != 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | + currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } + else if (name == "int" || name == "into" || name == "intd") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } + else if (name == "jmp" || name == "call") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) + { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } + else + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) + { + if (foundInstruction) + { + detail::print_error("Syntax error: " + line, "i64asm"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) + { + kRegisterBitWidth = 64U; + } + else if (line.find("bits 32") != std::string::npos) + { + kRegisterBitWidth = 32U; + } + else if (line.find("bits 16") != std::string::npos) + { + kRegisterBitWidth = 16U; + } + else if (line.find("org") != std::string::npos) + { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) + { + if (kOrigin = strtol( + (line.substr(line.find("org") + strlen("org") + 1)).c_str(), + nullptr, base[i]); + kOrigin) + { + if (errno != 0) + { + continue; + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) + { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) + { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) + { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += cAMD64IPAlignment; + + return true; } // Last rev 13-1-24 diff --git a/Sources/link.cc b/Sources/link.cc index 13e1db1..d0d330e 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -84,13 +84,13 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "-version: Show program version.\n"; kStdOut << "-verbose: Enable program trace.\n"; kStdOut << "-shared: Output as a shared PEF.\n"; - kStdOut << "-fat-bin: Output as FAT PEF.\n"; - kStdOut << "-32x0: Output as 32x0 PEF.\n"; - kStdOut << "-64x0: Output as 64x0 PEF.\n"; - kStdOut << "-amd64: Output as AMD64 PEF.\n"; - kStdOut << "-rv64: Output as RISC-V 64 PEF.\n"; - kStdOut << "-ppc64: Output as POWER 64 PEF.\n"; - kStdOut << "-output-file: Select output file name.\n"; + kStdOut << "-fat-bin: Output as a FAT PEF.\n"; + kStdOut << "-32x0: Output as a 32x0 PEF.\n"; + kStdOut << "-64x0: Output as a 64x0 PEF.\n"; + kStdOut << "-amd64: Output as a AMD64 PEF.\n"; + kStdOut << "-rv64: Output as a RISC-V PEF.\n"; + kStdOut << "-ppc64: Output as a POWER PEF.\n"; + kStdOut << "-output-file: Select the output file name.\n"; return 0; } else if (StringCompare(argv[i], "-v") == 0) { @@ -141,7 +141,7 @@ MPCC_MODULE(NewOSLinker) { } else { if (argv[i][0] == '-') { kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } kObjectList.emplace_back(argv[i]); @@ -203,7 +203,7 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "link: error: " << strerror(errno) << "\n"; } - return -MPCC_FILE_NOT_FOUND; + return MPCC_FILE_NOT_FOUND; } //! Read AE to convert as PEF. @@ -235,7 +235,7 @@ MPCC_MODULE(NewOSLinker) { << std::endl; std::remove(kOutput.c_str()); - return -MPCC_FAT_ERROR; + return MPCC_FAT_ERROR; } else { if (kVerbose) { kStdOut << "Yes.\n"; @@ -329,7 +329,7 @@ MPCC_MODULE(NewOSLinker) { std::remove(kOutput.c_str()); // don't continue, it is a fatal error. - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } pef_container.Cpu = archs; @@ -596,7 +596,7 @@ MPCC_MODULE(NewOSLinker) { } std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } // step 2.5: write program bytes. @@ -632,7 +632,7 @@ MPCC_MODULE(NewOSLinker) { << ", is corrupt, removing file...\n"; std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; + return MPCC_EXEC_ERROR; } return 0; diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 6c1f367..5c444dd 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -17,6 +17,7 @@ #define __ASM_NEED_PPC__ 1 +#include #include #include #include @@ -100,7 +101,7 @@ void print_warning(std::string reason, const std::string &file) noexcept { } // namespace detail /// Do not move it on top! it uses the assembler detail namespace! -#include +#include ///////////////////////////////////////////////////////////////////////////////////////// @@ -224,36 +225,36 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { std::size_t record_count = 0UL; - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "ppcasm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; ++record_count; - file_ptr_out << rec; + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "ppcasm: Wrote record " << record_hdr.fName << "...\n"; } // increment once again, so that we won't lie about the kUndefinedSymbols. ++record_count; for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; + CompilerKit::AERecordHeader undefined_sym{0}; if (kVerbose) kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; ++record_count; - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - file_ptr_out << _record_hdr; + file_ptr_out << undefined_sym; ++kCounter; } @@ -293,7 +294,7 @@ asm_fail_exit: if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; - return -1; + return MPCC_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/posix.make b/posix.make index 42e0ece..4e47c53 100644 --- a/posix.make +++ b/posix.make @@ -19,7 +19,7 @@ LINK_ALT_4_OUTPUT=Output/ppclink.exec PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exec -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) diff --git a/win64.make b/win64.make index 4abac3e..0d8482d 100644 --- a/win64.make +++ b/win64.make @@ -19,7 +19,7 @@ LINK_ALT_2_OUTPUT=Output/32link.exe PP_SRC=Sources/bpp.cc PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cxx +SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) -- cgit v1.2.3 From ebab1465b4d42910da1b36d8c65487c2f077b481 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 28 May 2024 21:32:21 +0200 Subject: MHR-21: refactors. Signed-off-by: Amlal El Mahrouss --- .gitignore | 4 +- .vscode/c_cpp_properties.json | 4 +- 64asm.rsrc | 8 +- 64x0-cc.rsrc | 8 +- Common/AsmKit/AsmKit.hpp | 217 ++++ Common/AsmKit/CPU/32x0.hpp | 95 ++ Common/AsmKit/CPU/64x0.hpp | 108 ++ Common/AsmKit/CPU/amd64.hpp | 56 + Common/AsmKit/CPU/ppc.hpp | 1919 ++++++++++++++++++++++++++++ Common/CompilerKit.hpp | 33 + Common/Defines.hpp | 147 +++ Common/ParserKit.hpp | 171 +++ Common/Public/SDK/CRT/__mpcc_alloca.hxx | 15 + Common/Public/SDK/CRT/__mpcc_defines.hxx | 89 ++ Common/Public/SDK/CRT/__mpcc_exception.hxx | 27 + Common/Public/SDK/CRT/__mpcc_hint.hxx | 20 + Common/Public/SDK/CRT/__mpcc_malloc.hxx | 30 + Common/Public/SDK/CRT/__mpcc_power.inc | 35 + Common/StdKit/AE.hpp | 143 +++ Common/StdKit/ELF.hpp | 389 ++++++ Common/StdKit/ErrorID.hpp | 22 + Common/StdKit/ErrorOr.hpp | 61 + Common/StdKit/PEF.hpp | 132 ++ Common/StdKit/Ref.hpp | 91 ++ Common/StdKit/String.hpp | 90 ++ Common/StdKit/XCOFF.hxx | 41 + Common/UUID.hpp | 983 ++++++++++++++ Common/Version.hxx | 3 + Documentation/ASM_SPECS.TXT | 11 - Documentation/HAVP.TXT | 13 - Documentation/Inside 64x0.pdf | Bin 64675 -> 0 bytes Documentation/NOTICE.TXT | 4 - Documentation/VNRP.TXT | 17 - Headers/AsmKit/AsmKit.hpp | 217 ---- Headers/AsmKit/CPU/32x0.hpp | 95 -- Headers/AsmKit/CPU/64x0.hpp | 108 -- Headers/AsmKit/CPU/amd64.hpp | 56 - Headers/AsmKit/CPU/ppc.hpp | 1919 ---------------------------- Headers/CompilerKit.hpp | 33 - Headers/Defines.hpp | 147 --- Headers/ParserKit.hpp | 171 --- Headers/StdKit/AE.hpp | 143 --- Headers/StdKit/ELF.hpp | 389 ------ Headers/StdKit/ErrorID.hpp | 22 - Headers/StdKit/ErrorOr.hpp | 61 - Headers/StdKit/PEF.hpp | 132 -- Headers/StdKit/Ref.hpp | 91 -- Headers/StdKit/String.hpp | 90 -- Headers/StdKit/XCOFF.hxx | 41 - Headers/UUID.hpp | 983 -------------- Headers/Version.hxx | 3 - SDK/__mpcc_alloca.hxx | 15 - SDK/__mpcc_defines.hxx | 89 -- SDK/__mpcc_exception.hxx | 27 - SDK/__mpcc_hint.hxx | 20 - SDK/__mpcc_malloc.hxx | 30 - SDK/__mpcc_power.inc | 35 - Sources/32asm.cc | 8 +- Sources/64asm.cc | 8 +- Sources/64x0-cc.cc | 6 +- Sources/AssemblyFactory.cc | 4 +- Sources/Detail/asmutils.hxx | 4 +- Sources/Detail/compilerutils.hxx | 4 +- Sources/String.cc | 2 +- Sources/bpp.cc | 4 +- Sources/coff2ae.cc | 6 +- Sources/cplusplus.cc | 4 +- Sources/elf2ae.cc | 6 +- Sources/i64asm.cc | 8 +- Sources/link.cc | 12 +- Sources/power-cc.cc | 1645 ++++++++++++++++++++++++ Sources/ppc-cc.cc | 1645 ------------------------ Sources/ppcasm.cc | 12 +- bpp.rsrc | 4 +- docs/Inside 64x0.pdf | Bin 0 -> 64675 bytes docs/asm-specs.txt | 11 + docs/havp.txt | 13 + docs/notice.txt | 4 + docs/vnrp.txt | 17 + i64asm.rsrc | 8 +- link.rsrc | 6 +- posix.make | 6 +- power-cc.rsrc | 27 + ppc-cc.rsrc | 27 - ppcasm.rsrc | 8 +- win64.make | 10 +- 86 files changed, 6711 insertions(+), 6711 deletions(-) create mode 100644 Common/AsmKit/AsmKit.hpp create mode 100644 Common/AsmKit/CPU/32x0.hpp create mode 100644 Common/AsmKit/CPU/64x0.hpp create mode 100644 Common/AsmKit/CPU/amd64.hpp create mode 100644 Common/AsmKit/CPU/ppc.hpp create mode 100644 Common/CompilerKit.hpp create mode 100644 Common/Defines.hpp create mode 100644 Common/ParserKit.hpp create mode 100644 Common/Public/SDK/CRT/__mpcc_alloca.hxx create mode 100644 Common/Public/SDK/CRT/__mpcc_defines.hxx create mode 100644 Common/Public/SDK/CRT/__mpcc_exception.hxx create mode 100644 Common/Public/SDK/CRT/__mpcc_hint.hxx create mode 100644 Common/Public/SDK/CRT/__mpcc_malloc.hxx create mode 100644 Common/Public/SDK/CRT/__mpcc_power.inc create mode 100644 Common/StdKit/AE.hpp create mode 100644 Common/StdKit/ELF.hpp create mode 100644 Common/StdKit/ErrorID.hpp create mode 100644 Common/StdKit/ErrorOr.hpp create mode 100644 Common/StdKit/PEF.hpp create mode 100644 Common/StdKit/Ref.hpp create mode 100644 Common/StdKit/String.hpp create mode 100644 Common/StdKit/XCOFF.hxx create mode 100644 Common/UUID.hpp create mode 100644 Common/Version.hxx delete mode 100644 Documentation/ASM_SPECS.TXT delete mode 100644 Documentation/HAVP.TXT delete mode 100644 Documentation/Inside 64x0.pdf delete mode 100644 Documentation/NOTICE.TXT delete mode 100644 Documentation/VNRP.TXT delete mode 100644 Headers/AsmKit/AsmKit.hpp delete mode 100644 Headers/AsmKit/CPU/32x0.hpp delete mode 100644 Headers/AsmKit/CPU/64x0.hpp delete mode 100644 Headers/AsmKit/CPU/amd64.hpp delete mode 100644 Headers/AsmKit/CPU/ppc.hpp delete mode 100644 Headers/CompilerKit.hpp delete mode 100644 Headers/Defines.hpp delete mode 100644 Headers/ParserKit.hpp delete mode 100644 Headers/StdKit/AE.hpp delete mode 100644 Headers/StdKit/ELF.hpp delete mode 100644 Headers/StdKit/ErrorID.hpp delete mode 100644 Headers/StdKit/ErrorOr.hpp delete mode 100644 Headers/StdKit/PEF.hpp delete mode 100644 Headers/StdKit/Ref.hpp delete mode 100644 Headers/StdKit/String.hpp delete mode 100644 Headers/StdKit/XCOFF.hxx delete mode 100644 Headers/UUID.hpp delete mode 100644 Headers/Version.hxx delete mode 100644 SDK/__mpcc_alloca.hxx delete mode 100644 SDK/__mpcc_defines.hxx delete mode 100644 SDK/__mpcc_exception.hxx delete mode 100644 SDK/__mpcc_hint.hxx delete mode 100644 SDK/__mpcc_malloc.hxx delete mode 100644 SDK/__mpcc_power.inc create mode 100644 Sources/power-cc.cc delete mode 100644 Sources/ppc-cc.cc create mode 100644 docs/Inside 64x0.pdf create mode 100644 docs/asm-specs.txt create mode 100644 docs/havp.txt create mode 100644 docs/notice.txt create mode 100644 docs/vnrp.txt create mode 100644 power-cc.rsrc delete mode 100644 ppc-cc.rsrc (limited to 'Sources') diff --git a/.gitignore b/.gitignore index ee93641..c8ab9fa 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,6 @@ local.properties *.exec *.bin -docs/ - # Compiled class file *.class @@ -66,6 +64,8 @@ Drivers/Output/Tests/*.masm .vs +docs/html +docs/latex docs/doxygen *.pc diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 8059633..0aad778 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "Macintosh (CLang)", "includePath": [ - "${workspaceFolder}/Headers/**", + "${workspaceFolder}/Common/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], @@ -16,7 +16,7 @@ { "name": "Windows (Cygwin)", "includePath": [ - "${workspaceFolder}/Headers/**", + "${workspaceFolder}/Common/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], diff --git a/64asm.rsrc b/64asm.rsrc index 7c84d45..9f473f1 100644 --- a/64asm.rsrc +++ b/64asm.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -11,12 +11,12 @@ BEGIN BLOCK "080904E4" BEGIN VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS 64x0 assembler." + VALUE "FileDescription", "SoftwareLabs assembler for 64x000." VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" + VALUE "InternalName", "Assembler" VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "64asm.exe" - VALUE "ProductName", "NewAssembler" + VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion END END diff --git a/64x0-cc.rsrc b/64x0-cc.rsrc index dcec172..300c684 100644 --- a/64x0-cc.rsrc +++ b/64x0-cc.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -11,12 +11,12 @@ BEGIN BLOCK "080904E4" BEGIN VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS 64x0 C compiler." + VALUE "FileDescription", "SoftwareLabs C Compiler for 64x000." VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewC" + VALUE "InternalName", "Compiler" VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "64x0-cc.exe" - VALUE "ProductName", "NewC" + VALUE "ProductName", "Compiler" VALUE "ProductVersion", kDistVersion END END diff --git a/Common/AsmKit/AsmKit.hpp b/Common/AsmKit/AsmKit.hpp new file mode 100644 index 0000000..020ca5c --- /dev/null +++ b/Common/AsmKit/AsmKit.hpp @@ -0,0 +1,217 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include +#include + +namespace CompilerKit +{ + // + // @brief Frontend to Assembly mountpoint. + // + class AssemblyInterface + { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + MPCC_COPY_DEFAULT(AssemblyInterface); + + //@ brief compile to object file. + // Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; + }; + + /// @brief Simple assembly factory + class AssemblyFactory final + { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + MPCC_COPY_DEFAULT(AssemblyFactory); + + public: + enum + { + kArchAMD64, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchUnknown, + }; + + Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; + }; + + union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; + }; + + union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) + : raw(raw) + { + } + ~NumberCast64() + { + raw = 0; + } + + CharType number[8]; + UInt64 raw; + }; + + union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) + : raw(raw) + { + } + ~NumberCast32() + { + raw = 0; + } + + CharType number[4]; + UInt32 raw; + }; + + union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) + : raw(raw) + { + } + ~NumberCast16() + { + raw = 0; + } + + CharType number[2]; + UInt16 raw; + }; + + union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) + : raw(raw) + { + } + ~NumberCast8() + { + raw = 0; + } + + CharType number; + UInt8 raw; + }; + + class EncoderInterface + { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + MPCC_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string& line, const std::string& file) = 0; + virtual bool WriteLine(std::string& line, const std::string& file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; + }; + +#ifdef __ASM_NEED_AMD64__ + + class EncoderAMD64 final : public EncoderInterface + { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; + + MPCC_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + + virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); + }; + +#endif // __ASM_NEED_AMD64__ + +#ifdef __ASM_NEED_64x0__ + + class Encoder64x0 final : public EncoderInterface + { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + MPCC_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_64x0__ + +#ifdef __ASM_NEED_32x0__ + + class Encoder32x0 final : public EncoderInterface + { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; + + MPCC_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ + +#ifdef __ASM_NEED_PPC__ + + class EncoderPowerPC final : public EncoderInterface + { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; + + MPCC_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ +} // namespace CompilerKit diff --git a/Common/AsmKit/CPU/32x0.hpp b/Common/AsmKit/CPU/32x0.hpp new file mode 100644 index 0000000..fe03336 --- /dev/null +++ b/Common/AsmKit/CPU/32x0.hpp @@ -0,0 +1,95 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @brief 32x0 support. +// @file CPU/32x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 + +#define kAsmByte 0 +#define kAsmHWord 1 +#define kAsmWord 2 + +struct CpuCode32x0 +{ + const char fName[32]; + char fOpcode; + char fSize; + char fFunct3; + char fFunct7; +}; + +#define kAsmDWordStr ".dword" /* 64 bit */ +#define kAsmWordStr ".word" /* 32-bit */ +#define kAsmHWordStr ".half" /* 16-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ + +inline std::vector kOpcodes32x0 = { + kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. + kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch + kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers + kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp + kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. + kAsmOpcodeDecl("cls", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR. + kAsmOpcodeDecl("rts", 0b0111011, 0b110, + kAsmImmediate) // pull stack and return form CR. + kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt +}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: TODO: find one +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Common/AsmKit/CPU/64x0.hpp b/Common/AsmKit/CPU/64x0.hpp new file mode 100644 index 0000000..b28866f --- /dev/null +++ b/Common/AsmKit/CPU/64x0.hpp @@ -0,0 +1,108 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +// @brief 64x0 support. +// @file CPU/64x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 + +typedef char e64k_character_t; +typedef uint8_t e64k_num_t; + +struct CpuOpcode64x0 +{ + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; +}; + +inline std::vector kOpcodes64x0 = { + kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) + kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) + kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) + kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL/JUMP ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Common/AsmKit/CPU/amd64.hpp b/Common/AsmKit/CPU/amd64.hpp new file mode 100644 index 0000000..507602c --- /dev/null +++ b/Common/AsmKit/CPU/amd64.hpp @@ -0,0 +1,56 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @brief AMD64 support. +// @file CPU/amd64.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, + +typedef char i64_character_t; +typedef uint8_t i64_byte_t; +typedef uint16_t i64_hword_t; +typedef uint32_t i64_word_t; + +struct CpuOpcodeAMD64 +{ + std::string fName; + i64_byte_t fPrefixBytes[4]; + i64_hword_t fOpcode; + i64_hword_t fModReg; + i64_word_t fDisplacment; + i64_word_t fImmediate; +}; + +/// these two are edge cases +#define kAsmIntOpcode 0xCC +#define kasmIntOpcodeAlt 0xCD + +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 +#define kJumpLimitStandardLimit 0xEB + +inline std::vector kOpcodesAMD64 = { + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF)}; + +#define kAsmRegisterLimit 15 diff --git a/Common/AsmKit/CPU/ppc.hpp b/Common/AsmKit/CPU/ppc.hpp new file mode 100644 index 0000000..c4265da --- /dev/null +++ b/Common/AsmKit/CPU/ppc.hpp @@ -0,0 +1,1919 @@ +#pragma once + +#include + +/// @note Based of: +/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html + +/* + * These defines are use in the cpus field of the instructions. If the field + * is zero it can execute on all cpus. The defines are or'ed together. This + * information is used to set the cpusubtype in the resulting object file. + */ +#define CPU601 0x1 +#define IMPL64 0x2 +#define OPTIONAL 0x4 +#define VMX 0x8 +#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ +#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ + +enum optype +{ + NONE, /* no operand */ + JBSR, /* jbsr pseudo op */ + PCREL, /* PC relative (branch offset) */ + BADDR, /* Branch address (sign extended absolute address) */ + D, /* 16 bit displacement */ + DS, /* 14 bit displacement (double word) */ + SI, /* signed 16 bit immediate */ + UI, /* unsigned 16 bit immediate */ + HI, /* high 16 bit immediate (with truncation) */ + GREG, /* general register */ + G0REG, /* general register r1-r31 or 0 */ + FREG, /* float register */ + VREG, /* vector register */ + SGREG, /* segment register */ + SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ + BCND, /* branch condition opcode */ + CRF, /* condition register field */ + CRFONLY, /* condition register field only no expression allowed */ + sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ + mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ + NUM, /* number */ + SNUM, /* signed number */ + NUM0, /* number (where 1< + +#define SizeType size_t + +#define VoidPtr void* +#define voidPtr VoidPtr + +#define UIntPtr uintptr_t + +#define Int64 int64_t +#define UInt64 uint64_t + +#define Int32 int +#define UInt32 unsigned + +#define Bool bool + +#define Int16 int16_t +#define UInt16 uint16_t + +#define Int8 int8_t +#define UInt8 uint8_t + +#define CharType char +#define Boolean bool + +#include +#include +#include + +#define nullPtr std::nullptr_t + +#define MUST_PASS(E) assert(E) + +#ifndef __FORCE_STRLEN +#define __FORCE_STRLEN 1 + +#define string_length(len) strlen(len) +#endif + +#ifndef __FORCE_MEMCPY +#define __FORCE_MEMCPY 1 + +#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) +#endif + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#include +#include +#include +#include + +namespace CompilerKit +{ + inline constexpr int BASE_YEAR = 1900; + + inline std::string current_date() noexcept + { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); + + std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); + + return fmt; + } + + inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept + { + if (limit == 0) + return false; + + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; + + while (limit != 1) + { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; + } +} // namespace CompilerKit + +#define PACKED __attribute__((packed)) + +typedef char char_type; + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts \ + { \ + ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ + } + +#ifdef __MODULE_NEED__ +#define MPCC_MODULE(name) int name(int argc, char** argv) +#else +#define MPCC_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __MODULE_NEED__ */ + +#pragma scalar_storage_order big - endian + +#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Common/ParserKit.hpp b/Common/ParserKit.hpp new file mode 100644 index 0000000..6e15c75 --- /dev/null +++ b/Common/ParserKit.hpp @@ -0,0 +1,171 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +namespace ParserKit +{ + using namespace CompilerKit; + + /// @brief Compiler backend, implements a frontend, such as C, C++... + /// See Toolchain, for some examples. + class CompilerBackend + { + public: + explicit CompilerBackend() = default; + virtual ~CompilerBackend() = default; + + MPCC_COPY_DEFAULT(CompilerBackend); + + // NOTE: cast this to your user defined ast. + typedef void* AstType; + + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + + virtual bool Compile(const std::string& text, const char* file) = 0; + + //! @brief What language are we dealing with? + virtual const char* Language() + { + return "Invalid Language"; + } + }; + + struct SyntaxLeafList; + struct SyntaxLeafList; + struct CompilerKeyword; + + /// we want to do that because to separate keywords. + enum KeywordKind + { + eKeywordKindNamespace, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, + eKeywordKindVariable, + eKeywordKindType, + eKeywordKindExpressionBegin, + eKeywordKindExpressionEnd, + eKeywordKindArgSeparator, + eKeywordKindBodyStart, + eKeywordKindBodyEnd, + eKeywordKindClass, + eKeywordKindPtrAccess, + eKeywordKindAccess, + eKeywordKindIf, + eKeywordKindElse, + eKeywordKindElseIf, + eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, + eKeywordKindConstant, + eKeywordKindTypedef, + eKeywordKindEndInstr, + eKeywordKindSpecifier, + eKeywordKindInvalid, + eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, + }; + + /// \brief Compiler keyword information struct. + struct CompilerKeyword + { + std::string keyword_name; + KeywordKind keyword_kind = eKeywordKindInvalid; + }; + struct SyntaxLeafList final + { + struct SyntaxLeaf final + { + Int32 fUserType; +#ifdef __PK_USE_STRUCT_INSTEAD__ + CompilerKeyword fUserData; +#else + std::string fUserData; +#endif + + std::string fUserValue; + struct SyntaxLeaf* fNext; + }; + + std::vector fLeafList; + SizeType fNumLeafs; + + size_t SizeOf() + { + return fNumLeafs; + } + std::vector& Get() + { + return fLeafList; + } + SyntaxLeaf& At(size_t index) + { + return fLeafList[index]; + } + }; + + /// find the perfect matching word in a haystack. + /// \param haystack base string + /// \param needle the string we search for. + /// \return if we found it or not. + inline bool find_word(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) + return true; + + if (index < 0 || index >= haystack.size()) + return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); + } + + /// find a word within strict conditions and returns a range of it. + /// \param haystack + /// \param needle + /// \return position of needle. + inline std::size_t find_word_range(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) + { + return index; + } + + return false; + } +} // namespace ParserKit diff --git a/Common/Public/SDK/CRT/__mpcc_alloca.hxx b/Common/Public/SDK/CRT/__mpcc_alloca.hxx new file mode 100644 index 0000000..a1c638e --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_alloca.hxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +typedef void* ptr_type; +typedef __SIZE_TYPE__ size_type; + +inline void* __mpcc_alloca_gcc(size_type sz) +{ + return __builtin_alloca(sz); +} diff --git a/Common/Public/SDK/CRT/__mpcc_defines.hxx b/Common/Public/SDK/CRT/__mpcc_defines.hxx new file mode 100644 index 0000000..5560410 --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_defines.hxx @@ -0,0 +1,89 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#ifndef __MPCC_DEF__ +#define __MPCC_DEF__ + +#ifndef __GNUC__ + +typedef __SIZE_TYPE__ size_t; + +#ifdef __LP64__ +typedef long int ssize_t; +#else +typedef int ssize_t; +#endif // __LP64__ + +typedef size_t ptrdiff_t; +typedef size_t uintptr_t; +typedef void* voidptr_t; +typedef void* any_t; +typedef char* caddr_t; + +#ifndef NULL +#define NULL ((voidptr_t)0) +#endif // !null + +#ifdef __GNUC__ +#include +#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#elif defined(__MPCC__) + +#define __alloca(sz) __mpcc_alloca(sz) +#endif + +#define __deref(ptr) (*(ptr)) + +#ifdef __cplusplus +#define __init_decl() \ + extern "C" \ + { +#define __fini_decl() \ + } \ + ; +#else +#define __init_decl() +#define __fini_decl() +#endif + +#if __has_builtin(__builtin_alloca) +#define alloca(sz) __builtin_alloca(sz) +#ifdef __alloca +#undef __alloca +#endif +#define __alloca alloca +#else +#warning alloca not detected (MPCC) +#endif + +typedef long long off_t; +typedef unsigned long long uoff_t; + +typedef union float_cast { + struct + { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int sign : 1; + }; + + float f; +} __attribute__((packed)) float_cast_t; + +typedef union double_cast { + struct + { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; +} __attribute__((packed)) double_cast_t; + +#endif // ifndef __GNUC__ + +#endif /* __MPCC_DEF__ */ diff --git a/Common/Public/SDK/CRT/__mpcc_exception.hxx b/Common/Public/SDK/CRT/__mpcc_exception.hxx new file mode 100644 index 0000000..9366102 --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_exception.hxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +/// This file is an implementation of __throw* family of functions. + +#include +#include +#include + +namespace std +{ + inline void __throw_general(void) + { + throw std::runtime_error("MPCC C++ Runtime error."); + } + + inline void __throw_domain_error(const char* error) + { + std::cout << "MPCC C++: Domain error: " << error << "\r"; + __throw_general(); + } +} // namespace std diff --git a/Common/Public/SDK/CRT/__mpcc_hint.hxx b/Common/Public/SDK/CRT/__mpcc_hint.hxx new file mode 100644 index 0000000..ee14711 --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_hint.hxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#pragma compiler(hint_manifest) + +#define _Input +#define _Output + +#define _Optional + +#define _StrictCheckInput +#define _StrictCheckOutput + +#define _InOut +#define _StrictInOut diff --git a/Common/Public/SDK/CRT/__mpcc_malloc.hxx b/Common/Public/SDK/CRT/__mpcc_malloc.hxx new file mode 100644 index 0000000..2731868 --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_malloc.hxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +namespace stdx +{ + /// @brief allocate a new class. + /// @tparam KindClass the class type to allocate. + template + inline void* allocate(Args&&... args) + { + return new KindClass(std::forward(args)...); + } + + /// @brief free a class. + /// @tparam KindClass the class type to allocate. + template + inline void release(KindClass ptr) + { + if (!ptr) + return; + delete ptr; + } +} // namespace stdx diff --git a/Common/Public/SDK/CRT/__mpcc_power.inc b/Common/Public/SDK/CRT/__mpcc_power.inc new file mode 100644 index 0000000..9e4928c --- /dev/null +++ b/Common/Public/SDK/CRT/__mpcc_power.inc @@ -0,0 +1,35 @@ +# Path: SDK/__mpcc_power.inc +# Language: MPCC POWER Assembly support for GNU. +# Build Date: 2024-6-4 + +%ifdef __CODETOOLS__ + +%def lda li +%def sta stw +%def ldw li + +%def r0 0 +%def r1 1 +%def r2 2 +%def r3 3 +%def r4 4 +%def r5 5 +%def r6 6 +%def r7 7 +%def r8 8 +%def r9 9 +%def r10 10 +%def r11 11 +%def r12 12 +%def r13 13 +%def r14 14 +%def r15 15 +%def r16 16 +%def r17 17 +%def r18 18 +%def r19 19 +%def r20 20 + +%endif + +%def nop mr 0, 0 diff --git a/Common/StdKit/AE.hpp b/Common/StdKit/AE.hpp new file mode 100644 index 0000000..9c4ac1a --- /dev/null +++ b/Common/StdKit/AE.hpp @@ -0,0 +1,143 @@ +/* + * ======================================================== + * + * MPCC + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include + +#define kAEMag0 'A' +#define kAEMag1 'E' + +#define kAESymbolLen 64 +#define kAEPad 8 +#define kAEMagLen 2 +#define kAEInvalidOpcode 0x00 + +// Advanced Executable File Format for MetroLink. +// Reloctable by offset is the default strategy. +// You can also relocate at runtime but that's up to the operating system +// loader. + +namespace CompilerKit +{ + // @brief Advanced Executable Header + // One thing to keep in mind. + // This object format, is reloctable. + typedef struct AEHeader final + { + CharType fMagic[kAEMagLen]; + CharType fArch; + CharType fSubArch; + SizeType fCount; + CharType fSize; + SizeType fStartCode; + SizeType fCodeSize; + CharType fPad[kAEPad]; + } PACKED AEHeader, *AEHeaderPtr; + + // @brief Advanced Executable Record. + // Could be data, code or bss. + // fKind must be filled with PEF fields. + + typedef struct AERecordHeader final + { + CharType fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + CharType fPad[kAEPad]; + } PACKED AERecordHeader, *AERecordHeaderPtr; + + enum + { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, + }; +} // namespace CompilerKit + +// provide operator<< for AE + +std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); + + return fp; +} + +std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); + + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); + return fp; +} + +namespace CompilerKit::Utils +{ + /** + * @brief AE Reader protocol + * + */ + class AEReadableProtocol final + { + public: + std::ifstream FP; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + MPCC_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) + { + if (!raw) + return nullptr; + + return this->_Read(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template + TypeClass* _Read(char* raw, std::size_t sz) + { + FP.read(raw, std::streamsize(sz)); + return reinterpret_cast(raw); + } + }; +} // namespace CompilerKit::Utils diff --git a/Common/StdKit/ELF.hpp b/Common/StdKit/ELF.hpp new file mode 100644 index 0000000..4f0d0ae --- /dev/null +++ b/Common/StdKit/ELF.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include +#include + +struct file; + +#ifndef elf_read_implies_exec +/* Executables for which elf_read_implies_exec() returns TRUE will + have the READ_IMPLIES_EXEC personality flag set automatically. + Override in asm/elf.h as needed. */ +#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 +#endif + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uintptr_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x)&0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* POWER VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; diff --git a/Common/StdKit/ErrorID.hpp b/Common/StdKit/ErrorID.hpp new file mode 100644 index 0000000..9f12ab2 --- /dev/null +++ b/Common/StdKit/ErrorID.hpp @@ -0,0 +1,22 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +#define MPCC_EXEC_ERROR -30 +#define MPCC_FILE_NOT_FOUND -31 +#define MPCC_DIR_NOT_FOUND -32 +#define MPCC_FILE_EXISTS -33 +#define MPCC_TOO_LONG -34 +#define MPCC_INVALID_DATA -35 +#define MPCC_UNIMPLEMENTED -36 +#define MPCC_FAT_ERROR -37 diff --git a/Common/StdKit/ErrorOr.hpp b/Common/StdKit/ErrorOr.hpp new file mode 100644 index 0000000..cf35b26 --- /dev/null +++ b/Common/StdKit/ErrorOr.hpp @@ -0,0 +1,61 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + using ErrorT = UInt32; + + template + class ErrorOr final + { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) + : mId(err) + { + } + + explicit ErrorOr(nullPtr Null) + { + } + + explicit ErrorOr(T Class) + : mRef(Class) + { + } + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref Leak() + { + return mRef; + } + + operator bool() + { + return mRef; + } + + private: + Ref mRef; + Int32 mId{0}; + }; + + using ErrorOrAny = ErrorOr; + +} // namespace CompilerKit diff --git a/Common/StdKit/PEF.hpp b/Common/StdKit/PEF.hpp new file mode 100644 index 0000000..b084f32 --- /dev/null +++ b/Common/StdKit/PEF.hpp @@ -0,0 +1,132 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @file PEF.hpp +// @brief Preferred Executable Format + +#define kPefMagic "Joy!" +#define kPefMagicFat "yoJ!" + +#define kPefExt ".exec" +#define kPefDylibExt ".lib" +#define kPefLibExt ".slib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" + +#define kPefMagicLen 5 + +#define kPefVersion 2 +#define kPefNameLen 255 + +#define kPefBaseOrigin (0x1000000) + +#define kPefStart "__ImageStart" + +namespace CompilerKit +{ + enum + { + kPefArchIntel86S = 100, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* 64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, + }; + + enum + { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchARM, + kPefSubArchIBM, + }; + + enum + { + kPefKindExec = 1, /* .exe */ + kPefKindSharedObject = 2, /* .lib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, + }; + + /* PEF container */ + typedef struct PEFContainer final + { + CharType Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ + } PACKED PEFContainer; + + /* First PEFCommandHeader starts after PEFContainer */ + /* Last container is __exec_end */ + + /* PEF executable section and commands. */ + + typedef struct PEFCommandHeader final + { + CharType Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* file offset */ + SizeType Size; /* file size */ + } PACKED PEFCommandHeader; + + enum + { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, + kPefInvalid = 0xFF, + }; +} // namespace CompilerKit + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} diff --git a/Common/StdKit/Ref.hpp b/Common/StdKit/Ref.hpp new file mode 100644 index 0000000..d13f97c --- /dev/null +++ b/Common/StdKit/Ref.hpp @@ -0,0 +1,91 @@ + +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +namespace CompilerKit +{ + // @author Amlal EL Mahrouss + // @brief Reference class, refers to a pointer of data in static memory. + template + class Ref final + { + public: + explicit Ref() = default; + ~Ref() = default; + + public: + explicit Ref(T cls, const bool& strong = false) + : m_Class(cls), m_Strong(strong) + { + } + + Ref& operator=(T ref) + { + m_Class = ref; + return *this; + } + + public: + T operator->() const + { + return m_Class; + } + + T& Leak() + { + return m_Class; + } + + T operator*() + { + return m_Class; + } + + bool IsStrong() const + { + return m_Strong; + } + + operator bool() + { + return m_Class; + } + + private: + T m_Class; + bool m_Strong{false}; + }; + + template + class NonNullRef final + { + public: + NonNullRef() = delete; + NonNullRef(nullPtr) = delete; + + explicit NonNullRef(T* ref) + : m_Ref(ref, true) + { + } + + Ref& operator->() + { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef& ref) = delete; + NonNullRef(const NonNullRef& ref) = default; + + private: + Ref m_Ref{nullptr}; + }; +} // namespace CompilerKit diff --git a/Common/StdKit/String.hpp b/Common/StdKit/String.hpp new file mode 100644 index 0000000..a05a31c --- /dev/null +++ b/Common/StdKit/String.hpp @@ -0,0 +1,90 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + /** + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + + class StringView final + { + public: + explicit StringView() = delete; + + explicit StringView(SizeType Sz) noexcept + : m_Sz(Sz) + { + m_Data = new char[Sz]; + assert(m_Data); + } + + ~StringView() noexcept + { + if (m_Data) + { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + MPCC_COPY_DEFAULT(StringView); + + CharType* Data(); + const CharType* CData() const; + SizeType Length() const; + + bool operator==(const CharType* rhs) const; + bool operator!=(const CharType* rhs) const; + + bool operator==(const StringView& rhs) const; + bool operator!=(const StringView& rhs) const; + + StringView& operator+=(const CharType* rhs); + StringView& operator+=(const StringView& rhs); + + operator bool() + { + return m_Data && m_Data[0] != 0; + } + + bool operator!() + { + return !m_Data || m_Data[0] == 0; + } + + private: + char* m_Data{nullptr}; + SizeType m_Sz{0}; + SizeType m_Cur{0}; + + friend class StringBuilder; + }; + + /** + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ + struct StringBuilder final + { + static StringView Construct(const CharType* data); + static const char* FromInt(const char* fmt, int n); + static const char* FromBool(const char* fmt, bool n); + static const char* Format(const char* fmt, const char* from); + static bool Equals(const char* lhs, const char* rhs); + }; +} // namespace CompilerKit diff --git a/Common/StdKit/XCOFF.hxx b/Common/StdKit/XCOFF.hxx new file mode 100644 index 0000000..a26b591 --- /dev/null +++ b/Common/StdKit/XCOFF.hxx @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: XCOFF.hpp + Purpose: XCOFF for NewOS. + + Revision History: + + 04/07/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __XCOFF__ +#define __XCOFF__ + +#include + +#define kXCOFF64Magic 0x01F7 + +#define kXCOFFRelFlg 0x0001 +#define kXCOFFExecutable 0x0002 +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace CompilerKit +{ + /// @brief XCoff identification header. + typedef struct XCoffFileHeader + { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header + } XCoffFileHeader; +} // namespace CompilerKit + +#endif // ifndef __XCOFF__ \ No newline at end of file diff --git a/Common/UUID.hpp b/Common/UUID.hpp new file mode 100644 index 0000000..00b153b --- /dev/null +++ b/Common/UUID.hpp @@ -0,0 +1,983 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define LIBUUID_CPP20_OR_GREATER +#endif + +#endif + +#ifdef LIBUUID_CPP20_OR_GREATER +#include +#else +#include +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#ifdef UUID_TIME_GENERATOR +#include +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#endif + +namespace uuids +{ +#ifdef __cpp_lib_span + template + using span = std::span; +#else + template + using span = gsl::span; +#endif + + namespace detail + { + template + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept + { + if (ch >= static_cast('0') && ch <= static_cast('9')) + return static_cast(ch - static_cast('0')); + if (ch >= static_cast('a') && ch <= static_cast('f')) + return static_cast(10 + ch - static_cast('a')); + if (ch >= static_cast('A') && ch <= static_cast('F')) + return static_cast(10 + ch - static_cast('A')); + return 0; + } + + template + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept + { + return (ch >= static_cast('0') && ch <= static_cast('9')) || + (ch >= static_cast('a') && ch <= static_cast('f')) || + (ch >= static_cast('A') && ch <= static_cast('F')); + } + + template + [[nodiscard]] constexpr std::basic_string_view to_string_view( + TChar const* str) noexcept + { + if (str) + return str; + return {}; + } + + template + [[nodiscard]] constexpr std::basic_string_view + to_string_view(StringType const& str) noexcept + { + return str; + } + + class sha1 + { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate( + uint32_t value, size_t const count) noexcept + { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() + { + reset(); + } + + void reset() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) + { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) + { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) + { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) + { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) + { + const uint8_t* block = static_cast(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) + { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) + { + while (m_blockByteIndex != 0) + { + process_byte(0); + } + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + else + { + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast((bitCount >> 24) & 0xFF)); + process_byte(static_cast((bitCount >> 16) & 0xFF)); + process_byte(static_cast((bitCount >> 8) & 0xFF)); + process_byte(static_cast((bitCount)&0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) + { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast(d32[0] >> 24); + digest[di++] = static_cast(d32[0] >> 16); + digest[di++] = static_cast(d32[0] >> 8); + digest[di++] = static_cast(d32[0] >> 0); + + digest[di++] = static_cast(d32[1] >> 24); + digest[di++] = static_cast(d32[1] >> 16); + digest[di++] = static_cast(d32[1] >> 8); + digest[di++] = static_cast(d32[1] >> 0); + + digest[di++] = static_cast(d32[2] >> 24); + digest[di++] = static_cast(d32[2] >> 16); + digest[di++] = static_cast(d32[2] >> 8); + digest[di++] = static_cast(d32[2] >> 0); + + digest[di++] = static_cast(d32[3] >> 24); + digest[di++] = static_cast(d32[3] >> 16); + digest[di++] = static_cast(d32[3] >> 8); + digest[di++] = static_cast(d32[3] >> 0); + + digest[di++] = static_cast(d32[4] >> 24); + digest[di++] = static_cast(d32[4] >> 16); + digest[di++] = static_cast(d32[4] >> 8); + digest[di++] = static_cast(d32[4] >> 0); + + return digest; + } + + private: + void process_block() + { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) + { + w[i] = static_cast(m_block[i * 4 + 0] << 24); + w[i] |= static_cast(m_block[i * 4 + 1] << 16); + w[i] |= static_cast(m_block[i * 4 + 2] << 8); + w[i] |= static_cast(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) + { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) + { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) + { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid[37] = + L"00000000-0000-0000-0000-000000000000"; + + template + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; + } // namespace detail + + // -------------------------------------------------------------------------------------------------------------------------- + // UUID format https://tools.ietf.org/html/rfc4122 + // -------------------------------------------------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------------------------------------------------- + // Field NDR Data Type Octet # Note + // -------------------------------------------------------------------------------------------------------------------------- + // time_low unsigned long 0 - 3 The low field + // of the timestamp. time_mid unsigned short 4 - 5 + // The middle field of the timestamp. time_hi_and_version unsigned + // short 6 - 7 The high field of the timestamp multiplexed + // with the version number. clock_seq_hi_and_reserved unsigned small 8 + // The high field of the clock sequence multiplexed with the variant. + // clock_seq_low unsigned small 9 The low + // field of the clock sequence. node character 10 + // - 15 The spatially unique node identifier. + // -------------------------------------------------------------------------------------------------------------------------- + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // -------------------------------------------------------------------------------------------------------------------------- + // enumerations + // -------------------------------------------------------------------------------------------------------------------------- + + // indicated by a bit pattern in octet 8, marked with N in + // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx + enum class uuid_variant + { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved + }; + + // indicated by a bit pattern in octet 6, marked with M in + // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx + enum class uuid_version + { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = + 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = + 5 // The name-based version specified in RFS 4122 with SHA1 hashing + }; + + // Forward declare uuid & to_string so that we can declare to_string as a friend + // later. + class uuid; + template , class Allocator = std::allocator> + std::basic_string to_string(uuid const& id); + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid class + // -------------------------------------------------------------------------------------------------------------------------- + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept + { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array const& arr) noexcept + : data{arr} + { + } + + explicit uuid(span bytes) + { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template + explicit uuid(ForwardIterator first, ForwardIterator last) + { + if (std::distance(first, last) == 16) + std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept + { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept + { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept + { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) + return false; + return true; + } + + void swap(uuid& other) noexcept + { + data.swap(other.data); + } + + [[nodiscard]] inline span as_bytes() const + { + return span( + reinterpret_cast(data.data()), 16); + } + + template + [[nodiscard]] constexpr static bool is_valid_uuid( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) + return false; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return false; + } + + if (firstDigit) + { + firstDigit = false; + } + else + { + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return false; + } + + return true; + } + + template + [[nodiscard]] constexpr static std::optional from_string( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array data{{0}}; + + if (str.empty()) + return {}; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return {}; + } + + if (firstDigit) + { + data[index] = static_cast(detail::hex2char(str[i]) << 4); + firstDigit = false; + } + else + { + data[index] = + static_cast(data[index] | detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return {}; + } + + return uuid{data}; + } + + private: + std::array data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template + friend std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id); + + template + friend std::basic_string to_string(uuid const& id); + + friend std::hash; + }; + + // -------------------------------------------------------------------------------------------------------------------------- + // operators and non-member functions + // -------------------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] inline bool operator==(uuid const& lhs, + uuid const& rhs) noexcept + { + return lhs.data == rhs.data; + } + + [[nodiscard]] inline bool operator!=(uuid const& lhs, + uuid const& rhs) noexcept + { + return !(lhs == rhs); + } + + [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data < rhs.data; + } + + template + [[nodiscard]] inline std::basic_string to_string( + uuid const& id) + { + std::basic_string uustr{detail::empty_guid}; + + for (size_t i = 0, index = 0; i < 36; ++i) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + continue; + } + uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; + uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; + index++; + } + + return uustr; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id) + { + s << to_string(id); + return s; + } + + inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept + { + lhs.swap(rhs); + } + + // -------------------------------------------------------------------------------------------------------------------------- + // namespace IDs that could be used for generating name-based uuids + // -------------------------------------------------------------------------------------------------------------------------- + + // Name string is a fully-qualified domain name + static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is a URL + static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an ISO OID (See https://oidref.com/, + // https://en.wikipedia.org/wiki/Object_identifier) + static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an X.500 DN, in DER or a text output format (See + // https://en.wikipedia.org/wiki/X.500, + // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) + static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid generators + // -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR + class uuid_system_generator + { + public: + using result_type = uuid; + + uuid operator()() + { +#ifdef _WIN32 + + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) + { + throw std::system_error(hr, std::system_category(), + "CoCreateGuid failed"); + } + + std::array bytes = { + {static_cast((newId.Data1 >> 24) & 0xFF), + static_cast((newId.Data1 >> 16) & 0xFF), + static_cast((newId.Data1 >> 8) & 0xFF), + static_cast((newId.Data1) & 0xFF), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xFF), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], + newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], + id[6], id[7], id[8], id[9], id[10], + id[11], id[12], id[13], id[14], id[15]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array arrbytes = { + {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, + bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, + bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, + bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; +#else + return uuid{}; +#endif + } + }; +#endif + + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) + : generator(&gen, [](auto) {}) + { + } + explicit basic_uuid_random_generator(engine_type* gen) + : generator(gen, [](auto) {}) + { + } + + [[nodiscard]] uuid operator()() + { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution distribution; + std::shared_ptr generator; + }; + + using uuid_random_generator = basic_uuid_random_generator; + + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept + : nsuuid(namespace_uuid) + { + } + + template + [[nodiscard]] uuid operator()(StringType const& name) + { + reset(); + process_characters(detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() + { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template + void process_characters(std::basic_string_view const str) + { + for (uint32_t c : str) + { + hasher.process_byte(static_cast(c & 0xFF)); + if constexpr (!std::is_same_v) + { + hasher.process_byte(static_cast((c >> 8) & 0xFF)); + hasher.process_byte(static_cast((c >> 16) & 0xFF)); + hasher.process_byte(static_cast((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() + { + detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + detail::sha1 hasher; + }; + +#ifdef UUID_TIME_GENERATOR + // !!! DO NOT USE THIS IN PRODUCTION + // this implementation is unreliable for good uuids + class uuid_time_generator + { + using mac_address = std::array; + + std::optional device_address; + + [[nodiscard]] bool get_mac_address() + { + if (device_address.has_value()) + { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) + return false; + std::vector buf(len); + auto pips = reinterpret_cast(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) + return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() + { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = + std::chrono::duration_cast(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() + { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() + { + if (get_mac_address()) + { + std::array data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } + }; +#endif +} // namespace uuids + +namespace std +{ + template <> + struct hash + { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const + { +#ifdef UUID_HASH_STRING_BASED + std::hash hasher; + return static_cast(hasher(uuids::to_string(uuid))); +#else + uint64_t l = static_cast(uuid.data[0]) << 56 | + static_cast(uuid.data[1]) << 48 | + static_cast(uuid.data[2]) << 40 | + static_cast(uuid.data[3]) << 32 | + static_cast(uuid.data[4]) << 24 | + static_cast(uuid.data[5]) << 16 | + static_cast(uuid.data[6]) << 8 | + static_cast(uuid.data[7]); + uint64_t h = static_cast(uuid.data[8]) << 56 | + static_cast(uuid.data[9]) << 48 | + static_cast(uuid.data[10]) << 40 | + static_cast(uuid.data[11]) << 32 | + static_cast(uuid.data[12]) << 24 | + static_cast(uuid.data[13]) << 16 | + static_cast(uuid.data[14]) << 8 | + static_cast(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) + { + return result_type(l ^ h); + } + else + { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } + }; +} // namespace std + +#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Common/Version.hxx b/Common/Version.hxx new file mode 100644 index 0000000..377a688 --- /dev/null +++ b/Common/Version.hxx @@ -0,0 +1,3 @@ +#pragma once + +#define kDistVersion "v1.20" diff --git a/Documentation/ASM_SPECS.TXT b/Documentation/ASM_SPECS.TXT deleted file mode 100644 index a0c42bf..0000000 --- a/Documentation/ASM_SPECS.TXT +++ /dev/null @@ -1,11 +0,0 @@ -==================== -X86 ASSEMBLER SPECS -==================== - -WHAT TO DO: - Provide a complete support of x86-64 with: - - - org directive. - - 64-bit and 32-bit registers. - - basic instructions (load, store, jump to) - - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Documentation/HAVP.TXT b/Documentation/HAVP.TXT deleted file mode 100644 index 12fcec5..0000000 --- a/Documentation/HAVP.TXT +++ /dev/null @@ -1,13 +0,0 @@ -HAVP - Harvard Audio/Video Processor - -- Encoding: IBAD - -- Data path = 24 - - 16: sound data - - 8: information data - -- Register size: 32 -- Store strategy: shift registers. -- Standard registers: [ r0, r9 ] -- Floating point registers: [ f0, f2 ] -- Builtin SRAM: 512kb diff --git a/Documentation/Inside 64x0.pdf b/Documentation/Inside 64x0.pdf deleted file mode 100644 index bcd6782..0000000 Binary files a/Documentation/Inside 64x0.pdf and /dev/null differ diff --git a/Documentation/NOTICE.TXT b/Documentation/NOTICE.TXT deleted file mode 100644 index 23691da..0000000 --- a/Documentation/NOTICE.TXT +++ /dev/null @@ -1,4 +0,0 @@ -The X64000 draft papers -They contain thing that might appear through the next iteration of 64k. - -Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Documentation/VNRP.TXT b/Documentation/VNRP.TXT deleted file mode 100644 index e17b494..0000000 --- a/Documentation/VNRP.TXT +++ /dev/null @@ -1,17 +0,0 @@ -VNRP - Von Neumann, RISC Processor - -- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs - -- Data path = 128-bit (register data) -- Addressing = 58-bit physical address size. - -- Registers (128-bit) = r0, r19 -- Float/Vector registers (128-bit) = f0, f9 - -- Out of order (superscalar also added to the equation) = Yes -- Superscalar = Yes - -- L1 cache: 16kb (8 instr, 8 data) -- L2 cache: 1024kb (512 instr, 512 data) - -- Clock speed: 1 Ghz diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp deleted file mode 100644 index d22ec21..0000000 --- a/Headers/AsmKit/AsmKit.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include -#include - -namespace CompilerKit -{ - // - // @brief Frontend to Assembly mountpoint. - // - class AssemblyInterface - { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - MPCC_COPY_DEFAULT(AssemblyInterface); - - //@ brief compile to object file. - // Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; - }; - - /// @brief Simple assembly factory - class AssemblyFactory final - { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - MPCC_COPY_DEFAULT(AssemblyFactory); - - public: - enum - { - kArchAMD64, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchUnknown, - }; - - Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; - }; - - union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; - }; - - union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) - : raw(raw) - { - } - ~NumberCast64() - { - raw = 0; - } - - CharType number[8]; - UInt64 raw; - }; - - union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) - : raw(raw) - { - } - ~NumberCast32() - { - raw = 0; - } - - CharType number[4]; - UInt32 raw; - }; - - union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) - : raw(raw) - { - } - ~NumberCast16() - { - raw = 0; - } - - CharType number[2]; - UInt16 raw; - }; - - union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) - : raw(raw) - { - } - ~NumberCast8() - { - raw = 0; - } - - CharType number; - UInt8 raw; - }; - - class EncoderInterface - { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - MPCC_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string& line, const std::string& file) = 0; - virtual bool WriteLine(std::string& line, const std::string& file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; - }; - -#ifdef __ASM_NEED_AMD64__ - - class EncoderAMD64 final : public EncoderInterface - { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - MPCC_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); - }; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_64x0__ - - class Encoder64x0 final : public EncoderInterface - { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - MPCC_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - - class Encoder32x0 final : public EncoderInterface - { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - MPCC_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - - class EncoderPowerPC final : public EncoderInterface - { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - MPCC_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp deleted file mode 100644 index 4d66da5..0000000 --- a/Headers/AsmKit/CPU/32x0.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @brief 32x0 support. -// @file CPU/32x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 - -#define kAsmByte 0 -#define kAsmHWord 1 -#define kAsmWord 2 - -struct CpuCode32x0 -{ - const char fName[32]; - char fOpcode; - char fSize; - char fFunct3; - char fFunct7; -}; - -#define kAsmDWordStr ".dword" /* 64 bit */ -#define kAsmWordStr ".word" /* 32-bit */ -#define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ - -inline std::vector kOpcodes32x0 = { - kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. - kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch - kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers - kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp - kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. - kAsmOpcodeDecl("cls", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR. - kAsmOpcodeDecl("rts", 0b0111011, 0b110, - kAsmImmediate) // pull stack and return form CR. - kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt -}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: TODO: find one -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp deleted file mode 100644 index 974f346..0000000 --- a/Headers/AsmKit/CPU/64x0.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -// @brief 64x0 support. -// @file CPU/64x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 - -typedef char e64k_character_t; -typedef uint8_t e64k_num_t; - -struct CpuOpcode64x0 -{ - const e64k_character_t fName[32]; - e64k_num_t fOpcode; - e64k_num_t fFunct3; - e64k_num_t fFunct7; -}; - -inline std::vector kOpcodes64x0 = { - kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) - kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) - kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL/JUMP ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp deleted file mode 100644 index 8f7e05c..0000000 --- a/Headers/AsmKit/CPU/amd64.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @brief AMD64 support. -// @file CPU/amd64.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, - -typedef char i64_character_t; -typedef uint8_t i64_byte_t; -typedef uint16_t i64_hword_t; -typedef uint32_t i64_word_t; - -struct CpuOpcodeAMD64 -{ - std::string fName; - i64_byte_t fPrefixBytes[4]; - i64_hword_t fOpcode; - i64_hword_t fModReg; - i64_word_t fDisplacment; - i64_word_t fImmediate; -}; - -/// these two are edge cases -#define kAsmIntOpcode 0xCC -#define kasmIntOpcodeAlt 0xCD - -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 -#define kJumpLimitStandardLimit 0xEB - -inline std::vector kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF)}; - -#define kAsmRegisterLimit 15 diff --git a/Headers/AsmKit/CPU/ppc.hpp b/Headers/AsmKit/CPU/ppc.hpp deleted file mode 100644 index c4265da..0000000 --- a/Headers/AsmKit/CPU/ppc.hpp +++ /dev/null @@ -1,1919 +0,0 @@ -#pragma once - -#include - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -/* - * These defines are use in the cpus field of the instructions. If the field - * is zero it can execute on all cpus. The defines are or'ed together. This - * information is used to set the cpusubtype in the resulting object file. - */ -#define CPU601 0x1 -#define IMPL64 0x2 -#define OPTIONAL 0x4 -#define VMX 0x8 -#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ -#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ - -enum optype -{ - NONE, /* no operand */ - JBSR, /* jbsr pseudo op */ - PCREL, /* PC relative (branch offset) */ - BADDR, /* Branch address (sign extended absolute address) */ - D, /* 16 bit displacement */ - DS, /* 14 bit displacement (double word) */ - SI, /* signed 16 bit immediate */ - UI, /* unsigned 16 bit immediate */ - HI, /* high 16 bit immediate (with truncation) */ - GREG, /* general register */ - G0REG, /* general register r1-r31 or 0 */ - FREG, /* float register */ - VREG, /* vector register */ - SGREG, /* segment register */ - SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ - BCND, /* branch condition opcode */ - CRF, /* condition register field */ - CRFONLY, /* condition register field only no expression allowed */ - sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ - mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ - NUM, /* number */ - SNUM, /* signed number */ - NUM0, /* number (where 1< - -#define SizeType size_t - -#define VoidPtr void* -#define voidPtr VoidPtr - -#define UIntPtr uintptr_t - -#define Int64 int64_t -#define UInt64 uint64_t - -#define Int32 int -#define UInt32 unsigned - -#define Bool bool - -#define Int16 int16_t -#define UInt16 uint16_t - -#define Int8 int8_t -#define UInt8 uint8_t - -#define CharType char -#define Boolean bool - -#include -#include -#include - -#define nullPtr std::nullptr_t - -#define MUST_PASS(E) assert(E) - -#ifndef __FORCE_STRLEN -#define __FORCE_STRLEN 1 - -#define string_length(len) strlen(len) -#endif - -#ifndef __FORCE_MEMCPY -#define __FORCE_MEMCPY 1 - -#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) -#endif - -#define MPCC_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define MPCC_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define MPCC_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define MPCC_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#include -#include -#include -#include - -namespace CompilerKit -{ - inline constexpr int BASE_YEAR = 1900; - - inline std::string current_date() noexcept - { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); - - return fmt; - } - - inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept - { - if (limit == 0) - return false; - - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; - - while (limit != 1) - { - ret = ret % 10; - str[cnt] = ret; - - ++cnt; - --limit; - --ret; - } - - str[copy_limit] = '\0'; - return true; - } -} // namespace CompilerKit - -#define PACKED __attribute__((packed)) - -typedef char char_type; - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { \ - ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ - } - -#ifdef __MODULE_NEED__ -#define MPCC_MODULE(name) int name(int argc, char** argv) -#else -#define MPCC_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __MODULE_NEED__ */ - -#pragma scalar_storage_order big - endian - -#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp deleted file mode 100644 index f77dba9..0000000 --- a/Headers/ParserKit.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -namespace ParserKit -{ - using namespace CompilerKit; - - /// @brief Compiler backend, implements a frontend, such as C, C++... - /// See Toolchain, for some examples. - class CompilerBackend - { - public: - explicit CompilerBackend() = default; - virtual ~CompilerBackend() = default; - - MPCC_COPY_DEFAULT(CompilerBackend); - - // NOTE: cast this to your user defined ast. - typedef void* AstType; - - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - - virtual bool Compile(const std::string& text, const char* file) = 0; - - //! @brief What language are we dealing with? - virtual const char* Language() - { - return "Invalid Language"; - } - }; - - struct SyntaxLeafList; - struct SyntaxLeafList; - struct CompilerKeyword; - - /// we want to do that because to separate keywords. - enum KeywordKind - { - eKeywordKindNamespace, - eKeywordKindFunctionStart, - eKeywordKindFunctionEnd, - eKeywordKindVariable, - eKeywordKindType, - eKeywordKindExpressionBegin, - eKeywordKindExpressionEnd, - eKeywordKindArgSeparator, - eKeywordKindBodyStart, - eKeywordKindBodyEnd, - eKeywordKindClass, - eKeywordKindPtrAccess, - eKeywordKindAccess, - eKeywordKindIf, - eKeywordKindElse, - eKeywordKindElseIf, - eKeywordKindVariableAssign, - eKeywordKindVariableDec, - eKeywordKindVariableInc, - eKeywordKindConstant, - eKeywordKindTypedef, - eKeywordKindEndInstr, - eKeywordKindSpecifier, - eKeywordKindInvalid, - eKeywordKindReturn, - eKeywordKindCommentInline, - eKeywordKindCommentMultiLineStart, - eKeywordKindCommentMultiLineEnd, - eKeywordKindEq, - eKeywordKindNotEq, - eKeywordKindGreaterEq, - eKeywordKindLessEq, - eKeywordKindPtr, - }; - - /// \brief Compiler keyword information struct. - struct CompilerKeyword - { - std::string keyword_name; - KeywordKind keyword_kind = eKeywordKindInvalid; - }; - struct SyntaxLeafList final - { - struct SyntaxLeaf final - { - Int32 fUserType; -#ifdef __PK_USE_STRUCT_INSTEAD__ - CompilerKeyword fUserData; -#else - std::string fUserData; -#endif - - std::string fUserValue; - struct SyntaxLeaf* fNext; - }; - - std::vector fLeafList; - SizeType fNumLeafs; - - size_t SizeOf() - { - return fNumLeafs; - } - std::vector& Get() - { - return fLeafList; - } - SyntaxLeaf& At(size_t index) - { - return fLeafList[index]; - } - }; - - /// find the perfect matching word in a haystack. - /// \param haystack base string - /// \param needle the string we search for. - /// \return if we found it or not. - inline bool find_word(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) - return true; - - if (index < 0 || index >= haystack.size()) - return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); - } - - /// find a word within strict conditions and returns a range of it. - /// \param haystack - /// \param needle - /// \return position of needle. - inline std::size_t find_word_range(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) - { - return index; - } - - return false; - } -} // namespace ParserKit diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp deleted file mode 100644 index ebae770..0000000 --- a/Headers/StdKit/AE.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ======================================================== - * - * MPCC - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen 64 -#define kAEPad 8 -#define kAEMagLen 2 -#define kAEInvalidOpcode 0x00 - -// Advanced Executable File Format for MetroLink. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system -// loader. - -namespace CompilerKit -{ - // @brief Advanced Executable Header - // One thing to keep in mind. - // This object format, is reloctable. - typedef struct AEHeader final - { - CharType fMagic[kAEMagLen]; - CharType fArch; - CharType fSubArch; - SizeType fCount; - CharType fSize; - SizeType fStartCode; - SizeType fCodeSize; - CharType fPad[kAEPad]; - } PACKED AEHeader, *AEHeaderPtr; - - // @brief Advanced Executable Record. - // Could be data, code or bss. - // fKind must be filled with PEF fields. - - typedef struct AERecordHeader final - { - CharType fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - CharType fPad[kAEPad]; - } PACKED AERecordHeader, *AERecordHeaderPtr; - - enum - { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, - }; -} // namespace CompilerKit - -// provide operator<< for AE - -std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils -{ - /** - * @brief AE Reader protocol - * - */ - class AEReadableProtocol final - { - public: - std::ifstream FP; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - MPCC_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) - { - if (!raw) - return nullptr; - - return this->_Read(raw, sz * sizeof(AERecordHeader)); - } - - private: - /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ - template - TypeClass* _Read(char* raw, std::size_t sz) - { - FP.read(raw, std::streamsize(sz)); - return reinterpret_cast(raw); - } - }; -} // namespace CompilerKit::Utils diff --git a/Headers/StdKit/ELF.hpp b/Headers/StdKit/ELF.hpp deleted file mode 100644 index 4f0d0ae..0000000 --- a/Headers/StdKit/ELF.hpp +++ /dev/null @@ -1,389 +0,0 @@ -#pragma once - -#include -#include - -struct file; - -#ifndef elf_read_implies_exec -/* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif - -/* 32-bit ELF base types. */ -typedef uint32_t Elf32_Addr; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Word; - -/* 64-bit ELF base types. */ -typedef uintptr_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef int16_t Elf64_SHalf; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* These constants are for the segment types stored in the image headers */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff -#define PT_GNU_EH_FRAME 0x6474e550 - -#define PT_GNU_STACK (PT_LOOS + 0x474e551) - -/* These constants define the different elf file types */ -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 -#define ET_LOPROC 0xff00 -#define ET_HIPROC 0xffff - -/* This is the info that is needed to parse the dynamic section of the file */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_ENCODING 32 -#define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 -#define DT_VALRNGLO 0x6ffffd00 -#define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff - -/* This info is needed when parsing the symbol table */ -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 - -#define ELF_ST_BIND(x) ((x) >> 4) -#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_BIND(x) ELF_ST_BIND(x) -#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) -#define ELF64_ST_BIND(x) ELF_ST_BIND(x) -#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) - -typedef struct dynamic -{ - Elf32_Sword d_tag; - union { - Elf32_Sword d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* entry tag value */ - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - -/* The following are used with relocations */ -#define ELF32_R_SYM(x) ((x) >> 8) -#define ELF32_R_TYPE(x) ((x)&0xff) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i)&0xffffffff) - -typedef struct elf32_rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct elf64_rel -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ -} Elf64_Rel; - -typedef struct elf32_rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct elf64_rela -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ - Elf64_Sxword r_addend; /* Constant addend used to compute value */ -} Elf64_Rela; - -typedef struct elf32_sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct elf64_sym -{ - Elf64_Word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - Elf64_Half st_shndx; /* Associated section index */ - Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Xword st_size; /* Associated symbol size */ -} Elf64_Sym; - -#define EI_NIDENT 16 - -typedef struct elf32_hdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; /* Entry point */ - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Ehdr; - -typedef struct elf64_hdr -{ - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* These constants define the permissions on sections in the program - header, p_flags. */ -#define PF_R 0x4 -#define PF_W 0x2 -#define PF_X 0x1 - -typedef struct elf32_phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -typedef struct elf64_phdr -{ - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment, file & memory */ -} Elf64_Phdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_NUM 12 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xffffffff - -/* sh_flags */ -#define SHF_WRITE 0x1 -#define SHF_ALLOC 0x2 -#define SHF_EXECINSTR 0x4 -#define SHF_MASKPROC 0xf0000000 - -/* special section indexes */ -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_LOPROC 0xff00 -#define SHN_HIPROC 0xff1f -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_HIRESERVE 0xffff - -typedef struct -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; - -typedef struct elf64_shdr -{ - Elf64_Word sh_name; /* Section name, index in string tbl */ - Elf64_Word sh_type; /* Type of section */ - Elf64_Xword sh_flags; /* Miscellaneous section attributes */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Size of section in bytes */ - Elf64_Word sh_link; /* Index of another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -#define EI_MAG0 0 /* e_ident[] indexes */ -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_PAD 8 - -#define ELFMAG0 0x7f /* EI_MAG */ -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define ELFCLASSNONE 0 /* EI_CLASS */ -#define ELFCLASS32 1 -#define ELFCLASS64 2 -#define ELFCLASSNUM 3 - -#define ELFDATANONE 0 /* e_ident[EI_DATA] */ -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_NONE 0 /* e_version, EI_VERSION */ -#define EV_CURRENT 1 -#define EV_NUM 2 - -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 - -#ifndef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE -#endif - -/* Notes used in ET_CORE */ -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ -#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* POWER VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ - -/* Note header in a PT_NOTE section */ -typedef struct elf32_note -{ - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ -} Elf32_Nhdr; - -/* Note header in a PT_NOTE section */ -typedef struct elf64_note -{ - Elf64_Word n_namesz; /* Name size */ - Elf64_Word n_descsz; /* Content size */ - Elf64_Word n_type; /* Content type */ -} Elf64_Nhdr; diff --git a/Headers/StdKit/ErrorID.hpp b/Headers/StdKit/ErrorID.hpp deleted file mode 100644 index ef1f778..0000000 --- a/Headers/StdKit/ErrorID.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -#define MPCC_EXEC_ERROR -30 -#define MPCC_FILE_NOT_FOUND -31 -#define MPCC_DIR_NOT_FOUND -32 -#define MPCC_FILE_EXISTS -33 -#define MPCC_TOO_LONG -34 -#define MPCC_INVALID_DATA -35 -#define MPCC_UNIMPLEMENTED -36 -#define MPCC_FAT_ERROR -37 diff --git a/Headers/StdKit/ErrorOr.hpp b/Headers/StdKit/ErrorOr.hpp deleted file mode 100644 index d61f3e9..0000000 --- a/Headers/StdKit/ErrorOr.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - using ErrorT = UInt32; - - template - class ErrorOr final - { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(Int32 err) - : mId(err) - { - } - - explicit ErrorOr(nullPtr Null) - { - } - - explicit ErrorOr(T Class) - : mRef(Class) - { - } - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref Leak() - { - return mRef; - } - - operator bool() - { - return mRef; - } - - private: - Ref mRef; - Int32 mId{0}; - }; - - using ErrorOrAny = ErrorOr; - -} // namespace CompilerKit diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp deleted file mode 100644 index 88c20ea..0000000 --- a/Headers/StdKit/PEF.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @file PEF.hpp -// @brief Preferred Executable Format - -#define kPefMagic "Joy!" -#define kPefMagicFat "yoJ!" - -#define kPefExt ".exec" -#define kPefDylibExt ".lib" -#define kPefLibExt ".slib" -#define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" - -#define kPefMagicLen 5 - -#define kPefVersion 2 -#define kPefNameLen 255 - -#define kPefBaseOrigin (0x1000000) - -#define kPefStart "__ImageStart" - -namespace CompilerKit -{ - enum - { - kPefArchIntel86S = 100, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* 64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, - }; - - enum - { - kPefSubArchAMD, - kPefSubArchIntel, - kPefSubArchARM, - kPefSubArchIBM, - }; - - enum - { - kPefKindExec = 1, /* .exe */ - kPefKindSharedObject = 2, /* .lib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, - }; - - /* PEF container */ - typedef struct PEFContainer final - { - CharType Magic[kPefMagicLen]; - UInt32 Linker; - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - } PACKED PEFContainer; - - /* First PEFCommandHeader starts after PEFContainer */ - /* Last container is __exec_end */ - - /* PEF executable section and commands. */ - - typedef struct PEFCommandHeader final - { - CharType Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* file offset */ - SizeType Size; /* file size */ - } PACKED PEFCommandHeader; - - enum - { - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, - kPefInvalid = 0xFF, - }; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/Headers/StdKit/Ref.hpp b/Headers/StdKit/Ref.hpp deleted file mode 100644 index d13f97c..0000000 --- a/Headers/StdKit/Ref.hpp +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -namespace CompilerKit -{ - // @author Amlal EL Mahrouss - // @brief Reference class, refers to a pointer of data in static memory. - template - class Ref final - { - public: - explicit Ref() = default; - ~Ref() = default; - - public: - explicit Ref(T cls, const bool& strong = false) - : m_Class(cls), m_Strong(strong) - { - } - - Ref& operator=(T ref) - { - m_Class = ref; - return *this; - } - - public: - T operator->() const - { - return m_Class; - } - - T& Leak() - { - return m_Class; - } - - T operator*() - { - return m_Class; - } - - bool IsStrong() const - { - return m_Strong; - } - - operator bool() - { - return m_Class; - } - - private: - T m_Class; - bool m_Strong{false}; - }; - - template - class NonNullRef final - { - public: - NonNullRef() = delete; - NonNullRef(nullPtr) = delete; - - explicit NonNullRef(T* ref) - : m_Ref(ref, true) - { - } - - Ref& operator->() - { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef& ref) = delete; - NonNullRef(const NonNullRef& ref) = default; - - private: - Ref m_Ref{nullptr}; - }; -} // namespace CompilerKit diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp deleted file mode 100644 index d4048ee..0000000 --- a/Headers/StdKit/String.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - - class StringView final - { - public: - explicit StringView() = delete; - - explicit StringView(SizeType Sz) noexcept - : m_Sz(Sz) - { - m_Data = new char[Sz]; - assert(m_Data); - } - - ~StringView() noexcept - { - if (m_Data) - { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - MPCC_COPY_DEFAULT(StringView); - - CharType* Data(); - const CharType* CData() const; - SizeType Length() const; - - bool operator==(const CharType* rhs) const; - bool operator!=(const CharType* rhs) const; - - bool operator==(const StringView& rhs) const; - bool operator!=(const StringView& rhs) const; - - StringView& operator+=(const CharType* rhs); - StringView& operator+=(const StringView& rhs); - - operator bool() - { - return m_Data && m_Data[0] != 0; - } - - bool operator!() - { - return !m_Data || m_Data[0] == 0; - } - - private: - char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; - }; - - /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ - struct StringBuilder final - { - static StringView Construct(const CharType* data); - static const char* FromInt(const char* fmt, int n); - static const char* FromBool(const char* fmt, bool n); - static const char* Format(const char* fmt, const char* from); - static bool Equals(const char* lhs, const char* rhs); - }; -} // namespace CompilerKit diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx deleted file mode 100644 index d339daa..0000000 --- a/Headers/StdKit/XCOFF.hxx +++ /dev/null @@ -1,41 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - - File: XCOFF.hpp - Purpose: XCOFF for NewOS. - - Revision History: - - 04/07/24: Added file (amlel) - -------------------------------------------- */ - -#ifndef __XCOFF__ -#define __XCOFF__ - -#include - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit -{ - /// @brief XCoff identification header. - typedef struct XCoffFileHeader - { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header - } XCoffFileHeader; -} // namespace CompilerKit - -#endif // ifndef __XCOFF__ \ No newline at end of file diff --git a/Headers/UUID.hpp b/Headers/UUID.hpp deleted file mode 100644 index 00b153b..0000000 --- a/Headers/UUID.hpp +++ /dev/null @@ -1,983 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus - -#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define LIBUUID_CPP20_OR_GREATER -#endif - -#endif - -#ifdef LIBUUID_CPP20_OR_GREATER -#include -#else -#include -#endif - -#ifdef _WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#ifdef UUID_TIME_GENERATOR -#include -#pragma comment(lib, "IPHLPAPI.lib") -#endif - -#elif defined(__linux__) || defined(__unix__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#elif defined(__APPLE__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#endif - -namespace uuids -{ -#ifdef __cpp_lib_span - template - using span = std::span; -#else - template - using span = gsl::span; -#endif - - namespace detail - { - template - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept - { - if (ch >= static_cast('0') && ch <= static_cast('9')) - return static_cast(ch - static_cast('0')); - if (ch >= static_cast('a') && ch <= static_cast('f')) - return static_cast(10 + ch - static_cast('a')); - if (ch >= static_cast('A') && ch <= static_cast('F')) - return static_cast(10 + ch - static_cast('A')); - return 0; - } - - template - [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast('0') && ch <= static_cast('9')) || - (ch >= static_cast('a') && ch <= static_cast('f')) || - (ch >= static_cast('A') && ch <= static_cast('F')); - } - - template - [[nodiscard]] constexpr std::basic_string_view to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template - [[nodiscard]] constexpr std::basic_string_view - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast(start); - const uint8_t* finish = static_cast(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast((bitCount >> 24) & 0xFF)); - process_byte(static_cast((bitCount >> 16) & 0xFF)); - process_byte(static_cast((bitCount >> 8) & 0xFF)); - process_byte(static_cast((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast(d32[0] >> 24); - digest[di++] = static_cast(d32[0] >> 16); - digest[di++] = static_cast(d32[0] >> 8); - digest[di++] = static_cast(d32[0] >> 0); - - digest[di++] = static_cast(d32[1] >> 24); - digest[di++] = static_cast(d32[1] >> 16); - digest[di++] = static_cast(d32[1] >> 8); - digest[di++] = static_cast(d32[1] >> 0); - - digest[di++] = static_cast(d32[2] >> 24); - digest[di++] = static_cast(d32[2] >> 16); - digest[di++] = static_cast(d32[2] >> 8); - digest[di++] = static_cast(d32[2] >> 0); - - digest[di++] = static_cast(d32[3] >> 24); - digest[di++] = static_cast(d32[3] >> 16); - digest[di++] = static_cast(d32[3] >> 8); - digest[di++] = static_cast(d32[3] >> 0); - - digest[di++] = static_cast(d32[4] >> 24); - digest[di++] = static_cast(d32[4] >> 16); - digest[di++] = static_cast(d32[4] >> 8); - digest[di++] = static_cast(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast(m_block[i * 4 + 0] << 24); - w[i] |= static_cast(m_block[i * 4 + 1] << 16); - w[i] |= static_cast(m_block[i * 4 + 2] << 8); - w[i] |= static_cast(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid[37] = - L"00000000-0000-0000-0000-000000000000"; - - template - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; - } // namespace detail - - // -------------------------------------------------------------------------------------------------------------------------- - // UUID format https://tools.ietf.org/html/rfc4122 - // -------------------------------------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------------------------------------- - // Field NDR Data Type Octet # Note - // -------------------------------------------------------------------------------------------------------------------------- - // time_low unsigned long 0 - 3 The low field - // of the timestamp. time_mid unsigned short 4 - 5 - // The middle field of the timestamp. time_hi_and_version unsigned - // short 6 - 7 The high field of the timestamp multiplexed - // with the version number. clock_seq_hi_and_reserved unsigned small 8 - // The high field of the clock sequence multiplexed with the variant. - // clock_seq_low unsigned small 9 The low - // field of the clock sequence. node character 10 - // - 15 The spatially unique node identifier. - // -------------------------------------------------------------------------------------------------------------------------- - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_low | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_mid | time_hi_and_version | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |clk_seq_hi_res | clk_seq_low | node (0-1) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | node (2-5) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // -------------------------------------------------------------------------------------------------------------------------- - // enumerations - // -------------------------------------------------------------------------------------------------------------------------- - - // indicated by a bit pattern in octet 8, marked with N in - // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx - enum class uuid_variant - { - // NCS backward compatibility (with the obsolete Apollo Network Computing - // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the - // UUID are a 48-bit timestamp (the number of 4 microsecond units of time - // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet - // is the "address family"; > the final 7 octets are a 56-bit host ID in the - // form specified by the address family - ncs, - - // RFC 4122/DCE 1.1 - // N bit pattern: 10xx - // > big-endian byte order - rfc, - - // Microsoft Corporation backward compatibility - // N bit pattern: 110x - // > little endian byte order - // > formely used in the Component Object Model (COM) library - microsoft, - - // reserved for possible future definition - // N bit pattern: 111x - reserved - }; - - // indicated by a bit pattern in octet 6, marked with M in - // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx - enum class uuid_version - { - none = 0, // only possible for nil or invalid uuids - time_based = 1, // The time-based version specified in RFC 4122 - dce_security = 2, // DCE Security version, with embedded POSIX UIDs. - name_based_md5 = - 3, // The name-based version specified in RFS 4122 with MD5 hashing - random_number_based = 4, // The randomly or pseudo-randomly generated version - // specified in RFS 4122 - name_based_sha1 = - 5 // The name-based version specified in RFS 4122 with SHA1 hashing - }; - - // Forward declare uuid & to_string so that we can declare to_string as a friend - // later. - class uuid; - template , class Allocator = std::allocator> - std::basic_string to_string(uuid const& id); - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid class - // -------------------------------------------------------------------------------------------------------------------------- - class uuid - { - public: - using value_type = uint8_t; - - constexpr uuid() noexcept = default; - - uuid(value_type (&arr)[16]) noexcept - { - std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); - } - - constexpr uuid(std::array const& arr) noexcept - : data{arr} - { - } - - explicit uuid(span bytes) - { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template - explicit uuid(ForwardIterator first, ForwardIterator last) - { - if (std::distance(first, last) == 16) - std::copy(first, last, std::begin(data)); - } - - [[nodiscard]] constexpr uuid_variant variant() const noexcept - { - if ((data[8] & 0x80) == 0x00) - return uuid_variant::ncs; - else if ((data[8] & 0xC0) == 0x80) - return uuid_variant::rfc; - else if ((data[8] & 0xE0) == 0xC0) - return uuid_variant::microsoft; - else - return uuid_variant::reserved; - } - - [[nodiscard]] constexpr uuid_version version() const noexcept - { - if ((data[6] & 0xF0) == 0x10) - return uuid_version::time_based; - else if ((data[6] & 0xF0) == 0x20) - return uuid_version::dce_security; - else if ((data[6] & 0xF0) == 0x30) - return uuid_version::name_based_md5; - else if ((data[6] & 0xF0) == 0x40) - return uuid_version::random_number_based; - else if ((data[6] & 0xF0) == 0x50) - return uuid_version::name_based_sha1; - else - return uuid_version::none; - } - - [[nodiscard]] constexpr bool is_nil() const noexcept - { - for (size_t i = 0; i < data.size(); ++i) - if (data[i] != 0) - return false; - return true; - } - - void swap(uuid& other) noexcept - { - data.swap(other.data); - } - - [[nodiscard]] inline span as_bytes() const - { - return span( - reinterpret_cast(data.data()), 16); - } - - template - [[nodiscard]] constexpr static bool is_valid_uuid( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) - return false; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template - [[nodiscard]] constexpr static std::optional from_string( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - std::array data{{0}}; - - if (str.empty()) - return {}; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return {}; - } - - if (firstDigit) - { - data[index] = static_cast(detail::hex2char(str[i]) << 4); - firstDigit = false; - } - else - { - data[index] = - static_cast(data[index] | detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return {}; - } - - return uuid{data}; - } - - private: - std::array data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template - friend std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id); - - template - friend std::basic_string to_string(uuid const& id); - - friend std::hash; - }; - - // -------------------------------------------------------------------------------------------------------------------------- - // operators and non-member functions - // -------------------------------------------------------------------------------------------------------------------------- - - [[nodiscard]] inline bool operator==(uuid const& lhs, - uuid const& rhs) noexcept - { - return lhs.data == rhs.data; - } - - [[nodiscard]] inline bool operator!=(uuid const& lhs, - uuid const& rhs) noexcept - { - return !(lhs == rhs); - } - - [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept - { - return lhs.data < rhs.data; - } - - template - [[nodiscard]] inline std::basic_string to_string( - uuid const& id) - { - std::basic_string uustr{detail::empty_guid}; - - for (size_t i = 0, index = 0; i < 36; ++i) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - continue; - } - uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; - uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; - index++; - } - - return uustr; - } - - template - std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id) - { - s << to_string(id); - return s; - } - - inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept - { - lhs.swap(rhs); - } - - // -------------------------------------------------------------------------------------------------------------------------- - // namespace IDs that could be used for generating name-based uuids - // -------------------------------------------------------------------------------------------------------------------------- - - // Name string is a fully-qualified domain name - static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is a URL - static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an ISO OID (See https://oidref.com/, - // https://en.wikipedia.org/wiki/Object_identifier) - static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an X.500 DN, in DER or a text output format (See - // https://en.wikipedia.org/wiki/X.500, - // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) - static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid generators - // -------------------------------------------------------------------------------------------------------------------------- - -#ifdef UUID_SYSTEM_GENERATOR - class uuid_system_generator - { - public: - using result_type = uuid; - - uuid operator()() - { -#ifdef _WIN32 - - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); - - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } - - std::array bytes = { - {static_cast((newId.Data1 >> 24) & 0xFF), - static_cast((newId.Data1 >> 16) & 0xFF), - static_cast((newId.Data1 >> 8) & 0xFF), - static_cast((newId.Data1) & 0xFF), - - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), - - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), - - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__linux__) || defined(__unix__) - - uuid_t id; - uuid_generate(id); - - std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], - id[6], id[7], id[8], id[9], id[10], - id[11], id[12], id[13], id[14], id[15]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array arrbytes = { - {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, - bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, - bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, - bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; -#else - return uuid{}; -#endif - } - }; -#endif - - template - class basic_uuid_random_generator - { - public: - using engine_type = UniformRandomNumberGenerator; - - explicit basic_uuid_random_generator(engine_type& gen) - : generator(&gen, [](auto) {}) - { - } - explicit basic_uuid_random_generator(engine_type* gen) - : generator(gen, [](auto) {}) - { - } - - [[nodiscard]] uuid operator()() - { - alignas(uint32_t) uint8_t bytes[16]; - for (int i = 0; i < 16; i += 4) - *reinterpret_cast(bytes + i) = distribution(*generator); - - // variant must be 10xxxxxx - bytes[8] &= 0xBF; - bytes[8] |= 0x80; - - // version must be 0100xxxx - bytes[6] &= 0x4F; - bytes[6] |= 0x40; - - return uuid{std::begin(bytes), std::end(bytes)}; - } - - private: - std::uniform_int_distribution distribution; - std::shared_ptr generator; - }; - - using uuid_random_generator = basic_uuid_random_generator; - - class uuid_name_generator - { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept - : nsuuid(namespace_uuid) - { - } - - template - [[nodiscard]] uuid operator()(StringType const& name) - { - reset(); - process_characters(detail::to_string_view(name)); - return make_uuid(); - } - - private: - void reset() - { - hasher.reset(); - std::byte bytes[16]; - auto nsbytes = nsuuid.as_bytes(); - std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); - hasher.process_bytes(bytes, 16); - } - - template - void process_characters(std::basic_string_view const str) - { - for (uint32_t c : str) - { - hasher.process_byte(static_cast(c & 0xFF)); - if constexpr (!std::is_same_v) - { - hasher.process_byte(static_cast((c >> 8) & 0xFF)); - hasher.process_byte(static_cast((c >> 16) & 0xFF)); - hasher.process_byte(static_cast((c >> 24) & 0xFF)); - } - } - } - - [[nodiscard]] uuid make_uuid() - { - detail::sha1::digest8_t digest; - hasher.get_digest_bytes(digest); - - // variant must be 0b10xxxxxx - digest[8] &= 0xBF; - digest[8] |= 0x80; - - // version must be 0b0101xxxx - digest[6] &= 0x5F; - digest[6] |= 0x50; - - return uuid{digest, digest + 16}; - } - - private: - uuid nsuuid; - detail::sha1 hasher; - }; - -#ifdef UUID_TIME_GENERATOR - // !!! DO NOT USE THIS IN PRODUCTION - // this implementation is unreliable for good uuids - class uuid_time_generator - { - using mac_address = std::array; - - std::optional device_address; - - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } - -#ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) - return false; - std::vector buf(len); - auto pips = reinterpret_cast(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) - return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; -#endif - - return device_address.has_value(); - } - - [[nodiscard]] long long get_time_intervals() - { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = - std::chrono::duration_cast(diff).count(); - return ns / 100; - } - - [[nodiscard]] static unsigned short get_clock_sequence() - { - static std::mt19937 clock_gen(std::random_device{}()); - static std::uniform_int_distribution clock_dis; - static std::atomic_ushort clock_sequence = clock_dis(clock_gen); - return clock_sequence++; - } - - public: - [[nodiscard]] uuid operator()() - { - if (get_mac_address()) - { - std::array data; - - auto tm = get_time_intervals(); - - auto clock_seq = get_clock_sequence(); - - auto ptm = reinterpret_cast(&tm); - - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); - - memcpy(&data[8], &clock_seq, 2); - - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; - - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; - - memcpy(&data[10], &device_address.value()[0], 6); - - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } - - return {}; - } - }; -#endif -} // namespace uuids - -namespace std -{ - template <> - struct hash - { - using argument_type = uuids::uuid; - using result_type = std::size_t; - - [[nodiscard]] result_type operator()(argument_type const& uuid) const - { -#ifdef UUID_HASH_STRING_BASED - std::hash hasher; - return static_cast(hasher(uuids::to_string(uuid))); -#else - uint64_t l = static_cast(uuid.data[0]) << 56 | - static_cast(uuid.data[1]) << 48 | - static_cast(uuid.data[2]) << 40 | - static_cast(uuid.data[3]) << 32 | - static_cast(uuid.data[4]) << 24 | - static_cast(uuid.data[5]) << 16 | - static_cast(uuid.data[6]) << 8 | - static_cast(uuid.data[7]); - uint64_t h = static_cast(uuid.data[8]) << 56 | - static_cast(uuid.data[9]) << 48 | - static_cast(uuid.data[10]) << 40 | - static_cast(uuid.data[11]) << 32 | - static_cast(uuid.data[12]) << 24 | - static_cast(uuid.data[13]) << 16 | - static_cast(uuid.data[14]) << 8 | - static_cast(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) - { - return result_type(l ^ h); - } - else - { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } -#endif - } - }; -} // namespace std - -#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Headers/Version.hxx b/Headers/Version.hxx deleted file mode 100644 index 377a688..0000000 --- a/Headers/Version.hxx +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define kDistVersion "v1.20" diff --git a/SDK/__mpcc_alloca.hxx b/SDK/__mpcc_alloca.hxx deleted file mode 100644 index a1c638e..0000000 --- a/SDK/__mpcc_alloca.hxx +++ /dev/null @@ -1,15 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -typedef void* ptr_type; -typedef __SIZE_TYPE__ size_type; - -inline void* __mpcc_alloca_gcc(size_type sz) -{ - return __builtin_alloca(sz); -} diff --git a/SDK/__mpcc_defines.hxx b/SDK/__mpcc_defines.hxx deleted file mode 100644 index 5560410..0000000 --- a/SDK/__mpcc_defines.hxx +++ /dev/null @@ -1,89 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#ifndef __MPCC_DEF__ -#define __MPCC_DEF__ - -#ifndef __GNUC__ - -typedef __SIZE_TYPE__ size_t; - -#ifdef __LP64__ -typedef long int ssize_t; -#else -typedef int ssize_t; -#endif // __LP64__ - -typedef size_t ptrdiff_t; -typedef size_t uintptr_t; -typedef void* voidptr_t; -typedef void* any_t; -typedef char* caddr_t; - -#ifndef NULL -#define NULL ((voidptr_t)0) -#endif // !null - -#ifdef __GNUC__ -#include -#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) -#elif defined(__MPCC__) - -#define __alloca(sz) __mpcc_alloca(sz) -#endif - -#define __deref(ptr) (*(ptr)) - -#ifdef __cplusplus -#define __init_decl() \ - extern "C" \ - { -#define __fini_decl() \ - } \ - ; -#else -#define __init_decl() -#define __fini_decl() -#endif - -#if __has_builtin(__builtin_alloca) -#define alloca(sz) __builtin_alloca(sz) -#ifdef __alloca -#undef __alloca -#endif -#define __alloca alloca -#else -#warning alloca not detected (MPCC) -#endif - -typedef long long off_t; -typedef unsigned long long uoff_t; - -typedef union float_cast { - struct - { - unsigned int mantissa : 23; - unsigned int exponent : 8; - unsigned int sign : 1; - }; - - float f; -} __attribute__((packed)) float_cast_t; - -typedef union double_cast { - struct - { - unsigned long long int mantissa : 52; - unsigned int exponent : 11; - unsigned int sign : 1; - }; - - double f; -} __attribute__((packed)) double_cast_t; - -#endif // ifndef __GNUC__ - -#endif /* __MPCC_DEF__ */ diff --git a/SDK/__mpcc_exception.hxx b/SDK/__mpcc_exception.hxx deleted file mode 100644 index 9366102..0000000 --- a/SDK/__mpcc_exception.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -/// This file is an implementation of __throw* family of functions. - -#include -#include -#include - -namespace std -{ - inline void __throw_general(void) - { - throw std::runtime_error("MPCC C++ Runtime error."); - } - - inline void __throw_domain_error(const char* error) - { - std::cout << "MPCC C++: Domain error: " << error << "\r"; - __throw_general(); - } -} // namespace std diff --git a/SDK/__mpcc_hint.hxx b/SDK/__mpcc_hint.hxx deleted file mode 100644 index ee14711..0000000 --- a/SDK/__mpcc_hint.hxx +++ /dev/null @@ -1,20 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#pragma compiler(hint_manifest) - -#define _Input -#define _Output - -#define _Optional - -#define _StrictCheckInput -#define _StrictCheckOutput - -#define _InOut -#define _StrictInOut diff --git a/SDK/__mpcc_malloc.hxx b/SDK/__mpcc_malloc.hxx deleted file mode 100644 index 2731868..0000000 --- a/SDK/__mpcc_malloc.hxx +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -namespace stdx -{ - /// @brief allocate a new class. - /// @tparam KindClass the class type to allocate. - template - inline void* allocate(Args&&... args) - { - return new KindClass(std::forward(args)...); - } - - /// @brief free a class. - /// @tparam KindClass the class type to allocate. - template - inline void release(KindClass ptr) - { - if (!ptr) - return; - delete ptr; - } -} // namespace stdx diff --git a/SDK/__mpcc_power.inc b/SDK/__mpcc_power.inc deleted file mode 100644 index 9e4928c..0000000 --- a/SDK/__mpcc_power.inc +++ /dev/null @@ -1,35 +0,0 @@ -# Path: SDK/__mpcc_power.inc -# Language: MPCC POWER Assembly support for GNU. -# Build Date: 2024-6-4 - -%ifdef __CODETOOLS__ - -%def lda li -%def sta stw -%def ldw li - -%def r0 0 -%def r1 1 -%def r2 2 -%def r3 3 -%def r4 4 -%def r5 5 -%def r6 6 -%def r7 7 -%def r8 8 -%def r9 9 -%def r10 10 -%def r11 11 -%def r12 12 -%def r13 13 -%def r14 14 -%def r15 15 -%def r16 16 -%def r17 17 -%def r18 18 -%def r19 19 -%def r20 20 - -%endif - -%def nop mr 0, 0 diff --git a/Sources/32asm.cc b/Sources/32asm.cc index 4c98645..f877553 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -19,10 +19,10 @@ #define __ASM_NEED_32x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 96bdc90..6e8cc6d 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -19,10 +19,10 @@ #define __ASM_NEED_64x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index d7b7491..3a0e569 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -10,9 +10,9 @@ /// BUGS: ? /// TODO: -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index d5c0da7..0000ab7 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -4,8 +4,8 @@ ------------------------------------------- */ -#include -#include +#include +#include /** * @file AssemblyFactory.cxx diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index 36c5901..f6fdb41 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include using namespace CompilerKit; diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index bebdd7f..9ddd3a2 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include #define kZero64Section ".zero64" #define kCode64Section ".code64" diff --git a/Sources/String.cc b/Sources/String.cc index 6f7603f..38bd444 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -18,7 +18,7 @@ * */ -#include +#include #include namespace CompilerKit { diff --git a/Sources/bpp.cc b/Sources/bpp.cc index a988693..accbef5 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -9,8 +9,8 @@ /// BUGS: 0 -#include -#include +#include +#include #include #include #include diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 59a99d4..349d543 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 3622606..db33688 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -16,8 +16,8 @@ #define kSplashCxx() \ kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") -#include -#include +#include +#include #include #include #include diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index 5f838be..a451a0a 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 5f0812c..5510252 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -27,10 +27,10 @@ #define kAssemblerPragmaSymStr "#" #define kAssemblerPragmaSym '#' -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/link.cc b/Sources/link.cc index d0d330e..47406c4 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -13,23 +13,23 @@ /// note: Do not look up for anything with .code64/.data64/.zero64! /// It will be loaded when program will start up! -#include +#include //! Assembler Kit -#include +#include //! Preferred Executable Format -#include -#include +#include +#include #include #include #include //! Dist version -#include +#include //! Advanced Executable Object Format -#include +#include //! C++ I/O headers. #include diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc new file mode 100644 index 0000000..b26dbf2 --- /dev/null +++ b/Sources/power-cc.cc @@ -0,0 +1,1645 @@ +/* + * ======================================================== + * + * cc + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kOk 0 + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cc +/// @brief POWER C Compiler. + +///////////////////// + +/// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +/// INTERNAL STRUCT OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + file.erase(file.find(".pp"), 3); + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "POWER C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; +static std::vector kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) + value.erase(value.find(' '), 1); + + while (value.find("import") != std::string::npos) + value.erase(value.find("import"), strlen("import")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) + { + if (value.find(reg.fName) != std::string::npos) + { + found = true; + syntaxLeaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) + syntaxLeaf.fUserValue += "r0"; + } + + syntaxLeaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + + " \ndword export .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error( + "assignement of value inside a struct " + textBuffer, file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } + else + { + substr += "\tli "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + kCompilerVariables.push_back({.fName = substr}); + + if (textBuffer[text_index] == ';') + break; + + std::string reg = kAsmRegisterPrefix; + + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); + + auto newSubstr = substr.substr(substr.find(" ")); + + std::string symbol; + + for (size_t start = 0; start < newSubstr.size(); ++start) + { + if (newSubstr[start] == ',') + break; + + if (newSubstr[start] == ' ') + continue; + + symbol += (newSubstr[start]); + } + + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + + syntaxLeaf.fUserValue += + "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tli r31, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + + syntaxLeaf.fUserValue += "\n\tblr\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (ParserKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (ParserKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && + !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && + !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ld", "stw", "add", "sub", "or"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (ParserKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (ParserKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (ParserKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import ") != std::string::npos) + { + std::string range = "import "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), + range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +MPCC_MODULE(NewOSCompilerCLangPowerPC) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc deleted file mode 100644 index 31dc359..0000000 --- a/Sources/ppc-cc.cc +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kOk 0 - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cc -/// @brief POWER C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCT OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - file.erase(file.find(".pp"), 3); - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend -{ -public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char* text, const char* file); - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override - { - return "POWER C"; - } -}; - -static CompilerBackendCLang* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace detail -{ - union number_cast final { - public: - number_cast(UInt64 _Raw) - : _Raw(_Raw) - { - } - - public: - char _Num[8]; - UInt64 _Raw; - }; - - union double_cast final { - public: - double_cast(float _Raw) - : _Raw(_Raw) - { - } - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string& text, const char* file) -{ - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) - { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) - { - if (substr[y] == ' ') - { - while (match_type.find(' ') != std::string::npos) - { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) - { - if (clType.fName == match_type) - { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) - { - break; - } - - if (textBuffer.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) - { - if (textBuffer[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) - { - if (textBuffer[value_index] == ';') - break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("import") != std::string::npos) - value.erase(value.find("import"), strlen("import")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) - { - if (value.find(reg.fName) != std::string::npos) - { - found = true; - syntaxLeaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) - syntaxLeaf.fUserValue += "r0"; - } - - syntaxLeaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') - { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + - " \ndword export .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (textBuffer[text_index] == ';' && kInStruct) - continue; - - if (textBuffer.find("typedef ") != std::string::npos) - continue; - - if (textBuffer[text_index] == '=' && kInStruct) - { - detail::print_error( - "assignement of value inside a struct " + textBuffer, file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : textBuffer) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) - { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (textBuffer.find("*") != std::string::npos) - { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } - else - { - substr += "\tli "; - } - } - else if (textBuffer.find('=') != std::string::npos && !kInBraces) - { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') - { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - kCompilerVariables.push_back({.fName = substr}); - - if (textBuffer[text_index] == ';') - break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) - { - if (newSubstr[start] == ',') - break; - - if (newSubstr[start] == ' ') - continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntaxLeaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) - { - if (textBuffer[idx] == ',') - continue; - - if (textBuffer[idx] == ' ') - continue; - - if (textBuffer[idx] == ')') - break; - } - - for (char substr_first_index : textBuffer) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) - args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : textBuffer) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') - break; - - substr += _text_i; - } - - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - - syntaxLeaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') - { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) - { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') - { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) - kIfFound = false; - - if (kInStruct) - kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char* text, const char* file) -{ - std::string err_str; - std::string ln = text; - - if (ln.empty()) - { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (isalnum(ln[i])) - { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) - return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) - { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '\'') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } - else if (ln.find('"') != std::string::npos) - { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '"') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - else - { - break; - } - } - } - } - else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) - { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) - { - if (ln.find(forbidden) != std::string::npos) - { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final - { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, - {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, - {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, - {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, - {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, - {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, - {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, - {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, - {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, - {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) - { - if (ln.find(variable.fBegin) != std::string::npos) - { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') - ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == variable.fEnd[0]) - { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) - { - if (ln[index_keyword] == ' ') - { - continue; - } - - if (isdigit(ln[index_keyword])) - { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) - { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") - { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') - { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) - { - if (var.fValue.find(keyword) != std::string::npos) - { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) - { - if (fn.find(keyword[0]) != std::string::npos) - { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) - { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') - break; - - if (fn[where_begin] != keyword[keyword_begin]) - { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) - { - err_str.clear(); - goto cc_next; - } - else - { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) - return err_str; - - if (keyword.find(".") != std::string::npos) - return err_str; - - if (isalnum(keyword[0])) - err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (ParserKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyMountpointCLang::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerBackend->Compile(line_src, src.data()); - } - else - { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) - return -1; - - std::vector keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (ParserKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (ParserKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("import ") != std::string::npos) - { - std::string range = "import "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -MPCC_MODULE(NewOSCompilerCLangPowerPC) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) - { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) - { - if (kState.fVerbose) - { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 5c444dd..0236491 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -17,12 +17,12 @@ #define __ASM_NEED_PPC__ 1 -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/bpp.rsrc b/bpp.rsrc index 6ed8ac5..3a8d4d9 100644 --- a/bpp.rsrc +++ b/bpp.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -11,7 +11,7 @@ BEGIN BLOCK "080904E4" BEGIN VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS Assembler Preprocessor." + VALUE "FileDescription", "SoftwareLabs Preprocessor." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewPreprocessor" VALUE "LegalCopyright", "SoftwareLabs" diff --git a/docs/Inside 64x0.pdf b/docs/Inside 64x0.pdf new file mode 100644 index 0000000..bcd6782 Binary files /dev/null and b/docs/Inside 64x0.pdf differ diff --git a/docs/asm-specs.txt b/docs/asm-specs.txt new file mode 100644 index 0000000..a0c42bf --- /dev/null +++ b/docs/asm-specs.txt @@ -0,0 +1,11 @@ +==================== +X86 ASSEMBLER SPECS +==================== + +WHAT TO DO: + Provide a complete support of x86-64 with: + + - org directive. + - 64-bit and 32-bit registers. + - basic instructions (load, store, jump to) + - flushable into object-code and flat binary. \ No newline at end of file diff --git a/docs/havp.txt b/docs/havp.txt new file mode 100644 index 0000000..12fcec5 --- /dev/null +++ b/docs/havp.txt @@ -0,0 +1,13 @@ +HAVP - Harvard Audio/Video Processor + +- Encoding: IBAD + +- Data path = 24 + - 16: sound data + - 8: information data + +- Register size: 32 +- Store strategy: shift registers. +- Standard registers: [ r0, r9 ] +- Floating point registers: [ f0, f2 ] +- Builtin SRAM: 512kb diff --git a/docs/notice.txt b/docs/notice.txt new file mode 100644 index 0000000..23691da --- /dev/null +++ b/docs/notice.txt @@ -0,0 +1,4 @@ +The X64000 draft papers +They contain thing that might appear through the next iteration of 64k. + +Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/docs/vnrp.txt b/docs/vnrp.txt new file mode 100644 index 0000000..e17b494 --- /dev/null +++ b/docs/vnrp.txt @@ -0,0 +1,17 @@ +VNRP - Von Neumann, RISC Processor + +- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs + +- Data path = 128-bit (register data) +- Addressing = 58-bit physical address size. + +- Registers (128-bit) = r0, r19 +- Float/Vector registers (128-bit) = f0, f9 + +- Out of order (superscalar also added to the equation) = Yes +- Superscalar = Yes + +- L1 cache: 16kb (8 instr, 8 data) +- L2 cache: 1024kb (512 instr, 512 data) + +- Clock speed: 1 Ghz diff --git a/i64asm.rsrc b/i64asm.rsrc index 2f981a6..4472b3f 100644 --- a/i64asm.rsrc +++ b/i64asm.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -11,12 +11,12 @@ BEGIN BLOCK "080904E4" BEGIN VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS AMD64 assembler." + VALUE "FileDescription", "SoftwareLabs assembler for AMD64." VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" + VALUE "InternalName", "Assembler" VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "i64asm.exe" - VALUE "ProductName", "NewAssembler" + VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion END END diff --git a/link.rsrc b/link.rsrc index 9661b04..550d87a 100644 --- a/link.rsrc +++ b/link.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -13,10 +13,10 @@ BEGIN VALUE "CompanyName", "SoftwareLabs" VALUE "FileDescription", "NewOS linker." VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewLinker" + VALUE "InternalName", "Linker" VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "link.exe" - VALUE "ProductName", "NewLinker" + VALUE "ProductName", "Linker" VALUE "ProductVersion", kDistVersion END END diff --git a/posix.make b/posix.make index 4e47c53..0a6ef8e 100644 --- a/posix.make +++ b/posix.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail +COMMON_INC=-I./Common -I./ -I./Sources/Detail LINK_CC=g++ -std=c++20 LINK_SRC=Sources/link.cc LINK_OUTPUT=Output/link.exec @@ -30,8 +30,8 @@ AMD64_CXX_OUTPUT=Output/cplusplus.exec 64X0_CC_OUTPUT=Output/64x0-cc.exec # C Compiler (Our own RISC) -PPC_CC_SRC=Sources/ppc-cc.cc $(SRC_COMMON) -PPC_CC_OUTPUT=Output/ppc-cc.exec +PPC_CC_SRC=Sources/power-cc.cc $(SRC_COMMON) +PPC_CC_OUTPUT=Output/power-cc.exec # 64x0 Assembler (Our Own RISC) ASM_SRC=Sources/64asm.cc $(SRC_COMMON) diff --git a/power-cc.rsrc b/power-cc.rsrc new file mode 100644 index 0000000..4a10e6b --- /dev/null +++ b/power-cc.rsrc @@ -0,0 +1,27 @@ +#include "Common/Version.hxx" + +1 ICON "Icons/app-logo.ico" + +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904E4" + BEGIN + VALUE "CompanyName", "SoftwareLabs" + VALUE "FileDescription", "SoftwareLabs C Compiler for POWER." + VALUE "FileVersion", kDistVersion + VALUE "InternalName", "Compiler" + VALUE "LegalCopyright", "SoftwareLabs" + VALUE "OriginalFilename", "power-cc.exe" + VALUE "ProductName", "Compiler" + VALUE "ProductVersion", kDistVersion + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1252 + END +END diff --git a/ppc-cc.rsrc b/ppc-cc.rsrc deleted file mode 100644 index 031dd4e..0000000 --- a/ppc-cc.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS POWER C compiler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewC" - VALUE "LegalCopyright", "SoftwareLabs" - VALUE "OriginalFilename", "ppc-cc.exe" - VALUE "ProductName", "NewC" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/ppcasm.rsrc b/ppcasm.rsrc index 4d3affe..cf3fbb9 100644 --- a/ppcasm.rsrc +++ b/ppcasm.rsrc @@ -1,4 +1,4 @@ -#include "Headers/Version.hxx" +#include "Common/Version.hxx" 1 ICON "Icons/app-logo.ico" @@ -11,12 +11,12 @@ BEGIN BLOCK "080904E4" BEGIN VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "NewOS POWER assembler." + VALUE "FileDescription", "SoftwareLabs assembler for POWER." VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" + VALUE "InternalName", "Assembler" VALUE "LegalCopyright", "SoftwareLabs" VALUE "OriginalFilename", "ppcasm.exe" - VALUE "ProductName", "NewAssembler" + VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion END END diff --git a/win64.make b/win64.make index 0d8482d..1e70bfd 100644 --- a/win64.make +++ b/win64.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail +COMMON_INC=-I./Common -I./ -I./Sources/Detail LINK_CC=x86_64-w64-mingw32-g++.exe -std=c++20 -Xlinker -s WINRES=x86_64-w64-mingw32-windres LINK_SRC=Sources/link.cc @@ -30,8 +30,8 @@ AMD64_CXX_OUTPUT=Output/cplusplus.exe 64X0_CC_OUTPUT=Output/64x0-cc.exe # C Compiler -PPC_CC_SRC=Sources/ppc-cc.cc $(SRC_COMMON) -PPC_CC_OUTPUT=Output/ppc-cc.exe +PPC_CC_SRC=Sources/power-cc.cc $(SRC_COMMON) +PPC_CC_OUTPUT=Output/power-cc.exe # 64x0 Assembler ASM_SRC=Sources/64asm.cc $(SRC_COMMON) @@ -60,10 +60,10 @@ compiler: $(WINRES) 64asm.rsrc -O coff -o 64asm.obj $(WINRES) ppcasm.rsrc -O coff -o ppcasm.obj $(WINRES) 64x0-cc.rsrc -O coff -o 64x0-cc.obj - $(WINRES) ppc-cc.rsrc -O coff -o ppc-cc.obj + $(WINRES) power-cc.rsrc -O coff -o power-cc.obj $(LINK_CC) $(COMMON_INC) 64x0-cc.obj $(64X0_CC_SRC) -o $(64X0_CC_OUTPUT) $(LINK_CC) $(COMMON_INC) $(AMD64_CXX_SRC) -o $(AMD64_CXX_OUTPUT) - $(LINK_CC) $(COMMON_INC) ppc-cc.obj $(PPC_CC_SRC) -o $(PPC_CC_OUTPUT) + $(LINK_CC) $(COMMON_INC) power-cc.obj $(PPC_CC_SRC) -o $(PPC_CC_OUTPUT) $(LINK_CC) $(COMMON_INC) i64asm.obj $(IASM_SRC) -o $(IASM_OUTPUT) $(LINK_CC) $(COMMON_INC) 64asm.obj $(ASM_SRC) -o $(ASM_OUTPUT) $(LINK_CC) $(COMMON_INC) ppcasm.obj $(PPCASM_SRC) -o $(PPCASM_OUTPUT) -- cgit v1.2.3 From d0b25baeca4f807b43cff3bda2efd03fdff96728 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 1 Jun 2024 12:22:17 +0200 Subject: publishing my work. Signed-off-by: Amlal El Mahrouss --- 64asm.rsrc | 6 +++--- 64x0-cc.rsrc | 6 +++--- Common/AsmKit/AsmKit.hpp | 2 +- Common/AsmKit/CPU/32x0.hpp | 2 +- Common/AsmKit/CPU/64x0.hpp | 2 +- Common/AsmKit/CPU/amd64.hpp | 2 +- Common/CompilerKit.hpp | 2 +- Common/Defines.hpp | 2 +- Common/ParserKit.hpp | 2 +- Common/Public/SDK/CRT/__mpcc_alloca.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_defines.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_exception.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_hint.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_malloc.hxx | 2 +- Common/StdKit/AE.hpp | 2 +- Common/StdKit/ErrorID.hpp | 2 +- Common/StdKit/ErrorOr.hpp | 2 +- Common/StdKit/PEF.hpp | 2 +- Common/StdKit/Ref.hpp | 2 +- Common/StdKit/String.hpp | 2 +- Common/StdKit/XCOFF.hxx | 2 +- ReadMe.md | 2 +- Sources/32asm.cc | 2 +- Sources/64asm.cc | 4 ++-- Sources/64x0-cc.cc | 6 +++--- Sources/AssemblyFactory.cc | 4 ++-- Sources/Detail/asmutils.hxx | 2 +- Sources/Detail/compilerutils.hxx | 2 +- Sources/String.cc | 4 ++-- Sources/bpp.cc | 6 +++--- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 10 +++++----- Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 6 +++--- Sources/link.cc | 8 ++++---- Sources/power-cc.cc | 4 ++-- Sources/ppcasm.cc | 6 +++--- bpp.rsrc | 6 +++--- i64asm.rsrc | 6 +++--- link.rsrc | 4 ++-- posix.make | 4 ++-- power-cc.rsrc | 6 +++--- ppcasm.rsrc | 6 +++--- win64.make | 4 ++-- 44 files changed, 78 insertions(+), 78 deletions(-) (limited to 'Sources') diff --git a/64asm.rsrc b/64asm.rsrc index 9f473f1..c01fa7a 100644 --- a/64asm.rsrc +++ b/64asm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs assembler for 64x000." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss assembler for 64x000." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "64asm.exe" VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion diff --git a/64x0-cc.rsrc b/64x0-cc.rsrc index 300c684..78d23b4 100644 --- a/64x0-cc.rsrc +++ b/64x0-cc.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs C Compiler for 64x000." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss C Compiler for 64x000." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Compiler" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "64x0-cc.exe" VALUE "ProductName", "Compiler" VALUE "ProductVersion", kDistVersion diff --git a/Common/AsmKit/AsmKit.hpp b/Common/AsmKit/AsmKit.hpp index 020ca5c..f4aecaf 100644 --- a/Common/AsmKit/AsmKit.hpp +++ b/Common/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/32x0.hpp b/Common/AsmKit/CPU/32x0.hpp index fe03336..94ec43a 100644 --- a/Common/AsmKit/CPU/32x0.hpp +++ b/Common/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/64x0.hpp b/Common/AsmKit/CPU/64x0.hpp index b28866f..48ebf95 100644 --- a/Common/AsmKit/CPU/64x0.hpp +++ b/Common/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/amd64.hpp b/Common/AsmKit/CPU/amd64.hpp index 507602c..92e649a 100644 --- a/Common/AsmKit/CPU/amd64.hpp +++ b/Common/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/CompilerKit.hpp b/Common/CompilerKit.hpp index b9de089..9abe154 100644 --- a/Common/CompilerKit.hpp +++ b/Common/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Defines.hpp b/Common/Defines.hpp index d76620c..3bf1ea8 100644 --- a/Common/Defines.hpp +++ b/Common/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/ParserKit.hpp b/Common/ParserKit.hpp index 6e15c75..98d078d 100644 --- a/Common/ParserKit.hpp +++ b/Common/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_alloca.hxx b/Common/Public/SDK/CRT/__mpcc_alloca.hxx index a1c638e..b653682 100644 --- a/Common/Public/SDK/CRT/__mpcc_alloca.hxx +++ b/Common/Public/SDK/CRT/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_defines.hxx b/Common/Public/SDK/CRT/__mpcc_defines.hxx index 5560410..1230662 100644 --- a/Common/Public/SDK/CRT/__mpcc_defines.hxx +++ b/Common/Public/SDK/CRT/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_exception.hxx b/Common/Public/SDK/CRT/__mpcc_exception.hxx index 9366102..663a5d2 100644 --- a/Common/Public/SDK/CRT/__mpcc_exception.hxx +++ b/Common/Public/SDK/CRT/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_hint.hxx b/Common/Public/SDK/CRT/__mpcc_hint.hxx index ee14711..3168e8e 100644 --- a/Common/Public/SDK/CRT/__mpcc_hint.hxx +++ b/Common/Public/SDK/CRT/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_malloc.hxx b/Common/Public/SDK/CRT/__mpcc_malloc.hxx index 2731868..3fd7fcc 100644 --- a/Common/Public/SDK/CRT/__mpcc_malloc.hxx +++ b/Common/Public/SDK/CRT/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/StdKit/AE.hpp b/Common/StdKit/AE.hpp index 9c4ac1a..4755b06 100644 --- a/Common/StdKit/AE.hpp +++ b/Common/StdKit/AE.hpp @@ -2,7 +2,7 @@ * ======================================================== * * MPCC - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/ErrorID.hpp b/Common/StdKit/ErrorID.hpp index 9f12ab2..92d2172 100644 --- a/Common/StdKit/ErrorID.hpp +++ b/Common/StdKit/ErrorID.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/ErrorOr.hpp b/Common/StdKit/ErrorOr.hpp index cf35b26..7ad6e8d 100644 --- a/Common/StdKit/ErrorOr.hpp +++ b/Common/StdKit/ErrorOr.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/PEF.hpp b/Common/StdKit/PEF.hpp index b084f32..e82e5ef 100644 --- a/Common/StdKit/PEF.hpp +++ b/Common/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Common/StdKit/Ref.hpp b/Common/StdKit/Ref.hpp index d13f97c..7ba4d95 100644 --- a/Common/StdKit/Ref.hpp +++ b/Common/StdKit/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/String.hpp b/Common/StdKit/String.hpp index a05a31c..3da302c 100644 --- a/Common/StdKit/String.hpp +++ b/Common/StdKit/String.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/XCOFF.hxx b/Common/StdKit/XCOFF.hxx index a26b591..6e9fd6d 100644 --- a/Common/StdKit/XCOFF.hxx +++ b/Common/StdKit/XCOFF.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss File: XCOFF.hpp Purpose: XCOFF for NewOS. diff --git a/ReadMe.md b/ReadMe.md index 82b3217..47e0e89 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -14,4 +14,4 @@ make all Author: Amlal El Mahrouss -##### Copyright SoftwareLabs, all rights reserved. +##### Copyright Amlal El Mahrouss, all rights reserved. diff --git a/Sources/32asm.cc b/Sources/32asm.cc index f877553..3f98cb7 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 6e8cc6d..587d5c3 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ @@ -110,7 +110,7 @@ MPCC_MODULE(NewOSAssembler64000) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 SoftwareLabs.\n"; + "2024 Amlal El Mahrouss.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 3a0e569..e3a0771 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ @@ -27,7 +27,7 @@ /* C driver */ /* This is part of MPCC C SDK. */ -/* (c) SoftwareLabs */ +/* (c) Amlal El Mahrouss */ /// @author Amlal El Mahrouss (amlel) /// @file 64x0-cc.cc @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 0000ab7..3b2fb7c 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ @@ -14,7 +14,7 @@ * @version 0.1 * @date 2024-01-27 * - * @copyright Copyright (c) 2024, SoftwareLabs + * @copyright Copyright (c) 2024, Amlal El Mahrouss * */ diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index f6fdb41..d0eb2c7 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index 9ddd3a2..a9332f4 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Sources/String.cc b/Sources/String.cc index 38bd444..7926441 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 SoftwareLabs + * @copyright Copyright (c) 2024 Amlal El Mahrouss * */ diff --git a/Sources/bpp.cc b/Sources/bpp.cc index accbef5..27dba78 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -2,7 +2,7 @@ * ======================================================== * * bpp - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ @@ -812,12 +812,12 @@ MPCC_MODULE(NewOSPreprocessor) { if (argv[index][0] == '-') { if (strcmp(argv[index], "-v") == 0) { - printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); + printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); return 0; } if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); + printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); printf("%s\n", "-working-dir : set directory to working path."); printf("%s\n", "-include-dir : add directory to include path."); printf("%s\n", "-def : def macro."); diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 349d543..6baa964 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index db33688..d03987c 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -2,7 +2,7 @@ * ======================================================== * * cplusplus - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") + kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright Amlal El Mahrouss.") #include #include @@ -29,9 +29,9 @@ #define kOk 0 -/* SoftwareLabs C++ driver */ +/* Amlal El Mahrouss C++ driver */ /* This is part of MPCC C++ compiler. */ -/* (c) SoftwareLabs */ +/* (c) Amlal El Mahrouss */ /// @author Amlal El Mahrouss (amlel) /// @file cc.cc @@ -170,7 +170,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for SoftwareLabs C++ */ +/* @brief C++ compiler backend for Amlal El Mahrouss C++ */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index a451a0a..f559c21 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 5510252..31f19b8 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ @@ -175,13 +175,13 @@ MPCC_MODULE(NewOSAssemblerAMD64) if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 SoftwareLabs.\n"; + "(c) 2024 Amlal El Mahrouss.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "SoftwareLabs.\n"; + "Amlal El Mahrouss.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/Sources/link.cc b/Sources/link.cc index 47406c4..e245f4c 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ /// @file link.cc /// @author Amlal El Mahrouss (amlel) -/// @brief SoftwareLabs Linker. +/// @brief Amlal El Mahrouss Linker. /// Last Rev: Sat Feb 24 CET 2024 @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "SoftwareLabs Linker %s, (c) SoftwareLabs 2024\n" +#define kLinkerVersion "Amlal El Mahrouss Linker %s, (c) Amlal El Mahrouss 2024\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -184,7 +184,7 @@ MPCC_MODULE(NewOSLinker) { pef_container.Count = 0UL; pef_container.Kind = CompilerKit::kPefKindExec; pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // SoftwareLabs Linker + pef_container.Linker = kLinkerId; // Amlal El Mahrouss Linker pef_container.Abi = kAbi; // Multi-Processor UX ABI pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; pef_container.Magic[1] = kPefMagic[1]; diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index b26dbf2..80573b9 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright SoftwareLabs, all rights reserved. + * Copyright Amlal El Mahrouss, all rights reserved. * * ======================================================== */ @@ -1531,7 +1531,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 0236491..2192ccd 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Amlal El Mahrouss ------------------------------------------- */ @@ -115,11 +115,11 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " - "2024 SoftwareLabs.\n"; + "2024 Amlal El Mahrouss.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: Copyright (c) 2024 " - "SoftwareLabs.\n"; + "Amlal El Mahrouss.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/bpp.rsrc b/bpp.rsrc index 3a8d4d9..5cc550c 100644 --- a/bpp.rsrc +++ b/bpp.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs Preprocessor." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss Preprocessor." VALUE "FileVersion", kDistVersion VALUE "InternalName", "NewPreprocessor" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "bpp.exe" VALUE "ProductName", "NewPreprocessor" VALUE "ProductVersion", kDistVersion diff --git a/i64asm.rsrc b/i64asm.rsrc index 4472b3f..1c12923 100644 --- a/i64asm.rsrc +++ b/i64asm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs assembler for AMD64." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss assembler for AMD64." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "i64asm.exe" VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion diff --git a/link.rsrc b/link.rsrc index 550d87a..88ca4d6 100644 --- a/link.rsrc +++ b/link.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" + VALUE "CompanyName", "Amlal El Mahrouss" VALUE "FileDescription", "NewOS linker." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Linker" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "link.exe" VALUE "ProductName", "Linker" VALUE "ProductVersion", kDistVersion diff --git a/posix.make b/posix.make index 0a6ef8e..b543b34 100644 --- a/posix.make +++ b/posix.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright SoftwareLabs, all rights reserved. + # Copyright Amlal El Mahrouss, all rights reserved. # # ======================================================== # @@ -74,7 +74,7 @@ linker: help: @echo "Compiler - MPCC Compiler Suite." @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - SoftwareLabs Linkers." + @echo "linker - Amlal El Mahrouss Linkers." @echo "clean - Clean objects and executables." .PHONY: clean diff --git a/power-cc.rsrc b/power-cc.rsrc index 4a10e6b..7831667 100644 --- a/power-cc.rsrc +++ b/power-cc.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs C Compiler for POWER." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss C Compiler for POWER." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Compiler" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "power-cc.exe" VALUE "ProductName", "Compiler" VALUE "ProductVersion", kDistVersion diff --git a/ppcasm.rsrc b/ppcasm.rsrc index cf3fbb9..174bc5c 100644 --- a/ppcasm.rsrc +++ b/ppcasm.rsrc @@ -10,11 +10,11 @@ BEGIN BEGIN BLOCK "080904E4" BEGIN - VALUE "CompanyName", "SoftwareLabs" - VALUE "FileDescription", "SoftwareLabs assembler for POWER." + VALUE "CompanyName", "Amlal El Mahrouss" + VALUE "FileDescription", "Amlal El Mahrouss assembler for POWER." VALUE "FileVersion", kDistVersion VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "SoftwareLabs" + VALUE "LegalCopyright", "Amlal El Mahrouss" VALUE "OriginalFilename", "ppcasm.exe" VALUE "ProductName", "Assembler" VALUE "ProductVersion", kDistVersion diff --git a/win64.make b/win64.make index 1e70bfd..ca10243 100644 --- a/win64.make +++ b/win64.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright SoftwareLabs, all rights reserved. + # Copyright Amlal El Mahrouss, all rights reserved. # # ======================================================== # @@ -80,7 +80,7 @@ linker: help: @echo "Compiler - MPCC Compiler Suite." @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - SoftwareLabs Linkers." + @echo "linker - Amlal El Mahrouss Linkers." @echo "clean - Clean objects and executables." .PHONY: clean -- cgit v1.2.3 From 68b1c532bad643ca983b37e29d6621bd8b957d69 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Sat, 1 Jun 2024 18:22:01 +0200 Subject: MHR-21: Amend commit, did some cleaning. Signed-off-by: Amlal EL Mahrouss --- 64asm.rsrc | 27 --------------------------- 64x0-cc.rsrc | 27 --------------------------- Common/AsmKit/AsmKit.hpp | 2 +- Common/AsmKit/CPU/32x0.hpp | 2 +- Common/AsmKit/CPU/64x0.hpp | 2 +- Common/AsmKit/CPU/amd64.hpp | 2 +- Common/CompilerKit.hpp | 2 +- Common/Defines.hpp | 2 +- Common/ParserKit.hpp | 2 +- Common/Public/SDK/CRT/__mpcc_alloca.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_defines.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_exception.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_hint.hxx | 2 +- Common/Public/SDK/CRT/__mpcc_malloc.hxx | 2 +- Common/StdKit/AE.hpp | 2 +- Common/StdKit/ErrorID.hpp | 2 +- Common/StdKit/ErrorOr.hpp | 2 +- Common/StdKit/PEF.hpp | 2 +- Common/StdKit/Ref.hpp | 4 ++-- Common/StdKit/String.hpp | 2 +- Common/StdKit/XCOFF.hxx | 2 +- ReadMe.md | 5 ++--- Sources/32asm.cc | 4 ++-- Sources/64asm.cc | 6 +++--- Sources/64x0-cc.cc | 8 ++++---- Sources/AssemblyFactory.cc | 6 +++--- Sources/Detail/asmutils.hxx | 2 +- Sources/Detail/compilerutils.hxx | 2 +- Sources/String.cc | 4 ++-- Sources/bpp.cc | 8 ++++---- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 12 ++++++------ Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 8 ++++---- Sources/link.cc | 10 +++++----- Sources/power-cc.cc | 6 +++--- Sources/ppcasm.cc | 8 ++++---- bpp.rsrc | 27 --------------------------- i64asm.rsrc | 27 --------------------------- link.rsrc | 27 --------------------------- posix.make | 6 +++--- power-cc.rsrc | 27 --------------------------- ppcasm.rsrc | 27 --------------------------- win64.make | 14 +++----------- 44 files changed, 72 insertions(+), 270 deletions(-) delete mode 100644 64asm.rsrc delete mode 100644 64x0-cc.rsrc delete mode 100644 bpp.rsrc delete mode 100644 i64asm.rsrc delete mode 100644 link.rsrc delete mode 100644 power-cc.rsrc delete mode 100644 ppcasm.rsrc (limited to 'Sources') diff --git a/64asm.rsrc b/64asm.rsrc deleted file mode 100644 index c01fa7a..0000000 --- a/64asm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss assembler for 64x000." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "64asm.exe" - VALUE "ProductName", "Assembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/64x0-cc.rsrc b/64x0-cc.rsrc deleted file mode 100644 index 78d23b4..0000000 --- a/64x0-cc.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss C Compiler for 64x000." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Compiler" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "64x0-cc.exe" - VALUE "ProductName", "Compiler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/Common/AsmKit/AsmKit.hpp b/Common/AsmKit/AsmKit.hpp index f4aecaf..020ca5c 100644 --- a/Common/AsmKit/AsmKit.hpp +++ b/Common/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/32x0.hpp b/Common/AsmKit/CPU/32x0.hpp index 94ec43a..fe03336 100644 --- a/Common/AsmKit/CPU/32x0.hpp +++ b/Common/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/64x0.hpp b/Common/AsmKit/CPU/64x0.hpp index 48ebf95..b28866f 100644 --- a/Common/AsmKit/CPU/64x0.hpp +++ b/Common/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/AsmKit/CPU/amd64.hpp b/Common/AsmKit/CPU/amd64.hpp index 92e649a..507602c 100644 --- a/Common/AsmKit/CPU/amd64.hpp +++ b/Common/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/CompilerKit.hpp b/Common/CompilerKit.hpp index 9abe154..b9de089 100644 --- a/Common/CompilerKit.hpp +++ b/Common/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Defines.hpp b/Common/Defines.hpp index 3bf1ea8..d76620c 100644 --- a/Common/Defines.hpp +++ b/Common/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/ParserKit.hpp b/Common/ParserKit.hpp index 98d078d..6e15c75 100644 --- a/Common/ParserKit.hpp +++ b/Common/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_alloca.hxx b/Common/Public/SDK/CRT/__mpcc_alloca.hxx index b653682..a1c638e 100644 --- a/Common/Public/SDK/CRT/__mpcc_alloca.hxx +++ b/Common/Public/SDK/CRT/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_defines.hxx b/Common/Public/SDK/CRT/__mpcc_defines.hxx index 1230662..5560410 100644 --- a/Common/Public/SDK/CRT/__mpcc_defines.hxx +++ b/Common/Public/SDK/CRT/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_exception.hxx b/Common/Public/SDK/CRT/__mpcc_exception.hxx index 663a5d2..9366102 100644 --- a/Common/Public/SDK/CRT/__mpcc_exception.hxx +++ b/Common/Public/SDK/CRT/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_hint.hxx b/Common/Public/SDK/CRT/__mpcc_hint.hxx index 3168e8e..ee14711 100644 --- a/Common/Public/SDK/CRT/__mpcc_hint.hxx +++ b/Common/Public/SDK/CRT/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/Public/SDK/CRT/__mpcc_malloc.hxx b/Common/Public/SDK/CRT/__mpcc_malloc.hxx index 3fd7fcc..2731868 100644 --- a/Common/Public/SDK/CRT/__mpcc_malloc.hxx +++ b/Common/Public/SDK/CRT/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/StdKit/AE.hpp b/Common/StdKit/AE.hpp index 4755b06..9c4ac1a 100644 --- a/Common/StdKit/AE.hpp +++ b/Common/StdKit/AE.hpp @@ -2,7 +2,7 @@ * ======================================================== * * MPCC - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/ErrorID.hpp b/Common/StdKit/ErrorID.hpp index 92d2172..9f12ab2 100644 --- a/Common/StdKit/ErrorID.hpp +++ b/Common/StdKit/ErrorID.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/ErrorOr.hpp b/Common/StdKit/ErrorOr.hpp index 7ad6e8d..cf35b26 100644 --- a/Common/StdKit/ErrorOr.hpp +++ b/Common/StdKit/ErrorOr.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/PEF.hpp b/Common/StdKit/PEF.hpp index e82e5ef..b084f32 100644 --- a/Common/StdKit/PEF.hpp +++ b/Common/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Common/StdKit/Ref.hpp b/Common/StdKit/Ref.hpp index 7ba4d95..f4a11c0 100644 --- a/Common/StdKit/Ref.hpp +++ b/Common/StdKit/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -12,7 +12,7 @@ namespace CompilerKit { - // @author Amlal EL Mahrouss + // @author SoftwareLabs // @brief Reference class, refers to a pointer of data in static memory. template class Ref final diff --git a/Common/StdKit/String.hpp b/Common/StdKit/String.hpp index 3da302c..a05a31c 100644 --- a/Common/StdKit/String.hpp +++ b/Common/StdKit/String.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ diff --git a/Common/StdKit/XCOFF.hxx b/Common/StdKit/XCOFF.hxx index 6e9fd6d..a26b591 100644 --- a/Common/StdKit/XCOFF.hxx +++ b/Common/StdKit/XCOFF.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs File: XCOFF.hpp Purpose: XCOFF for NewOS. diff --git a/ReadMe.md b/ReadMe.md index 47e0e89..ba91d98 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -9,9 +9,8 @@ git clone git@bitbucket.org:mahrouss/codetools.git and ``` -make all +make -f .make all ``` -Author: Amlal El Mahrouss -##### Copyright Amlal El Mahrouss, all rights reserved. +##### Copyright SoftwareLabs, all rights reserved. diff --git a/Sources/32asm.cc b/Sources/32asm.cc index 3f98cb7..82d23e6 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 32asm.cxx -// @author Amlal El Mahrouss +// @author SoftwareLabs // @brief 32x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 587d5c3..6287b3e 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 64asm.cxx -// @author Amlal El Mahrouss +// @author SoftwareLabs // @brief 64x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string @@ -110,7 +110,7 @@ MPCC_MODULE(NewOSAssembler64000) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 Amlal El Mahrouss.\n"; + "2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index e3a0771..36f56a8 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -27,9 +27,9 @@ /* C driver */ /* This is part of MPCC C SDK. */ -/* (c) Amlal El Mahrouss */ +/* (c) SoftwareLabs */ -/// @author Amlal El Mahrouss (amlel) +/// @author SoftwareLabs (amlel) /// @file 64x0-cc.cc /// @brief 64x0 C Compiler. @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 3b2fb7c..1952f54 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ @@ -9,12 +9,12 @@ /** * @file AssemblyFactory.cxx - * @author Amlal El Mahrouss (amlal@mahrouss.com) + * @author SoftwareLabs (amlal@mahrouss.com) * @brief Assembler Kit * @version 0.1 * @date 2024-01-27 * - * @copyright Copyright (c) 2024, Amlal El Mahrouss + * @copyright Copyright (c) 2024, SoftwareLabs * */ diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index d0eb2c7..f6fdb41 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index a9332f4..9ddd3a2 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/String.cc b/Sources/String.cc index 7926441..38bd444 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 Amlal El Mahrouss + * @copyright Copyright (c) 2024 SoftwareLabs * */ diff --git a/Sources/bpp.cc b/Sources/bpp.cc index 27dba78..aa0b72a 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -2,7 +2,7 @@ * ======================================================== * * bpp - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -19,7 +19,7 @@ #define kMacroPrefix '%' -// @author Amlal El Mahrouss (amlel) +// @author SoftwareLabs (amlel) // @file bpp.cc // @brief C preprocessor. @@ -812,12 +812,12 @@ MPCC_MODULE(NewOSPreprocessor) { if (argv[index][0] == '-') { if (strcmp(argv[index], "-v") == 0) { - printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); + printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); return 0; } if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); + printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); printf("%s\n", "-working-dir : set directory to working path."); printf("%s\n", "-include-dir : add directory to include path."); printf("%s\n", "-def : def macro."); diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 6baa964..349d543 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index d03987c..72b654a 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -2,7 +2,7 @@ * ======================================================== * * cplusplus - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright Amlal El Mahrouss.") + kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") #include #include @@ -29,11 +29,11 @@ #define kOk 0 -/* Amlal El Mahrouss C++ driver */ +/* SoftwareLabs C++ driver */ /* This is part of MPCC C++ compiler. */ -/* (c) Amlal El Mahrouss */ +/* (c) SoftwareLabs */ -/// @author Amlal El Mahrouss (amlel) +/// @author SoftwareLabs (amlel) /// @file cc.cc /// @brief Optimized C++ Compiler. /// @todo Throw error for scoped inside scoped variables when they get referenced outside. @@ -170,7 +170,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for Amlal El Mahrouss C++ */ +/* @brief C++ compiler backend for SoftwareLabs C++ */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index f559c21..a451a0a 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 31f19b8..391c63f 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ ///////////////////////////////////////////////////////////////////////////////////////// /// @file i64asm.cxx -/// @author Amlal El Mahrouss +/// @author SoftwareLabs /// @brief AMD64 Assembler. /// REMINDER: when dealing with an undefined symbol use (string @@ -175,13 +175,13 @@ MPCC_MODULE(NewOSAssemblerAMD64) if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 Amlal El Mahrouss.\n"; + "(c) 2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "Amlal El Mahrouss.\n"; + "SoftwareLabs.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/Sources/link.cc b/Sources/link.cc index e245f4c..e0a49cf 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ /// @file link.cc -/// @author Amlal El Mahrouss (amlel) -/// @brief Amlal El Mahrouss Linker. +/// @author SoftwareLabs (amlel) +/// @brief SoftwareLabs Linker. /// Last Rev: Sat Feb 24 CET 2024 @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Amlal El Mahrouss Linker %s, (c) Amlal El Mahrouss 2024\n" +#define kLinkerVersion "SoftwareLabs Linker %s, (c) SoftwareLabs 2024\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -184,7 +184,7 @@ MPCC_MODULE(NewOSLinker) { pef_container.Count = 0UL; pef_container.Kind = CompilerKit::kPefKindExec; pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Amlal El Mahrouss Linker + pef_container.Linker = kLinkerId; // SoftwareLabs Linker pef_container.Abi = kAbi; // Multi-Processor UX ABI pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; pef_container.Magic[1] = kPefMagic[1]; diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index 80573b9..ad99611 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Amlal El Mahrouss, all rights reserved. + * Copyright SoftwareLabs, all rights reserved. * * ======================================================== */ @@ -22,7 +22,7 @@ #define kOk 0 -/// @author Amlal El Mahrouss (amlel) +/// @author SoftwareLabs (amlel) /// @file cc.cc /// @brief POWER C Compiler. @@ -1531,7 +1531,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 2192ccd..89de014 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright Amlal El Mahrouss + Copyright SoftwareLabs ------------------------------------------- */ ///////////////////////////////////////////////////////////////////////////////////////// /// @file ppcasm.cxx -/// @author Amlal El Mahrouss +/// @author SoftwareLabs /// @brief POWER Assembler. /// REMINDER: when dealing with an undefined symbol use (string @@ -115,11 +115,11 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " - "2024 Amlal El Mahrouss.\n"; + "2024 SoftwareLabs.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: Copyright (c) 2024 " - "Amlal El Mahrouss.\n"; + "SoftwareLabs.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/bpp.rsrc b/bpp.rsrc deleted file mode 100644 index 5cc550c..0000000 --- a/bpp.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss Preprocessor." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewPreprocessor" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "bpp.exe" - VALUE "ProductName", "NewPreprocessor" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/i64asm.rsrc b/i64asm.rsrc deleted file mode 100644 index 1c12923..0000000 --- a/i64asm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss assembler for AMD64." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "i64asm.exe" - VALUE "ProductName", "Assembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/link.rsrc b/link.rsrc deleted file mode 100644 index 88ca4d6..0000000 --- a/link.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "NewOS linker." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Linker" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "link.exe" - VALUE "ProductName", "Linker" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/posix.make b/posix.make index b543b34..119457d 100644 --- a/posix.make +++ b/posix.make @@ -2,13 +2,13 @@ # ======================================================== # # MPCC - # Copyright Amlal El Mahrouss, all rights reserved. + # Copyright SoftwareLabs, all rights reserved. # # ======================================================== # COMMON_INC=-I./Common -I./ -I./Sources/Detail -LINK_CC=g++ -std=c++20 +LINK_CC=clang++ -std=c++20 LINK_SRC=Sources/link.cc LINK_OUTPUT=Output/link.exec LINK_ALT_OUTPUT=Output/64link.exec @@ -74,7 +74,7 @@ linker: help: @echo "Compiler - MPCC Compiler Suite." @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - Amlal El Mahrouss Linkers." + @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." .PHONY: clean diff --git a/power-cc.rsrc b/power-cc.rsrc deleted file mode 100644 index 7831667..0000000 --- a/power-cc.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss C Compiler for POWER." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Compiler" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "power-cc.exe" - VALUE "ProductName", "Compiler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/ppcasm.rsrc b/ppcasm.rsrc deleted file mode 100644 index 174bc5c..0000000 --- a/ppcasm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Common/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Amlal El Mahrouss" - VALUE "FileDescription", "Amlal El Mahrouss assembler for POWER." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "Assembler" - VALUE "LegalCopyright", "Amlal El Mahrouss" - VALUE "OriginalFilename", "ppcasm.exe" - VALUE "ProductName", "Assembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/win64.make b/win64.make index ca10243..0315371 100644 --- a/win64.make +++ b/win64.make @@ -2,14 +2,13 @@ # ======================================================== # # MPCC - # Copyright Amlal El Mahrouss, all rights reserved. + # Copyright SoftwareLabs, all rights reserved. # # ======================================================== # COMMON_INC=-I./Common -I./ -I./Sources/Detail -LINK_CC=x86_64-w64-mingw32-g++.exe -std=c++20 -Xlinker -s -WINRES=x86_64-w64-mingw32-windres +LINK_CC=clang++ -std=c++20 -Xlinker -s LINK_SRC=Sources/link.cc LINK_OUTPUT=Output/link.exe LINK_ALT_OUTPUT=Output/64link.exe @@ -51,16 +50,10 @@ all: pre-processor compiler linker .PHONY: pre-processor pre-processor: - $(WINRES) bpp.rsrc -O coff -o bpp.obj $(LINK_CC) $(COMMON_INC) $(PP_SRC) bpp.obj -o $(PP_OUTPUT) .PHONY: compiler compiler: - $(WINRES) i64asm.rsrc -O coff -o i64asm.obj - $(WINRES) 64asm.rsrc -O coff -o 64asm.obj - $(WINRES) ppcasm.rsrc -O coff -o ppcasm.obj - $(WINRES) 64x0-cc.rsrc -O coff -o 64x0-cc.obj - $(WINRES) power-cc.rsrc -O coff -o power-cc.obj $(LINK_CC) $(COMMON_INC) 64x0-cc.obj $(64X0_CC_SRC) -o $(64X0_CC_OUTPUT) $(LINK_CC) $(COMMON_INC) $(AMD64_CXX_SRC) -o $(AMD64_CXX_OUTPUT) $(LINK_CC) $(COMMON_INC) power-cc.obj $(PPC_CC_SRC) -o $(PPC_CC_OUTPUT) @@ -70,7 +63,6 @@ compiler: .PHONY: linker linker: - $(WINRES) link.rsrc -O coff -o link.obj $(LINK_CC) $(COMMON_INC) link.obj $(LINK_SRC) -o $(LINK_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_2_OUTPUT) @@ -80,7 +72,7 @@ linker: help: @echo "Compiler - MPCC Compiler Suite." @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - Amlal El Mahrouss Linkers." + @echo "linker - SoftwareLabs Linkers." @echo "clean - Clean objects and executables." .PHONY: clean -- cgit v1.2.3 From c6d1383155700a9ee10200e2023e6ed06243a698 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Mon, 3 Jun 2024 08:11:20 +0200 Subject: meta: cplusplus: refactors. Signed-off-by: Amlal El Mahrouss --- Sources/cplusplus.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 72b654a..97b6a82 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "LightSpeed C++ Compiler, Copyright SoftwareLabs.") + kPrintF(kWhite "%s\n", "SoftwareLabs C++ Compiler, Copyright SoftwareLabs.") #include #include @@ -667,10 +667,10 @@ public: (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; (*kState.fOutputAssembly) - << "; Language: MPCC assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; - (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" - << "\n\n"; + << "; Language: AMD64 assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; + (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" + << "\n"; ParserKit::SyntaxLeafList syntax; @@ -704,7 +704,7 @@ static void cxx_print_help() { kSplashCxx(); kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/softwarelabs/developer/newos/cplusplus\n"); + kPrintF("%s", "www.softwarelabs.com/developer/cplusplus\n"); } ///////////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 0aebad569eef2989e32d9825ce52708371685ff9 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Sun, 9 Jun 2024 19:57:20 +0200 Subject: MHR-21: Finish C++ compiler. Signed-off-by: Amlal EL Mahrouss --- .vscode/c_cpp_properties.json | 4 +- Comm/AsmKit/AsmKit.hpp | 217 ++++ Comm/AsmKit/CPU/32x0.hpp | 95 ++ Comm/AsmKit/CPU/64x0.hpp | 108 ++ Comm/AsmKit/CPU/amd64.hpp | 56 + Comm/AsmKit/CPU/ppc.hpp | 1919 ++++++++++++++++++++++++++++ Comm/CompilerKit.hpp | 33 + Comm/Defines.hpp | 147 +++ Comm/ParserKit.hpp | 171 +++ Comm/Public/SDK/CRT/__mpcc_alloca.hxx | 15 + Comm/Public/SDK/CRT/__mpcc_defines.hxx | 89 ++ Comm/Public/SDK/CRT/__mpcc_exception.hxx | 27 + Comm/Public/SDK/CRT/__mpcc_hint.hxx | 20 + Comm/Public/SDK/CRT/__mpcc_malloc.hxx | 30 + Comm/Public/SDK/CRT/__mpcc_power.inc | 35 + Comm/StdKit/AE.hpp | 143 +++ Comm/StdKit/ELF.hpp | 389 ++++++ Comm/StdKit/ErrorID.hpp | 22 + Comm/StdKit/ErrorOr.hpp | 61 + Comm/StdKit/PEF.hpp | 132 ++ Comm/StdKit/Ref.hpp | 91 ++ Comm/StdKit/String.hpp | 90 ++ Comm/StdKit/XCOFF.hxx | 41 + Comm/UUID.hpp | 983 ++++++++++++++ Comm/Version.hxx | 3 + Common/AsmKit/AsmKit.hpp | 217 ---- Common/AsmKit/CPU/32x0.hpp | 95 -- Common/AsmKit/CPU/64x0.hpp | 108 -- Common/AsmKit/CPU/amd64.hpp | 56 - Common/AsmKit/CPU/ppc.hpp | 1919 ---------------------------- Common/CompilerKit.hpp | 33 - Common/Defines.hpp | 147 --- Common/ParserKit.hpp | 171 --- Common/Public/SDK/CRT/__mpcc_alloca.hxx | 15 - Common/Public/SDK/CRT/__mpcc_defines.hxx | 89 -- Common/Public/SDK/CRT/__mpcc_exception.hxx | 27 - Common/Public/SDK/CRT/__mpcc_hint.hxx | 20 - Common/Public/SDK/CRT/__mpcc_malloc.hxx | 30 - Common/Public/SDK/CRT/__mpcc_power.inc | 35 - Common/StdKit/AE.hpp | 143 --- Common/StdKit/ELF.hpp | 389 ------ Common/StdKit/ErrorID.hpp | 22 - Common/StdKit/ErrorOr.hpp | 61 - Common/StdKit/PEF.hpp | 132 -- Common/StdKit/Ref.hpp | 91 -- Common/StdKit/String.hpp | 90 -- Common/StdKit/XCOFF.hxx | 41 - Common/UUID.hpp | 983 -------------- Common/Version.hxx | 3 - Doc/Inside 64x0.pdf | Bin 0 -> 64675 bytes Doc/asm-specs.txt | 11 + Doc/havp.txt | 13 + Doc/notice.txt | 4 + Doc/vnrp.txt | 17 + Sources/32asm.cc | 8 +- Sources/64asm.cc | 8 +- Sources/64x0-cc.cc | 6 +- Sources/AssemblyFactory.cc | 4 +- Sources/Detail/asmutils.hxx | 4 +- Sources/Detail/compilerutils.hxx | 4 +- Sources/String.cc | 2 +- Sources/bpp.cc | 4 +- Sources/coff2ae.cc | 6 +- Sources/cplusplus.cc | 4 +- Sources/elf2ae.cc | 6 +- Sources/i64asm.cc | 8 +- Sources/link.cc | 12 +- Sources/power-cc.cc | 6 +- Sources/ppcasm.cc | 12 +- docs/Inside 64x0.pdf | Bin 64675 -> 0 bytes docs/asm-specs.txt | 11 - docs/havp.txt | 13 - docs/notice.txt | 4 - docs/vnrp.txt | 17 - posix.make | 2 +- win64.make | 2 +- 76 files changed, 5013 insertions(+), 5013 deletions(-) create mode 100644 Comm/AsmKit/AsmKit.hpp create mode 100644 Comm/AsmKit/CPU/32x0.hpp create mode 100644 Comm/AsmKit/CPU/64x0.hpp create mode 100644 Comm/AsmKit/CPU/amd64.hpp create mode 100644 Comm/AsmKit/CPU/ppc.hpp create mode 100644 Comm/CompilerKit.hpp create mode 100644 Comm/Defines.hpp create mode 100644 Comm/ParserKit.hpp create mode 100644 Comm/Public/SDK/CRT/__mpcc_alloca.hxx create mode 100644 Comm/Public/SDK/CRT/__mpcc_defines.hxx create mode 100644 Comm/Public/SDK/CRT/__mpcc_exception.hxx create mode 100644 Comm/Public/SDK/CRT/__mpcc_hint.hxx create mode 100644 Comm/Public/SDK/CRT/__mpcc_malloc.hxx create mode 100644 Comm/Public/SDK/CRT/__mpcc_power.inc create mode 100644 Comm/StdKit/AE.hpp create mode 100644 Comm/StdKit/ELF.hpp create mode 100644 Comm/StdKit/ErrorID.hpp create mode 100644 Comm/StdKit/ErrorOr.hpp create mode 100644 Comm/StdKit/PEF.hpp create mode 100644 Comm/StdKit/Ref.hpp create mode 100644 Comm/StdKit/String.hpp create mode 100644 Comm/StdKit/XCOFF.hxx create mode 100644 Comm/UUID.hpp create mode 100644 Comm/Version.hxx delete mode 100644 Common/AsmKit/AsmKit.hpp delete mode 100644 Common/AsmKit/CPU/32x0.hpp delete mode 100644 Common/AsmKit/CPU/64x0.hpp delete mode 100644 Common/AsmKit/CPU/amd64.hpp delete mode 100644 Common/AsmKit/CPU/ppc.hpp delete mode 100644 Common/CompilerKit.hpp delete mode 100644 Common/Defines.hpp delete mode 100644 Common/ParserKit.hpp delete mode 100644 Common/Public/SDK/CRT/__mpcc_alloca.hxx delete mode 100644 Common/Public/SDK/CRT/__mpcc_defines.hxx delete mode 100644 Common/Public/SDK/CRT/__mpcc_exception.hxx delete mode 100644 Common/Public/SDK/CRT/__mpcc_hint.hxx delete mode 100644 Common/Public/SDK/CRT/__mpcc_malloc.hxx delete mode 100644 Common/Public/SDK/CRT/__mpcc_power.inc delete mode 100644 Common/StdKit/AE.hpp delete mode 100644 Common/StdKit/ELF.hpp delete mode 100644 Common/StdKit/ErrorID.hpp delete mode 100644 Common/StdKit/ErrorOr.hpp delete mode 100644 Common/StdKit/PEF.hpp delete mode 100644 Common/StdKit/Ref.hpp delete mode 100644 Common/StdKit/String.hpp delete mode 100644 Common/StdKit/XCOFF.hxx delete mode 100644 Common/UUID.hpp delete mode 100644 Common/Version.hxx create mode 100644 Doc/Inside 64x0.pdf create mode 100644 Doc/asm-specs.txt create mode 100644 Doc/havp.txt create mode 100644 Doc/notice.txt create mode 100644 Doc/vnrp.txt delete mode 100644 docs/Inside 64x0.pdf delete mode 100644 docs/asm-specs.txt delete mode 100644 docs/havp.txt delete mode 100644 docs/notice.txt delete mode 100644 docs/vnrp.txt (limited to 'Sources') diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 0aad778..696e195 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "Macintosh (CLang)", "includePath": [ - "${workspaceFolder}/Common/**", + "${workspaceFolder}/Comm/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], @@ -16,7 +16,7 @@ { "name": "Windows (Cygwin)", "includePath": [ - "${workspaceFolder}/Common/**", + "${workspaceFolder}/Comm/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], diff --git a/Comm/AsmKit/AsmKit.hpp b/Comm/AsmKit/AsmKit.hpp new file mode 100644 index 0000000..1801130 --- /dev/null +++ b/Comm/AsmKit/AsmKit.hpp @@ -0,0 +1,217 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include +#include + +namespace CompilerKit +{ + // + // @brief Frontend to Assembly mountpoint. + // + class AssemblyInterface + { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + MPCC_COPY_DEFAULT(AssemblyInterface); + + //@ brief compile to object file. + // Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; + }; + + /// @brief Simple assembly factory + class AssemblyFactory final + { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + MPCC_COPY_DEFAULT(AssemblyFactory); + + public: + enum + { + kArchAMD64, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchUnknown, + }; + + Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; + }; + + union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; + }; + + union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) + : raw(raw) + { + } + ~NumberCast64() + { + raw = 0; + } + + CharType number[8]; + UInt64 raw; + }; + + union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) + : raw(raw) + { + } + ~NumberCast32() + { + raw = 0; + } + + CharType number[4]; + UInt32 raw; + }; + + union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) + : raw(raw) + { + } + ~NumberCast16() + { + raw = 0; + } + + CharType number[2]; + UInt16 raw; + }; + + union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) + : raw(raw) + { + } + ~NumberCast8() + { + raw = 0; + } + + CharType number; + UInt8 raw; + }; + + class EncoderInterface + { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + MPCC_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string& line, const std::string& file) = 0; + virtual bool WriteLine(std::string& line, const std::string& file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; + }; + +#ifdef __ASM_NEED_AMD64__ + + class EncoderAMD64 final : public EncoderInterface + { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; + + MPCC_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + + virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); + }; + +#endif // __ASM_NEED_AMD64__ + +#ifdef __ASM_NEED_64x0__ + + class Encoder64x0 final : public EncoderInterface + { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + MPCC_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_64x0__ + +#ifdef __ASM_NEED_32x0__ + + class Encoder32x0 final : public EncoderInterface + { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; + + MPCC_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ + +#ifdef __ASM_NEED_PPC__ + + class EncoderPowerPC final : public EncoderInterface + { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; + + MPCC_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ +} // namespace CompilerKit diff --git a/Comm/AsmKit/CPU/32x0.hpp b/Comm/AsmKit/CPU/32x0.hpp new file mode 100644 index 0000000..0013752 --- /dev/null +++ b/Comm/AsmKit/CPU/32x0.hpp @@ -0,0 +1,95 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @brief 32x0 support. +// @file CPU/32x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 + +#define kAsmByte 0 +#define kAsmHWord 1 +#define kAsmWord 2 + +struct CpuCode32x0 +{ + const char fName[32]; + char fOpcode; + char fSize; + char fFunct3; + char fFunct7; +}; + +#define kAsmDWordStr ".dword" /* 64 bit */ +#define kAsmWordStr ".word" /* 32-bit */ +#define kAsmHWordStr ".half" /* 16-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ + +inline std::vector kOpcodes32x0 = { + kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. + kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch + kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers + kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp + kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. + kAsmOpcodeDecl("cls", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR. + kAsmOpcodeDecl("rts", 0b0111011, 0b110, + kAsmImmediate) // pull stack and return form CR. + kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt +}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: TODO: find one +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Comm/AsmKit/CPU/64x0.hpp b/Comm/AsmKit/CPU/64x0.hpp new file mode 100644 index 0000000..e2e03c8 --- /dev/null +++ b/Comm/AsmKit/CPU/64x0.hpp @@ -0,0 +1,108 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +// @brief 64x0 support. +// @file CPU/64x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 + +typedef char e64k_character_t; +typedef uint8_t e64k_num_t; + +struct CpuOpcode64x0 +{ + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; +}; + +inline std::vector kOpcodes64x0 = { + kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) + kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) + kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) + kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL/JUMP ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Comm/AsmKit/CPU/amd64.hpp b/Comm/AsmKit/CPU/amd64.hpp new file mode 100644 index 0000000..d461574 --- /dev/null +++ b/Comm/AsmKit/CPU/amd64.hpp @@ -0,0 +1,56 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @brief AMD64 support. +// @file CPU/amd64.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, + +typedef char i64_character_t; +typedef uint8_t i64_byte_t; +typedef uint16_t i64_hword_t; +typedef uint32_t i64_word_t; + +struct CpuOpcodeAMD64 +{ + std::string fName; + i64_byte_t fPrefixBytes[4]; + i64_hword_t fOpcode; + i64_hword_t fModReg; + i64_word_t fDisplacment; + i64_word_t fImmediate; +}; + +/// these two are edge cases +#define kAsmIntOpcode 0xCC +#define kasmIntOpcodeAlt 0xCD + +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 +#define kJumpLimitStandardLimit 0xEB + +inline std::vector kOpcodesAMD64 = { + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF)}; + +#define kAsmRegisterLimit 15 diff --git a/Comm/AsmKit/CPU/ppc.hpp b/Comm/AsmKit/CPU/ppc.hpp new file mode 100644 index 0000000..c4265da --- /dev/null +++ b/Comm/AsmKit/CPU/ppc.hpp @@ -0,0 +1,1919 @@ +#pragma once + +#include + +/// @note Based of: +/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html + +/* + * These defines are use in the cpus field of the instructions. If the field + * is zero it can execute on all cpus. The defines are or'ed together. This + * information is used to set the cpusubtype in the resulting object file. + */ +#define CPU601 0x1 +#define IMPL64 0x2 +#define OPTIONAL 0x4 +#define VMX 0x8 +#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ +#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ + +enum optype +{ + NONE, /* no operand */ + JBSR, /* jbsr pseudo op */ + PCREL, /* PC relative (branch offset) */ + BADDR, /* Branch address (sign extended absolute address) */ + D, /* 16 bit displacement */ + DS, /* 14 bit displacement (double word) */ + SI, /* signed 16 bit immediate */ + UI, /* unsigned 16 bit immediate */ + HI, /* high 16 bit immediate (with truncation) */ + GREG, /* general register */ + G0REG, /* general register r1-r31 or 0 */ + FREG, /* float register */ + VREG, /* vector register */ + SGREG, /* segment register */ + SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ + BCND, /* branch condition opcode */ + CRF, /* condition register field */ + CRFONLY, /* condition register field only no expression allowed */ + sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ + mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ + NUM, /* number */ + SNUM, /* signed number */ + NUM0, /* number (where 1< + +#define SizeType size_t + +#define VoidPtr void* +#define voidPtr VoidPtr + +#define UIntPtr uintptr_t + +#define Int64 int64_t +#define UInt64 uint64_t + +#define Int32 int +#define UInt32 unsigned + +#define Bool bool + +#define Int16 int16_t +#define UInt16 uint16_t + +#define Int8 int8_t +#define UInt8 uint8_t + +#define CharType char +#define Boolean bool + +#include +#include +#include + +#define nullPtr std::nullptr_t + +#define MUST_PASS(E) assert(E) + +#ifndef __FORCE_STRLEN +#define __FORCE_STRLEN 1 + +#define string_length(len) strlen(len) +#endif + +#ifndef __FORCE_MEMCPY +#define __FORCE_MEMCPY 1 + +#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) +#endif + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#include +#include +#include +#include + +namespace CompilerKit +{ + inline constexpr int BASE_YEAR = 1900; + + inline std::string current_date() noexcept + { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); + + std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); + + return fmt; + } + + inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept + { + if (limit == 0) + return false; + + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; + + while (limit != 1) + { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; + } +} // namespace CompilerKit + +#define PACKED __attribute__((packed)) + +typedef char char_type; + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts \ + { \ + ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ + } + +#ifdef __MODULE_NEED__ +#define MPCC_MODULE(name) int name(int argc, char** argv) +#else +#define MPCC_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __MODULE_NEED__ */ + +#pragma scalar_storage_order big - endian + +#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Comm/ParserKit.hpp b/Comm/ParserKit.hpp new file mode 100644 index 0000000..9109d32 --- /dev/null +++ b/Comm/ParserKit.hpp @@ -0,0 +1,171 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include +#include + +namespace ParserKit +{ + using namespace CompilerKit; + + /// @brief Compiler backend, implements a frontend, such as C, C++... + /// See Toolchain, for some examples. + class CompilerBackend + { + public: + explicit CompilerBackend() = default; + virtual ~CompilerBackend() = default; + + MPCC_COPY_DEFAULT(CompilerBackend); + + // NOTE: cast this to your user defined ast. + typedef void* AstType; + + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + + virtual bool Compile(const std::string& text, const char* file) = 0; + + //! @brief What language are we dealing with? + virtual const char* Language() + { + return "Invalid Language"; + } + }; + + struct SyntaxLeafList; + struct SyntaxLeafList; + struct CompilerKeyword; + + /// we want to do that because to separate keywords. + enum KeywordKind + { + eKeywordKindNamespace, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, + eKeywordKindVariable, + eKeywordKindType, + eKeywordKindExpressionBegin, + eKeywordKindExpressionEnd, + eKeywordKindArgSeparator, + eKeywordKindBodyStart, + eKeywordKindBodyEnd, + eKeywordKindClass, + eKeywordKindPtrAccess, + eKeywordKindAccess, + eKeywordKindIf, + eKeywordKindElse, + eKeywordKindElseIf, + eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, + eKeywordKindConstant, + eKeywordKindTypedef, + eKeywordKindEndInstr, + eKeywordKindSpecifier, + eKeywordKindInvalid, + eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, + }; + + /// \brief Compiler keyword information struct. + struct CompilerKeyword + { + std::string keyword_name; + KeywordKind keyword_kind = eKeywordKindInvalid; + }; + struct SyntaxLeafList final + { + struct SyntaxLeaf final + { + Int32 fUserType; +#ifdef __PK_USE_STRUCT_INSTEAD__ + CompilerKeyword fUserData; +#else + std::string fUserData; +#endif + + std::string fUserValue; + struct SyntaxLeaf* fNext; + }; + + std::vector fLeafList; + SizeType fNumLeafs; + + size_t SizeOf() + { + return fNumLeafs; + } + std::vector& Get() + { + return fLeafList; + } + SyntaxLeaf& At(size_t index) + { + return fLeafList[index]; + } + }; + + /// find the perfect matching word in a haystack. + /// \param haystack base string + /// \param needle the string we search for. + /// \return if we found it or not. + inline bool find_word(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) + return true; + + if (index < 0 || index >= haystack.size()) + return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); + } + + /// find a word within strict conditions and returns a range of it. + /// \param haystack + /// \param needle + /// \return position of needle. + inline std::size_t find_word_range(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) + { + return index; + } + + return false; + } +} // namespace ParserKit diff --git a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx new file mode 100644 index 0000000..a1c638e --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +typedef void* ptr_type; +typedef __SIZE_TYPE__ size_type; + +inline void* __mpcc_alloca_gcc(size_type sz) +{ + return __builtin_alloca(sz); +} diff --git a/Comm/Public/SDK/CRT/__mpcc_defines.hxx b/Comm/Public/SDK/CRT/__mpcc_defines.hxx new file mode 100644 index 0000000..5560410 --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_defines.hxx @@ -0,0 +1,89 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#ifndef __MPCC_DEF__ +#define __MPCC_DEF__ + +#ifndef __GNUC__ + +typedef __SIZE_TYPE__ size_t; + +#ifdef __LP64__ +typedef long int ssize_t; +#else +typedef int ssize_t; +#endif // __LP64__ + +typedef size_t ptrdiff_t; +typedef size_t uintptr_t; +typedef void* voidptr_t; +typedef void* any_t; +typedef char* caddr_t; + +#ifndef NULL +#define NULL ((voidptr_t)0) +#endif // !null + +#ifdef __GNUC__ +#include +#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#elif defined(__MPCC__) + +#define __alloca(sz) __mpcc_alloca(sz) +#endif + +#define __deref(ptr) (*(ptr)) + +#ifdef __cplusplus +#define __init_decl() \ + extern "C" \ + { +#define __fini_decl() \ + } \ + ; +#else +#define __init_decl() +#define __fini_decl() +#endif + +#if __has_builtin(__builtin_alloca) +#define alloca(sz) __builtin_alloca(sz) +#ifdef __alloca +#undef __alloca +#endif +#define __alloca alloca +#else +#warning alloca not detected (MPCC) +#endif + +typedef long long off_t; +typedef unsigned long long uoff_t; + +typedef union float_cast { + struct + { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int sign : 1; + }; + + float f; +} __attribute__((packed)) float_cast_t; + +typedef union double_cast { + struct + { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; +} __attribute__((packed)) double_cast_t; + +#endif // ifndef __GNUC__ + +#endif /* __MPCC_DEF__ */ diff --git a/Comm/Public/SDK/CRT/__mpcc_exception.hxx b/Comm/Public/SDK/CRT/__mpcc_exception.hxx new file mode 100644 index 0000000..9366102 --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_exception.hxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +/// This file is an implementation of __throw* family of functions. + +#include +#include +#include + +namespace std +{ + inline void __throw_general(void) + { + throw std::runtime_error("MPCC C++ Runtime error."); + } + + inline void __throw_domain_error(const char* error) + { + std::cout << "MPCC C++: Domain error: " << error << "\r"; + __throw_general(); + } +} // namespace std diff --git a/Comm/Public/SDK/CRT/__mpcc_hint.hxx b/Comm/Public/SDK/CRT/__mpcc_hint.hxx new file mode 100644 index 0000000..ee14711 --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_hint.hxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#pragma compiler(hint_manifest) + +#define _Input +#define _Output + +#define _Optional + +#define _StrictCheckInput +#define _StrictCheckOutput + +#define _InOut +#define _StrictInOut diff --git a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx new file mode 100644 index 0000000..2731868 --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +namespace stdx +{ + /// @brief allocate a new class. + /// @tparam KindClass the class type to allocate. + template + inline void* allocate(Args&&... args) + { + return new KindClass(std::forward(args)...); + } + + /// @brief free a class. + /// @tparam KindClass the class type to allocate. + template + inline void release(KindClass ptr) + { + if (!ptr) + return; + delete ptr; + } +} // namespace stdx diff --git a/Comm/Public/SDK/CRT/__mpcc_power.inc b/Comm/Public/SDK/CRT/__mpcc_power.inc new file mode 100644 index 0000000..9e4928c --- /dev/null +++ b/Comm/Public/SDK/CRT/__mpcc_power.inc @@ -0,0 +1,35 @@ +# Path: SDK/__mpcc_power.inc +# Language: MPCC POWER Assembly support for GNU. +# Build Date: 2024-6-4 + +%ifdef __CODETOOLS__ + +%def lda li +%def sta stw +%def ldw li + +%def r0 0 +%def r1 1 +%def r2 2 +%def r3 3 +%def r4 4 +%def r5 5 +%def r6 6 +%def r7 7 +%def r8 8 +%def r9 9 +%def r10 10 +%def r11 11 +%def r12 12 +%def r13 13 +%def r14 14 +%def r15 15 +%def r16 16 +%def r17 17 +%def r18 18 +%def r19 19 +%def r20 20 + +%endif + +%def nop mr 0, 0 diff --git a/Comm/StdKit/AE.hpp b/Comm/StdKit/AE.hpp new file mode 100644 index 0000000..505ed77 --- /dev/null +++ b/Comm/StdKit/AE.hpp @@ -0,0 +1,143 @@ +/* + * ======================================================== + * + * MPCC + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include + +#define kAEMag0 'A' +#define kAEMag1 'E' + +#define kAESymbolLen 64 +#define kAEPad 8 +#define kAEMagLen 2 +#define kAEInvalidOpcode 0x00 + +// Advanced Executable File Format for MetroLink. +// Reloctable by offset is the default strategy. +// You can also relocate at runtime but that's up to the operating system +// loader. + +namespace CompilerKit +{ + // @brief Advanced Executable Header + // One thing to keep in mind. + // This object format, is reloctable. + typedef struct AEHeader final + { + CharType fMagic[kAEMagLen]; + CharType fArch; + CharType fSubArch; + SizeType fCount; + CharType fSize; + SizeType fStartCode; + SizeType fCodeSize; + CharType fPad[kAEPad]; + } PACKED AEHeader, *AEHeaderPtr; + + // @brief Advanced Executable Record. + // Could be data, code or bss. + // fKind must be filled with PEF fields. + + typedef struct AERecordHeader final + { + CharType fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + CharType fPad[kAEPad]; + } PACKED AERecordHeader, *AERecordHeaderPtr; + + enum + { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, + }; +} // namespace CompilerKit + +// provide operator<< for AE + +std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); + + return fp; +} + +std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); + + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); + return fp; +} + +namespace CompilerKit::Utils +{ + /** + * @brief AE Reader protocol + * + */ + class AEReadableProtocol final + { + public: + std::ifstream FP; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + MPCC_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) + { + if (!raw) + return nullptr; + + return this->_Read(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template + TypeClass* _Read(char* raw, std::size_t sz) + { + FP.read(raw, std::streamsize(sz)); + return reinterpret_cast(raw); + } + }; +} // namespace CompilerKit::Utils diff --git a/Comm/StdKit/ELF.hpp b/Comm/StdKit/ELF.hpp new file mode 100644 index 0000000..4f0d0ae --- /dev/null +++ b/Comm/StdKit/ELF.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include +#include + +struct file; + +#ifndef elf_read_implies_exec +/* Executables for which elf_read_implies_exec() returns TRUE will + have the READ_IMPLIES_EXEC personality flag set automatically. + Override in asm/elf.h as needed. */ +#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 +#endif + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uintptr_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x)&0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* POWER VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; diff --git a/Comm/StdKit/ErrorID.hpp b/Comm/StdKit/ErrorID.hpp new file mode 100644 index 0000000..bea70ae --- /dev/null +++ b/Comm/StdKit/ErrorID.hpp @@ -0,0 +1,22 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +#define MPCC_EXEC_ERROR -30 +#define MPCC_FILE_NOT_FOUND -31 +#define MPCC_DIR_NOT_FOUND -32 +#define MPCC_FILE_EXISTS -33 +#define MPCC_TOO_LONG -34 +#define MPCC_INVALID_DATA -35 +#define MPCC_UNIMPLEMENTED -36 +#define MPCC_FAT_ERROR -37 diff --git a/Comm/StdKit/ErrorOr.hpp b/Comm/StdKit/ErrorOr.hpp new file mode 100644 index 0000000..0125f82 --- /dev/null +++ b/Comm/StdKit/ErrorOr.hpp @@ -0,0 +1,61 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + using ErrorT = UInt32; + + template + class ErrorOr final + { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) + : mId(err) + { + } + + explicit ErrorOr(nullPtr Null) + { + } + + explicit ErrorOr(T Class) + : mRef(Class) + { + } + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref Leak() + { + return mRef; + } + + operator bool() + { + return mRef; + } + + private: + Ref mRef; + Int32 mId{0}; + }; + + using ErrorOrAny = ErrorOr; + +} // namespace CompilerKit diff --git a/Comm/StdKit/PEF.hpp b/Comm/StdKit/PEF.hpp new file mode 100644 index 0000000..e790d6a --- /dev/null +++ b/Comm/StdKit/PEF.hpp @@ -0,0 +1,132 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + +------------------------------------------- */ + +#pragma once + +#include + +// @file PEF.hpp +// @brief Preferred Executable Format + +#define kPefMagic "Joy!" +#define kPefMagicFat "yoJ!" + +#define kPefExt ".exec" +#define kPefDylibExt ".lib" +#define kPefLibExt ".slib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" + +#define kPefMagicLen 5 + +#define kPefVersion 2 +#define kPefNameLen 255 + +#define kPefBaseOrigin (0x1000000) + +#define kPefStart "__ImageStart" + +namespace CompilerKit +{ + enum + { + kPefArchIntel86S = 100, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* 64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, + }; + + enum + { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchGeneric, + kPefSubArchIBM, + }; + + enum + { + kPefKindExec = 1, /* .exe */ + kPefKindSharedObject = 2, /* .lib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, + }; + + /* PEF container */ + typedef struct PEFContainer final + { + CharType Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ + } PACKED PEFContainer; + + /* First PEFCommandHeader starts after PEFContainer */ + /* Last container is __exec_end */ + + /* PEF executable section and commands. */ + + typedef struct PEFCommandHeader final + { + CharType Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* file offset */ + SizeType Size; /* file size */ + } PACKED PEFCommandHeader; + + enum + { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, + kPefInvalid = 0xFF, + }; +} // namespace CompilerKit + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} diff --git a/Comm/StdKit/Ref.hpp b/Comm/StdKit/Ref.hpp new file mode 100644 index 0000000..f4a11c0 --- /dev/null +++ b/Comm/StdKit/Ref.hpp @@ -0,0 +1,91 @@ + +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +namespace CompilerKit +{ + // @author SoftwareLabs + // @brief Reference class, refers to a pointer of data in static memory. + template + class Ref final + { + public: + explicit Ref() = default; + ~Ref() = default; + + public: + explicit Ref(T cls, const bool& strong = false) + : m_Class(cls), m_Strong(strong) + { + } + + Ref& operator=(T ref) + { + m_Class = ref; + return *this; + } + + public: + T operator->() const + { + return m_Class; + } + + T& Leak() + { + return m_Class; + } + + T operator*() + { + return m_Class; + } + + bool IsStrong() const + { + return m_Strong; + } + + operator bool() + { + return m_Class; + } + + private: + T m_Class; + bool m_Strong{false}; + }; + + template + class NonNullRef final + { + public: + NonNullRef() = delete; + NonNullRef(nullPtr) = delete; + + explicit NonNullRef(T* ref) + : m_Ref(ref, true) + { + } + + Ref& operator->() + { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef& ref) = delete; + NonNullRef(const NonNullRef& ref) = default; + + private: + Ref m_Ref{nullptr}; + }; +} // namespace CompilerKit diff --git a/Comm/StdKit/String.hpp b/Comm/StdKit/String.hpp new file mode 100644 index 0000000..c6589cc --- /dev/null +++ b/Comm/StdKit/String.hpp @@ -0,0 +1,90 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright SoftwareLabs, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + /** + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + + class StringView final + { + public: + explicit StringView() = delete; + + explicit StringView(SizeType Sz) noexcept + : m_Sz(Sz) + { + m_Data = new char[Sz]; + assert(m_Data); + } + + ~StringView() noexcept + { + if (m_Data) + { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + MPCC_COPY_DEFAULT(StringView); + + CharType* Data(); + const CharType* CData() const; + SizeType Length() const; + + bool operator==(const CharType* rhs) const; + bool operator!=(const CharType* rhs) const; + + bool operator==(const StringView& rhs) const; + bool operator!=(const StringView& rhs) const; + + StringView& operator+=(const CharType* rhs); + StringView& operator+=(const StringView& rhs); + + operator bool() + { + return m_Data && m_Data[0] != 0; + } + + bool operator!() + { + return !m_Data || m_Data[0] == 0; + } + + private: + char* m_Data{nullptr}; + SizeType m_Sz{0}; + SizeType m_Cur{0}; + + friend class StringBuilder; + }; + + /** + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ + struct StringBuilder final + { + static StringView Construct(const CharType* data); + static const char* FromInt(const char* fmt, int n); + static const char* FromBool(const char* fmt, bool n); + static const char* Format(const char* fmt, const char* from); + static bool Equals(const char* lhs, const char* rhs); + }; +} // namespace CompilerKit diff --git a/Comm/StdKit/XCOFF.hxx b/Comm/StdKit/XCOFF.hxx new file mode 100644 index 0000000..fee1888 --- /dev/null +++ b/Comm/StdKit/XCOFF.hxx @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright SoftwareLabs + + File: XCOFF.hpp + Purpose: XCOFF for NewOS. + + Revision History: + + 04/07/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __XCOFF__ +#define __XCOFF__ + +#include + +#define kXCOFF64Magic 0x01F7 + +#define kXCOFFRelFlg 0x0001 +#define kXCOFFExecutable 0x0002 +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace CompilerKit +{ + /// @brief XCoff identification header. + typedef struct XCoffFileHeader + { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header + } XCoffFileHeader; +} // namespace CompilerKit + +#endif // ifndef __XCOFF__ \ No newline at end of file diff --git a/Comm/UUID.hpp b/Comm/UUID.hpp new file mode 100644 index 0000000..00b153b --- /dev/null +++ b/Comm/UUID.hpp @@ -0,0 +1,983 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define LIBUUID_CPP20_OR_GREATER +#endif + +#endif + +#ifdef LIBUUID_CPP20_OR_GREATER +#include +#else +#include +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#ifdef UUID_TIME_GENERATOR +#include +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#endif + +namespace uuids +{ +#ifdef __cpp_lib_span + template + using span = std::span; +#else + template + using span = gsl::span; +#endif + + namespace detail + { + template + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept + { + if (ch >= static_cast('0') && ch <= static_cast('9')) + return static_cast(ch - static_cast('0')); + if (ch >= static_cast('a') && ch <= static_cast('f')) + return static_cast(10 + ch - static_cast('a')); + if (ch >= static_cast('A') && ch <= static_cast('F')) + return static_cast(10 + ch - static_cast('A')); + return 0; + } + + template + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept + { + return (ch >= static_cast('0') && ch <= static_cast('9')) || + (ch >= static_cast('a') && ch <= static_cast('f')) || + (ch >= static_cast('A') && ch <= static_cast('F')); + } + + template + [[nodiscard]] constexpr std::basic_string_view to_string_view( + TChar const* str) noexcept + { + if (str) + return str; + return {}; + } + + template + [[nodiscard]] constexpr std::basic_string_view + to_string_view(StringType const& str) noexcept + { + return str; + } + + class sha1 + { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate( + uint32_t value, size_t const count) noexcept + { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() + { + reset(); + } + + void reset() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) + { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) + { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) + { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) + { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) + { + const uint8_t* block = static_cast(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) + { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) + { + while (m_blockByteIndex != 0) + { + process_byte(0); + } + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + else + { + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast((bitCount >> 24) & 0xFF)); + process_byte(static_cast((bitCount >> 16) & 0xFF)); + process_byte(static_cast((bitCount >> 8) & 0xFF)); + process_byte(static_cast((bitCount)&0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) + { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast(d32[0] >> 24); + digest[di++] = static_cast(d32[0] >> 16); + digest[di++] = static_cast(d32[0] >> 8); + digest[di++] = static_cast(d32[0] >> 0); + + digest[di++] = static_cast(d32[1] >> 24); + digest[di++] = static_cast(d32[1] >> 16); + digest[di++] = static_cast(d32[1] >> 8); + digest[di++] = static_cast(d32[1] >> 0); + + digest[di++] = static_cast(d32[2] >> 24); + digest[di++] = static_cast(d32[2] >> 16); + digest[di++] = static_cast(d32[2] >> 8); + digest[di++] = static_cast(d32[2] >> 0); + + digest[di++] = static_cast(d32[3] >> 24); + digest[di++] = static_cast(d32[3] >> 16); + digest[di++] = static_cast(d32[3] >> 8); + digest[di++] = static_cast(d32[3] >> 0); + + digest[di++] = static_cast(d32[4] >> 24); + digest[di++] = static_cast(d32[4] >> 16); + digest[di++] = static_cast(d32[4] >> 8); + digest[di++] = static_cast(d32[4] >> 0); + + return digest; + } + + private: + void process_block() + { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) + { + w[i] = static_cast(m_block[i * 4 + 0] << 24); + w[i] |= static_cast(m_block[i * 4 + 1] << 16); + w[i] |= static_cast(m_block[i * 4 + 2] << 8); + w[i] |= static_cast(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) + { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) + { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) + { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid[37] = + L"00000000-0000-0000-0000-000000000000"; + + template + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; + } // namespace detail + + // -------------------------------------------------------------------------------------------------------------------------- + // UUID format https://tools.ietf.org/html/rfc4122 + // -------------------------------------------------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------------------------------------------------- + // Field NDR Data Type Octet # Note + // -------------------------------------------------------------------------------------------------------------------------- + // time_low unsigned long 0 - 3 The low field + // of the timestamp. time_mid unsigned short 4 - 5 + // The middle field of the timestamp. time_hi_and_version unsigned + // short 6 - 7 The high field of the timestamp multiplexed + // with the version number. clock_seq_hi_and_reserved unsigned small 8 + // The high field of the clock sequence multiplexed with the variant. + // clock_seq_low unsigned small 9 The low + // field of the clock sequence. node character 10 + // - 15 The spatially unique node identifier. + // -------------------------------------------------------------------------------------------------------------------------- + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // -------------------------------------------------------------------------------------------------------------------------- + // enumerations + // -------------------------------------------------------------------------------------------------------------------------- + + // indicated by a bit pattern in octet 8, marked with N in + // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx + enum class uuid_variant + { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved + }; + + // indicated by a bit pattern in octet 6, marked with M in + // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx + enum class uuid_version + { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = + 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = + 5 // The name-based version specified in RFS 4122 with SHA1 hashing + }; + + // Forward declare uuid & to_string so that we can declare to_string as a friend + // later. + class uuid; + template , class Allocator = std::allocator> + std::basic_string to_string(uuid const& id); + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid class + // -------------------------------------------------------------------------------------------------------------------------- + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept + { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array const& arr) noexcept + : data{arr} + { + } + + explicit uuid(span bytes) + { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template + explicit uuid(ForwardIterator first, ForwardIterator last) + { + if (std::distance(first, last) == 16) + std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept + { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept + { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept + { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) + return false; + return true; + } + + void swap(uuid& other) noexcept + { + data.swap(other.data); + } + + [[nodiscard]] inline span as_bytes() const + { + return span( + reinterpret_cast(data.data()), 16); + } + + template + [[nodiscard]] constexpr static bool is_valid_uuid( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) + return false; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return false; + } + + if (firstDigit) + { + firstDigit = false; + } + else + { + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return false; + } + + return true; + } + + template + [[nodiscard]] constexpr static std::optional from_string( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array data{{0}}; + + if (str.empty()) + return {}; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return {}; + } + + if (firstDigit) + { + data[index] = static_cast(detail::hex2char(str[i]) << 4); + firstDigit = false; + } + else + { + data[index] = + static_cast(data[index] | detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return {}; + } + + return uuid{data}; + } + + private: + std::array data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template + friend std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id); + + template + friend std::basic_string to_string(uuid const& id); + + friend std::hash; + }; + + // -------------------------------------------------------------------------------------------------------------------------- + // operators and non-member functions + // -------------------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] inline bool operator==(uuid const& lhs, + uuid const& rhs) noexcept + { + return lhs.data == rhs.data; + } + + [[nodiscard]] inline bool operator!=(uuid const& lhs, + uuid const& rhs) noexcept + { + return !(lhs == rhs); + } + + [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data < rhs.data; + } + + template + [[nodiscard]] inline std::basic_string to_string( + uuid const& id) + { + std::basic_string uustr{detail::empty_guid}; + + for (size_t i = 0, index = 0; i < 36; ++i) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + continue; + } + uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; + uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; + index++; + } + + return uustr; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id) + { + s << to_string(id); + return s; + } + + inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept + { + lhs.swap(rhs); + } + + // -------------------------------------------------------------------------------------------------------------------------- + // namespace IDs that could be used for generating name-based uuids + // -------------------------------------------------------------------------------------------------------------------------- + + // Name string is a fully-qualified domain name + static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is a URL + static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an ISO OID (See https://oidref.com/, + // https://en.wikipedia.org/wiki/Object_identifier) + static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an X.500 DN, in DER or a text output format (See + // https://en.wikipedia.org/wiki/X.500, + // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) + static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid generators + // -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR + class uuid_system_generator + { + public: + using result_type = uuid; + + uuid operator()() + { +#ifdef _WIN32 + + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) + { + throw std::system_error(hr, std::system_category(), + "CoCreateGuid failed"); + } + + std::array bytes = { + {static_cast((newId.Data1 >> 24) & 0xFF), + static_cast((newId.Data1 >> 16) & 0xFF), + static_cast((newId.Data1 >> 8) & 0xFF), + static_cast((newId.Data1) & 0xFF), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xFF), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], + newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], + id[6], id[7], id[8], id[9], id[10], + id[11], id[12], id[13], id[14], id[15]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array arrbytes = { + {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, + bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, + bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, + bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; +#else + return uuid{}; +#endif + } + }; +#endif + + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) + : generator(&gen, [](auto) {}) + { + } + explicit basic_uuid_random_generator(engine_type* gen) + : generator(gen, [](auto) {}) + { + } + + [[nodiscard]] uuid operator()() + { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution distribution; + std::shared_ptr generator; + }; + + using uuid_random_generator = basic_uuid_random_generator; + + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept + : nsuuid(namespace_uuid) + { + } + + template + [[nodiscard]] uuid operator()(StringType const& name) + { + reset(); + process_characters(detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() + { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template + void process_characters(std::basic_string_view const str) + { + for (uint32_t c : str) + { + hasher.process_byte(static_cast(c & 0xFF)); + if constexpr (!std::is_same_v) + { + hasher.process_byte(static_cast((c >> 8) & 0xFF)); + hasher.process_byte(static_cast((c >> 16) & 0xFF)); + hasher.process_byte(static_cast((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() + { + detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + detail::sha1 hasher; + }; + +#ifdef UUID_TIME_GENERATOR + // !!! DO NOT USE THIS IN PRODUCTION + // this implementation is unreliable for good uuids + class uuid_time_generator + { + using mac_address = std::array; + + std::optional device_address; + + [[nodiscard]] bool get_mac_address() + { + if (device_address.has_value()) + { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) + return false; + std::vector buf(len); + auto pips = reinterpret_cast(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) + return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() + { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = + std::chrono::duration_cast(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() + { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() + { + if (get_mac_address()) + { + std::array data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } + }; +#endif +} // namespace uuids + +namespace std +{ + template <> + struct hash + { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const + { +#ifdef UUID_HASH_STRING_BASED + std::hash hasher; + return static_cast(hasher(uuids::to_string(uuid))); +#else + uint64_t l = static_cast(uuid.data[0]) << 56 | + static_cast(uuid.data[1]) << 48 | + static_cast(uuid.data[2]) << 40 | + static_cast(uuid.data[3]) << 32 | + static_cast(uuid.data[4]) << 24 | + static_cast(uuid.data[5]) << 16 | + static_cast(uuid.data[6]) << 8 | + static_cast(uuid.data[7]); + uint64_t h = static_cast(uuid.data[8]) << 56 | + static_cast(uuid.data[9]) << 48 | + static_cast(uuid.data[10]) << 40 | + static_cast(uuid.data[11]) << 32 | + static_cast(uuid.data[12]) << 24 | + static_cast(uuid.data[13]) << 16 | + static_cast(uuid.data[14]) << 8 | + static_cast(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) + { + return result_type(l ^ h); + } + else + { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } + }; +} // namespace std + +#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Comm/Version.hxx b/Comm/Version.hxx new file mode 100644 index 0000000..377a688 --- /dev/null +++ b/Comm/Version.hxx @@ -0,0 +1,3 @@ +#pragma once + +#define kDistVersion "v1.20" diff --git a/Common/AsmKit/AsmKit.hpp b/Common/AsmKit/AsmKit.hpp deleted file mode 100644 index 020ca5c..0000000 --- a/Common/AsmKit/AsmKit.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include -#include - -namespace CompilerKit -{ - // - // @brief Frontend to Assembly mountpoint. - // - class AssemblyInterface - { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - MPCC_COPY_DEFAULT(AssemblyInterface); - - //@ brief compile to object file. - // Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; - }; - - /// @brief Simple assembly factory - class AssemblyFactory final - { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - MPCC_COPY_DEFAULT(AssemblyFactory); - - public: - enum - { - kArchAMD64, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchUnknown, - }; - - Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; - }; - - union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; - }; - - union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) - : raw(raw) - { - } - ~NumberCast64() - { - raw = 0; - } - - CharType number[8]; - UInt64 raw; - }; - - union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) - : raw(raw) - { - } - ~NumberCast32() - { - raw = 0; - } - - CharType number[4]; - UInt32 raw; - }; - - union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) - : raw(raw) - { - } - ~NumberCast16() - { - raw = 0; - } - - CharType number[2]; - UInt16 raw; - }; - - union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) - : raw(raw) - { - } - ~NumberCast8() - { - raw = 0; - } - - CharType number; - UInt8 raw; - }; - - class EncoderInterface - { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - MPCC_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string& line, const std::string& file) = 0; - virtual bool WriteLine(std::string& line, const std::string& file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; - }; - -#ifdef __ASM_NEED_AMD64__ - - class EncoderAMD64 final : public EncoderInterface - { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - MPCC_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); - }; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_64x0__ - - class Encoder64x0 final : public EncoderInterface - { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - MPCC_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - - class Encoder32x0 final : public EncoderInterface - { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - MPCC_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - - class EncoderPowerPC final : public EncoderInterface - { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - MPCC_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/Common/AsmKit/CPU/32x0.hpp b/Common/AsmKit/CPU/32x0.hpp deleted file mode 100644 index fe03336..0000000 --- a/Common/AsmKit/CPU/32x0.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @brief 32x0 support. -// @file CPU/32x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 - -#define kAsmByte 0 -#define kAsmHWord 1 -#define kAsmWord 2 - -struct CpuCode32x0 -{ - const char fName[32]; - char fOpcode; - char fSize; - char fFunct3; - char fFunct7; -}; - -#define kAsmDWordStr ".dword" /* 64 bit */ -#define kAsmWordStr ".word" /* 32-bit */ -#define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ - -inline std::vector kOpcodes32x0 = { - kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. - kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch - kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers - kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp - kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. - kAsmOpcodeDecl("cls", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR. - kAsmOpcodeDecl("rts", 0b0111011, 0b110, - kAsmImmediate) // pull stack and return form CR. - kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt -}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: TODO: find one -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Common/AsmKit/CPU/64x0.hpp b/Common/AsmKit/CPU/64x0.hpp deleted file mode 100644 index b28866f..0000000 --- a/Common/AsmKit/CPU/64x0.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -// @brief 64x0 support. -// @file CPU/64x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 - -typedef char e64k_character_t; -typedef uint8_t e64k_num_t; - -struct CpuOpcode64x0 -{ - const e64k_character_t fName[32]; - e64k_num_t fOpcode; - e64k_num_t fFunct3; - e64k_num_t fFunct7; -}; - -inline std::vector kOpcodes64x0 = { - kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) - kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) - kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL/JUMP ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Common/AsmKit/CPU/amd64.hpp b/Common/AsmKit/CPU/amd64.hpp deleted file mode 100644 index 507602c..0000000 --- a/Common/AsmKit/CPU/amd64.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @brief AMD64 support. -// @file CPU/amd64.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, - -typedef char i64_character_t; -typedef uint8_t i64_byte_t; -typedef uint16_t i64_hword_t; -typedef uint32_t i64_word_t; - -struct CpuOpcodeAMD64 -{ - std::string fName; - i64_byte_t fPrefixBytes[4]; - i64_hword_t fOpcode; - i64_hword_t fModReg; - i64_word_t fDisplacment; - i64_word_t fImmediate; -}; - -/// these two are edge cases -#define kAsmIntOpcode 0xCC -#define kasmIntOpcodeAlt 0xCD - -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 -#define kJumpLimitStandardLimit 0xEB - -inline std::vector kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF)}; - -#define kAsmRegisterLimit 15 diff --git a/Common/AsmKit/CPU/ppc.hpp b/Common/AsmKit/CPU/ppc.hpp deleted file mode 100644 index c4265da..0000000 --- a/Common/AsmKit/CPU/ppc.hpp +++ /dev/null @@ -1,1919 +0,0 @@ -#pragma once - -#include - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -/* - * These defines are use in the cpus field of the instructions. If the field - * is zero it can execute on all cpus. The defines are or'ed together. This - * information is used to set the cpusubtype in the resulting object file. - */ -#define CPU601 0x1 -#define IMPL64 0x2 -#define OPTIONAL 0x4 -#define VMX 0x8 -#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ -#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ - -enum optype -{ - NONE, /* no operand */ - JBSR, /* jbsr pseudo op */ - PCREL, /* PC relative (branch offset) */ - BADDR, /* Branch address (sign extended absolute address) */ - D, /* 16 bit displacement */ - DS, /* 14 bit displacement (double word) */ - SI, /* signed 16 bit immediate */ - UI, /* unsigned 16 bit immediate */ - HI, /* high 16 bit immediate (with truncation) */ - GREG, /* general register */ - G0REG, /* general register r1-r31 or 0 */ - FREG, /* float register */ - VREG, /* vector register */ - SGREG, /* segment register */ - SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ - BCND, /* branch condition opcode */ - CRF, /* condition register field */ - CRFONLY, /* condition register field only no expression allowed */ - sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ - mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ - NUM, /* number */ - SNUM, /* signed number */ - NUM0, /* number (where 1< - -#define SizeType size_t - -#define VoidPtr void* -#define voidPtr VoidPtr - -#define UIntPtr uintptr_t - -#define Int64 int64_t -#define UInt64 uint64_t - -#define Int32 int -#define UInt32 unsigned - -#define Bool bool - -#define Int16 int16_t -#define UInt16 uint16_t - -#define Int8 int8_t -#define UInt8 uint8_t - -#define CharType char -#define Boolean bool - -#include -#include -#include - -#define nullPtr std::nullptr_t - -#define MUST_PASS(E) assert(E) - -#ifndef __FORCE_STRLEN -#define __FORCE_STRLEN 1 - -#define string_length(len) strlen(len) -#endif - -#ifndef __FORCE_MEMCPY -#define __FORCE_MEMCPY 1 - -#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) -#endif - -#define MPCC_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define MPCC_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define MPCC_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define MPCC_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#include -#include -#include -#include - -namespace CompilerKit -{ - inline constexpr int BASE_YEAR = 1900; - - inline std::string current_date() noexcept - { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); - - return fmt; - } - - inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept - { - if (limit == 0) - return false; - - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; - - while (limit != 1) - { - ret = ret % 10; - str[cnt] = ret; - - ++cnt; - --limit; - --ret; - } - - str[copy_limit] = '\0'; - return true; - } -} // namespace CompilerKit - -#define PACKED __attribute__((packed)) - -typedef char char_type; - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { \ - ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ - } - -#ifdef __MODULE_NEED__ -#define MPCC_MODULE(name) int name(int argc, char** argv) -#else -#define MPCC_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __MODULE_NEED__ */ - -#pragma scalar_storage_order big - endian - -#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Common/ParserKit.hpp b/Common/ParserKit.hpp deleted file mode 100644 index 6e15c75..0000000 --- a/Common/ParserKit.hpp +++ /dev/null @@ -1,171 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include -#include - -namespace ParserKit -{ - using namespace CompilerKit; - - /// @brief Compiler backend, implements a frontend, such as C, C++... - /// See Toolchain, for some examples. - class CompilerBackend - { - public: - explicit CompilerBackend() = default; - virtual ~CompilerBackend() = default; - - MPCC_COPY_DEFAULT(CompilerBackend); - - // NOTE: cast this to your user defined ast. - typedef void* AstType; - - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - - virtual bool Compile(const std::string& text, const char* file) = 0; - - //! @brief What language are we dealing with? - virtual const char* Language() - { - return "Invalid Language"; - } - }; - - struct SyntaxLeafList; - struct SyntaxLeafList; - struct CompilerKeyword; - - /// we want to do that because to separate keywords. - enum KeywordKind - { - eKeywordKindNamespace, - eKeywordKindFunctionStart, - eKeywordKindFunctionEnd, - eKeywordKindVariable, - eKeywordKindType, - eKeywordKindExpressionBegin, - eKeywordKindExpressionEnd, - eKeywordKindArgSeparator, - eKeywordKindBodyStart, - eKeywordKindBodyEnd, - eKeywordKindClass, - eKeywordKindPtrAccess, - eKeywordKindAccess, - eKeywordKindIf, - eKeywordKindElse, - eKeywordKindElseIf, - eKeywordKindVariableAssign, - eKeywordKindVariableDec, - eKeywordKindVariableInc, - eKeywordKindConstant, - eKeywordKindTypedef, - eKeywordKindEndInstr, - eKeywordKindSpecifier, - eKeywordKindInvalid, - eKeywordKindReturn, - eKeywordKindCommentInline, - eKeywordKindCommentMultiLineStart, - eKeywordKindCommentMultiLineEnd, - eKeywordKindEq, - eKeywordKindNotEq, - eKeywordKindGreaterEq, - eKeywordKindLessEq, - eKeywordKindPtr, - }; - - /// \brief Compiler keyword information struct. - struct CompilerKeyword - { - std::string keyword_name; - KeywordKind keyword_kind = eKeywordKindInvalid; - }; - struct SyntaxLeafList final - { - struct SyntaxLeaf final - { - Int32 fUserType; -#ifdef __PK_USE_STRUCT_INSTEAD__ - CompilerKeyword fUserData; -#else - std::string fUserData; -#endif - - std::string fUserValue; - struct SyntaxLeaf* fNext; - }; - - std::vector fLeafList; - SizeType fNumLeafs; - - size_t SizeOf() - { - return fNumLeafs; - } - std::vector& Get() - { - return fLeafList; - } - SyntaxLeaf& At(size_t index) - { - return fLeafList[index]; - } - }; - - /// find the perfect matching word in a haystack. - /// \param haystack base string - /// \param needle the string we search for. - /// \return if we found it or not. - inline bool find_word(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) - return true; - - if (index < 0 || index >= haystack.size()) - return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); - } - - /// find a word within strict conditions and returns a range of it. - /// \param haystack - /// \param needle - /// \return position of needle. - inline std::size_t find_word_range(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) - { - return index; - } - - return false; - } -} // namespace ParserKit diff --git a/Common/Public/SDK/CRT/__mpcc_alloca.hxx b/Common/Public/SDK/CRT/__mpcc_alloca.hxx deleted file mode 100644 index a1c638e..0000000 --- a/Common/Public/SDK/CRT/__mpcc_alloca.hxx +++ /dev/null @@ -1,15 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -typedef void* ptr_type; -typedef __SIZE_TYPE__ size_type; - -inline void* __mpcc_alloca_gcc(size_type sz) -{ - return __builtin_alloca(sz); -} diff --git a/Common/Public/SDK/CRT/__mpcc_defines.hxx b/Common/Public/SDK/CRT/__mpcc_defines.hxx deleted file mode 100644 index 5560410..0000000 --- a/Common/Public/SDK/CRT/__mpcc_defines.hxx +++ /dev/null @@ -1,89 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#ifndef __MPCC_DEF__ -#define __MPCC_DEF__ - -#ifndef __GNUC__ - -typedef __SIZE_TYPE__ size_t; - -#ifdef __LP64__ -typedef long int ssize_t; -#else -typedef int ssize_t; -#endif // __LP64__ - -typedef size_t ptrdiff_t; -typedef size_t uintptr_t; -typedef void* voidptr_t; -typedef void* any_t; -typedef char* caddr_t; - -#ifndef NULL -#define NULL ((voidptr_t)0) -#endif // !null - -#ifdef __GNUC__ -#include -#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) -#elif defined(__MPCC__) - -#define __alloca(sz) __mpcc_alloca(sz) -#endif - -#define __deref(ptr) (*(ptr)) - -#ifdef __cplusplus -#define __init_decl() \ - extern "C" \ - { -#define __fini_decl() \ - } \ - ; -#else -#define __init_decl() -#define __fini_decl() -#endif - -#if __has_builtin(__builtin_alloca) -#define alloca(sz) __builtin_alloca(sz) -#ifdef __alloca -#undef __alloca -#endif -#define __alloca alloca -#else -#warning alloca not detected (MPCC) -#endif - -typedef long long off_t; -typedef unsigned long long uoff_t; - -typedef union float_cast { - struct - { - unsigned int mantissa : 23; - unsigned int exponent : 8; - unsigned int sign : 1; - }; - - float f; -} __attribute__((packed)) float_cast_t; - -typedef union double_cast { - struct - { - unsigned long long int mantissa : 52; - unsigned int exponent : 11; - unsigned int sign : 1; - }; - - double f; -} __attribute__((packed)) double_cast_t; - -#endif // ifndef __GNUC__ - -#endif /* __MPCC_DEF__ */ diff --git a/Common/Public/SDK/CRT/__mpcc_exception.hxx b/Common/Public/SDK/CRT/__mpcc_exception.hxx deleted file mode 100644 index 9366102..0000000 --- a/Common/Public/SDK/CRT/__mpcc_exception.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -/// This file is an implementation of __throw* family of functions. - -#include -#include -#include - -namespace std -{ - inline void __throw_general(void) - { - throw std::runtime_error("MPCC C++ Runtime error."); - } - - inline void __throw_domain_error(const char* error) - { - std::cout << "MPCC C++: Domain error: " << error << "\r"; - __throw_general(); - } -} // namespace std diff --git a/Common/Public/SDK/CRT/__mpcc_hint.hxx b/Common/Public/SDK/CRT/__mpcc_hint.hxx deleted file mode 100644 index ee14711..0000000 --- a/Common/Public/SDK/CRT/__mpcc_hint.hxx +++ /dev/null @@ -1,20 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#pragma compiler(hint_manifest) - -#define _Input -#define _Output - -#define _Optional - -#define _StrictCheckInput -#define _StrictCheckOutput - -#define _InOut -#define _StrictInOut diff --git a/Common/Public/SDK/CRT/__mpcc_malloc.hxx b/Common/Public/SDK/CRT/__mpcc_malloc.hxx deleted file mode 100644 index 2731868..0000000 --- a/Common/Public/SDK/CRT/__mpcc_malloc.hxx +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -namespace stdx -{ - /// @brief allocate a new class. - /// @tparam KindClass the class type to allocate. - template - inline void* allocate(Args&&... args) - { - return new KindClass(std::forward(args)...); - } - - /// @brief free a class. - /// @tparam KindClass the class type to allocate. - template - inline void release(KindClass ptr) - { - if (!ptr) - return; - delete ptr; - } -} // namespace stdx diff --git a/Common/Public/SDK/CRT/__mpcc_power.inc b/Common/Public/SDK/CRT/__mpcc_power.inc deleted file mode 100644 index 9e4928c..0000000 --- a/Common/Public/SDK/CRT/__mpcc_power.inc +++ /dev/null @@ -1,35 +0,0 @@ -# Path: SDK/__mpcc_power.inc -# Language: MPCC POWER Assembly support for GNU. -# Build Date: 2024-6-4 - -%ifdef __CODETOOLS__ - -%def lda li -%def sta stw -%def ldw li - -%def r0 0 -%def r1 1 -%def r2 2 -%def r3 3 -%def r4 4 -%def r5 5 -%def r6 6 -%def r7 7 -%def r8 8 -%def r9 9 -%def r10 10 -%def r11 11 -%def r12 12 -%def r13 13 -%def r14 14 -%def r15 15 -%def r16 16 -%def r17 17 -%def r18 18 -%def r19 19 -%def r20 20 - -%endif - -%def nop mr 0, 0 diff --git a/Common/StdKit/AE.hpp b/Common/StdKit/AE.hpp deleted file mode 100644 index 9c4ac1a..0000000 --- a/Common/StdKit/AE.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ======================================================== - * - * MPCC - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen 64 -#define kAEPad 8 -#define kAEMagLen 2 -#define kAEInvalidOpcode 0x00 - -// Advanced Executable File Format for MetroLink. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system -// loader. - -namespace CompilerKit -{ - // @brief Advanced Executable Header - // One thing to keep in mind. - // This object format, is reloctable. - typedef struct AEHeader final - { - CharType fMagic[kAEMagLen]; - CharType fArch; - CharType fSubArch; - SizeType fCount; - CharType fSize; - SizeType fStartCode; - SizeType fCodeSize; - CharType fPad[kAEPad]; - } PACKED AEHeader, *AEHeaderPtr; - - // @brief Advanced Executable Record. - // Could be data, code or bss. - // fKind must be filled with PEF fields. - - typedef struct AERecordHeader final - { - CharType fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - CharType fPad[kAEPad]; - } PACKED AERecordHeader, *AERecordHeaderPtr; - - enum - { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, - }; -} // namespace CompilerKit - -// provide operator<< for AE - -std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils -{ - /** - * @brief AE Reader protocol - * - */ - class AEReadableProtocol final - { - public: - std::ifstream FP; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - MPCC_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) - { - if (!raw) - return nullptr; - - return this->_Read(raw, sz * sizeof(AERecordHeader)); - } - - private: - /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ - template - TypeClass* _Read(char* raw, std::size_t sz) - { - FP.read(raw, std::streamsize(sz)); - return reinterpret_cast(raw); - } - }; -} // namespace CompilerKit::Utils diff --git a/Common/StdKit/ELF.hpp b/Common/StdKit/ELF.hpp deleted file mode 100644 index 4f0d0ae..0000000 --- a/Common/StdKit/ELF.hpp +++ /dev/null @@ -1,389 +0,0 @@ -#pragma once - -#include -#include - -struct file; - -#ifndef elf_read_implies_exec -/* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif - -/* 32-bit ELF base types. */ -typedef uint32_t Elf32_Addr; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Word; - -/* 64-bit ELF base types. */ -typedef uintptr_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef int16_t Elf64_SHalf; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* These constants are for the segment types stored in the image headers */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff -#define PT_GNU_EH_FRAME 0x6474e550 - -#define PT_GNU_STACK (PT_LOOS + 0x474e551) - -/* These constants define the different elf file types */ -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 -#define ET_LOPROC 0xff00 -#define ET_HIPROC 0xffff - -/* This is the info that is needed to parse the dynamic section of the file */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_ENCODING 32 -#define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 -#define DT_VALRNGLO 0x6ffffd00 -#define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff - -/* This info is needed when parsing the symbol table */ -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 - -#define ELF_ST_BIND(x) ((x) >> 4) -#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_BIND(x) ELF_ST_BIND(x) -#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) -#define ELF64_ST_BIND(x) ELF_ST_BIND(x) -#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) - -typedef struct dynamic -{ - Elf32_Sword d_tag; - union { - Elf32_Sword d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* entry tag value */ - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - -/* The following are used with relocations */ -#define ELF32_R_SYM(x) ((x) >> 8) -#define ELF32_R_TYPE(x) ((x)&0xff) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i)&0xffffffff) - -typedef struct elf32_rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct elf64_rel -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ -} Elf64_Rel; - -typedef struct elf32_rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct elf64_rela -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ - Elf64_Sxword r_addend; /* Constant addend used to compute value */ -} Elf64_Rela; - -typedef struct elf32_sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct elf64_sym -{ - Elf64_Word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - Elf64_Half st_shndx; /* Associated section index */ - Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Xword st_size; /* Associated symbol size */ -} Elf64_Sym; - -#define EI_NIDENT 16 - -typedef struct elf32_hdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; /* Entry point */ - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Ehdr; - -typedef struct elf64_hdr -{ - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* These constants define the permissions on sections in the program - header, p_flags. */ -#define PF_R 0x4 -#define PF_W 0x2 -#define PF_X 0x1 - -typedef struct elf32_phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -typedef struct elf64_phdr -{ - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment, file & memory */ -} Elf64_Phdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_NUM 12 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xffffffff - -/* sh_flags */ -#define SHF_WRITE 0x1 -#define SHF_ALLOC 0x2 -#define SHF_EXECINSTR 0x4 -#define SHF_MASKPROC 0xf0000000 - -/* special section indexes */ -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_LOPROC 0xff00 -#define SHN_HIPROC 0xff1f -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_HIRESERVE 0xffff - -typedef struct -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; - -typedef struct elf64_shdr -{ - Elf64_Word sh_name; /* Section name, index in string tbl */ - Elf64_Word sh_type; /* Type of section */ - Elf64_Xword sh_flags; /* Miscellaneous section attributes */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Size of section in bytes */ - Elf64_Word sh_link; /* Index of another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -#define EI_MAG0 0 /* e_ident[] indexes */ -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_PAD 8 - -#define ELFMAG0 0x7f /* EI_MAG */ -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define ELFCLASSNONE 0 /* EI_CLASS */ -#define ELFCLASS32 1 -#define ELFCLASS64 2 -#define ELFCLASSNUM 3 - -#define ELFDATANONE 0 /* e_ident[EI_DATA] */ -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_NONE 0 /* e_version, EI_VERSION */ -#define EV_CURRENT 1 -#define EV_NUM 2 - -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 - -#ifndef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE -#endif - -/* Notes used in ET_CORE */ -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ -#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* POWER VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ - -/* Note header in a PT_NOTE section */ -typedef struct elf32_note -{ - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ -} Elf32_Nhdr; - -/* Note header in a PT_NOTE section */ -typedef struct elf64_note -{ - Elf64_Word n_namesz; /* Name size */ - Elf64_Word n_descsz; /* Content size */ - Elf64_Word n_type; /* Content type */ -} Elf64_Nhdr; diff --git a/Common/StdKit/ErrorID.hpp b/Common/StdKit/ErrorID.hpp deleted file mode 100644 index 9f12ab2..0000000 --- a/Common/StdKit/ErrorID.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -#define MPCC_EXEC_ERROR -30 -#define MPCC_FILE_NOT_FOUND -31 -#define MPCC_DIR_NOT_FOUND -32 -#define MPCC_FILE_EXISTS -33 -#define MPCC_TOO_LONG -34 -#define MPCC_INVALID_DATA -35 -#define MPCC_UNIMPLEMENTED -36 -#define MPCC_FAT_ERROR -37 diff --git a/Common/StdKit/ErrorOr.hpp b/Common/StdKit/ErrorOr.hpp deleted file mode 100644 index cf35b26..0000000 --- a/Common/StdKit/ErrorOr.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - using ErrorT = UInt32; - - template - class ErrorOr final - { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(Int32 err) - : mId(err) - { - } - - explicit ErrorOr(nullPtr Null) - { - } - - explicit ErrorOr(T Class) - : mRef(Class) - { - } - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref Leak() - { - return mRef; - } - - operator bool() - { - return mRef; - } - - private: - Ref mRef; - Int32 mId{0}; - }; - - using ErrorOrAny = ErrorOr; - -} // namespace CompilerKit diff --git a/Common/StdKit/PEF.hpp b/Common/StdKit/PEF.hpp deleted file mode 100644 index 9fcc554..0000000 --- a/Common/StdKit/PEF.hpp +++ /dev/null @@ -1,132 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - -------------------------------------------- */ - -#pragma once - -#include - -// @file PEF.hpp -// @brief Preferred Executable Format - -#define kPefMagic "Joy!" -#define kPefMagicFat "yoJ!" - -#define kPefExt ".exec" -#define kPefDylibExt ".lib" -#define kPefLibExt ".slib" -#define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" - -#define kPefMagicLen 5 - -#define kPefVersion 2 -#define kPefNameLen 255 - -#define kPefBaseOrigin (0x1000000) - -#define kPefStart "__ImageStart" - -namespace CompilerKit -{ - enum - { - kPefArchIntel86S = 100, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* 64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, - }; - - enum - { - kPefSubArchAMD, - kPefSubArchIntel, - kPefSubArchGeneric, - kPefSubArchIBM, - }; - - enum - { - kPefKindExec = 1, /* .exe */ - kPefKindSharedObject = 2, /* .lib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, - }; - - /* PEF container */ - typedef struct PEFContainer final - { - CharType Magic[kPefMagicLen]; - UInt32 Linker; - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - } PACKED PEFContainer; - - /* First PEFCommandHeader starts after PEFContainer */ - /* Last container is __exec_end */ - - /* PEF executable section and commands. */ - - typedef struct PEFCommandHeader final - { - CharType Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* file offset */ - SizeType Size; /* file size */ - } PACKED PEFCommandHeader; - - enum - { - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, - kPefInvalid = 0xFF, - }; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/Common/StdKit/Ref.hpp b/Common/StdKit/Ref.hpp deleted file mode 100644 index f4a11c0..0000000 --- a/Common/StdKit/Ref.hpp +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -namespace CompilerKit -{ - // @author SoftwareLabs - // @brief Reference class, refers to a pointer of data in static memory. - template - class Ref final - { - public: - explicit Ref() = default; - ~Ref() = default; - - public: - explicit Ref(T cls, const bool& strong = false) - : m_Class(cls), m_Strong(strong) - { - } - - Ref& operator=(T ref) - { - m_Class = ref; - return *this; - } - - public: - T operator->() const - { - return m_Class; - } - - T& Leak() - { - return m_Class; - } - - T operator*() - { - return m_Class; - } - - bool IsStrong() const - { - return m_Strong; - } - - operator bool() - { - return m_Class; - } - - private: - T m_Class; - bool m_Strong{false}; - }; - - template - class NonNullRef final - { - public: - NonNullRef() = delete; - NonNullRef(nullPtr) = delete; - - explicit NonNullRef(T* ref) - : m_Ref(ref, true) - { - } - - Ref& operator->() - { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef& ref) = delete; - NonNullRef(const NonNullRef& ref) = default; - - private: - Ref m_Ref{nullptr}; - }; -} // namespace CompilerKit diff --git a/Common/StdKit/String.hpp b/Common/StdKit/String.hpp deleted file mode 100644 index a05a31c..0000000 --- a/Common/StdKit/String.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright SoftwareLabs, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - - class StringView final - { - public: - explicit StringView() = delete; - - explicit StringView(SizeType Sz) noexcept - : m_Sz(Sz) - { - m_Data = new char[Sz]; - assert(m_Data); - } - - ~StringView() noexcept - { - if (m_Data) - { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - MPCC_COPY_DEFAULT(StringView); - - CharType* Data(); - const CharType* CData() const; - SizeType Length() const; - - bool operator==(const CharType* rhs) const; - bool operator!=(const CharType* rhs) const; - - bool operator==(const StringView& rhs) const; - bool operator!=(const StringView& rhs) const; - - StringView& operator+=(const CharType* rhs); - StringView& operator+=(const StringView& rhs); - - operator bool() - { - return m_Data && m_Data[0] != 0; - } - - bool operator!() - { - return !m_Data || m_Data[0] == 0; - } - - private: - char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; - }; - - /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ - struct StringBuilder final - { - static StringView Construct(const CharType* data); - static const char* FromInt(const char* fmt, int n); - static const char* FromBool(const char* fmt, bool n); - static const char* Format(const char* fmt, const char* from); - static bool Equals(const char* lhs, const char* rhs); - }; -} // namespace CompilerKit diff --git a/Common/StdKit/XCOFF.hxx b/Common/StdKit/XCOFF.hxx deleted file mode 100644 index a26b591..0000000 --- a/Common/StdKit/XCOFF.hxx +++ /dev/null @@ -1,41 +0,0 @@ -/* ------------------------------------------- - - Copyright SoftwareLabs - - File: XCOFF.hpp - Purpose: XCOFF for NewOS. - - Revision History: - - 04/07/24: Added file (amlel) - -------------------------------------------- */ - -#ifndef __XCOFF__ -#define __XCOFF__ - -#include - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit -{ - /// @brief XCoff identification header. - typedef struct XCoffFileHeader - { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header - } XCoffFileHeader; -} // namespace CompilerKit - -#endif // ifndef __XCOFF__ \ No newline at end of file diff --git a/Common/UUID.hpp b/Common/UUID.hpp deleted file mode 100644 index 00b153b..0000000 --- a/Common/UUID.hpp +++ /dev/null @@ -1,983 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus - -#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define LIBUUID_CPP20_OR_GREATER -#endif - -#endif - -#ifdef LIBUUID_CPP20_OR_GREATER -#include -#else -#include -#endif - -#ifdef _WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#ifdef UUID_TIME_GENERATOR -#include -#pragma comment(lib, "IPHLPAPI.lib") -#endif - -#elif defined(__linux__) || defined(__unix__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#elif defined(__APPLE__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#endif - -namespace uuids -{ -#ifdef __cpp_lib_span - template - using span = std::span; -#else - template - using span = gsl::span; -#endif - - namespace detail - { - template - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept - { - if (ch >= static_cast('0') && ch <= static_cast('9')) - return static_cast(ch - static_cast('0')); - if (ch >= static_cast('a') && ch <= static_cast('f')) - return static_cast(10 + ch - static_cast('a')); - if (ch >= static_cast('A') && ch <= static_cast('F')) - return static_cast(10 + ch - static_cast('A')); - return 0; - } - - template - [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast('0') && ch <= static_cast('9')) || - (ch >= static_cast('a') && ch <= static_cast('f')) || - (ch >= static_cast('A') && ch <= static_cast('F')); - } - - template - [[nodiscard]] constexpr std::basic_string_view to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template - [[nodiscard]] constexpr std::basic_string_view - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast(start); - const uint8_t* finish = static_cast(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast((bitCount >> 24) & 0xFF)); - process_byte(static_cast((bitCount >> 16) & 0xFF)); - process_byte(static_cast((bitCount >> 8) & 0xFF)); - process_byte(static_cast((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast(d32[0] >> 24); - digest[di++] = static_cast(d32[0] >> 16); - digest[di++] = static_cast(d32[0] >> 8); - digest[di++] = static_cast(d32[0] >> 0); - - digest[di++] = static_cast(d32[1] >> 24); - digest[di++] = static_cast(d32[1] >> 16); - digest[di++] = static_cast(d32[1] >> 8); - digest[di++] = static_cast(d32[1] >> 0); - - digest[di++] = static_cast(d32[2] >> 24); - digest[di++] = static_cast(d32[2] >> 16); - digest[di++] = static_cast(d32[2] >> 8); - digest[di++] = static_cast(d32[2] >> 0); - - digest[di++] = static_cast(d32[3] >> 24); - digest[di++] = static_cast(d32[3] >> 16); - digest[di++] = static_cast(d32[3] >> 8); - digest[di++] = static_cast(d32[3] >> 0); - - digest[di++] = static_cast(d32[4] >> 24); - digest[di++] = static_cast(d32[4] >> 16); - digest[di++] = static_cast(d32[4] >> 8); - digest[di++] = static_cast(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast(m_block[i * 4 + 0] << 24); - w[i] |= static_cast(m_block[i * 4 + 1] << 16); - w[i] |= static_cast(m_block[i * 4 + 2] << 8); - w[i] |= static_cast(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid[37] = - L"00000000-0000-0000-0000-000000000000"; - - template - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; - } // namespace detail - - // -------------------------------------------------------------------------------------------------------------------------- - // UUID format https://tools.ietf.org/html/rfc4122 - // -------------------------------------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------------------------------------- - // Field NDR Data Type Octet # Note - // -------------------------------------------------------------------------------------------------------------------------- - // time_low unsigned long 0 - 3 The low field - // of the timestamp. time_mid unsigned short 4 - 5 - // The middle field of the timestamp. time_hi_and_version unsigned - // short 6 - 7 The high field of the timestamp multiplexed - // with the version number. clock_seq_hi_and_reserved unsigned small 8 - // The high field of the clock sequence multiplexed with the variant. - // clock_seq_low unsigned small 9 The low - // field of the clock sequence. node character 10 - // - 15 The spatially unique node identifier. - // -------------------------------------------------------------------------------------------------------------------------- - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_low | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_mid | time_hi_and_version | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |clk_seq_hi_res | clk_seq_low | node (0-1) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | node (2-5) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // -------------------------------------------------------------------------------------------------------------------------- - // enumerations - // -------------------------------------------------------------------------------------------------------------------------- - - // indicated by a bit pattern in octet 8, marked with N in - // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx - enum class uuid_variant - { - // NCS backward compatibility (with the obsolete Apollo Network Computing - // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the - // UUID are a 48-bit timestamp (the number of 4 microsecond units of time - // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet - // is the "address family"; > the final 7 octets are a 56-bit host ID in the - // form specified by the address family - ncs, - - // RFC 4122/DCE 1.1 - // N bit pattern: 10xx - // > big-endian byte order - rfc, - - // Microsoft Corporation backward compatibility - // N bit pattern: 110x - // > little endian byte order - // > formely used in the Component Object Model (COM) library - microsoft, - - // reserved for possible future definition - // N bit pattern: 111x - reserved - }; - - // indicated by a bit pattern in octet 6, marked with M in - // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx - enum class uuid_version - { - none = 0, // only possible for nil or invalid uuids - time_based = 1, // The time-based version specified in RFC 4122 - dce_security = 2, // DCE Security version, with embedded POSIX UIDs. - name_based_md5 = - 3, // The name-based version specified in RFS 4122 with MD5 hashing - random_number_based = 4, // The randomly or pseudo-randomly generated version - // specified in RFS 4122 - name_based_sha1 = - 5 // The name-based version specified in RFS 4122 with SHA1 hashing - }; - - // Forward declare uuid & to_string so that we can declare to_string as a friend - // later. - class uuid; - template , class Allocator = std::allocator> - std::basic_string to_string(uuid const& id); - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid class - // -------------------------------------------------------------------------------------------------------------------------- - class uuid - { - public: - using value_type = uint8_t; - - constexpr uuid() noexcept = default; - - uuid(value_type (&arr)[16]) noexcept - { - std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); - } - - constexpr uuid(std::array const& arr) noexcept - : data{arr} - { - } - - explicit uuid(span bytes) - { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template - explicit uuid(ForwardIterator first, ForwardIterator last) - { - if (std::distance(first, last) == 16) - std::copy(first, last, std::begin(data)); - } - - [[nodiscard]] constexpr uuid_variant variant() const noexcept - { - if ((data[8] & 0x80) == 0x00) - return uuid_variant::ncs; - else if ((data[8] & 0xC0) == 0x80) - return uuid_variant::rfc; - else if ((data[8] & 0xE0) == 0xC0) - return uuid_variant::microsoft; - else - return uuid_variant::reserved; - } - - [[nodiscard]] constexpr uuid_version version() const noexcept - { - if ((data[6] & 0xF0) == 0x10) - return uuid_version::time_based; - else if ((data[6] & 0xF0) == 0x20) - return uuid_version::dce_security; - else if ((data[6] & 0xF0) == 0x30) - return uuid_version::name_based_md5; - else if ((data[6] & 0xF0) == 0x40) - return uuid_version::random_number_based; - else if ((data[6] & 0xF0) == 0x50) - return uuid_version::name_based_sha1; - else - return uuid_version::none; - } - - [[nodiscard]] constexpr bool is_nil() const noexcept - { - for (size_t i = 0; i < data.size(); ++i) - if (data[i] != 0) - return false; - return true; - } - - void swap(uuid& other) noexcept - { - data.swap(other.data); - } - - [[nodiscard]] inline span as_bytes() const - { - return span( - reinterpret_cast(data.data()), 16); - } - - template - [[nodiscard]] constexpr static bool is_valid_uuid( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) - return false; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template - [[nodiscard]] constexpr static std::optional from_string( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - std::array data{{0}}; - - if (str.empty()) - return {}; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return {}; - } - - if (firstDigit) - { - data[index] = static_cast(detail::hex2char(str[i]) << 4); - firstDigit = false; - } - else - { - data[index] = - static_cast(data[index] | detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return {}; - } - - return uuid{data}; - } - - private: - std::array data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template - friend std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id); - - template - friend std::basic_string to_string(uuid const& id); - - friend std::hash; - }; - - // -------------------------------------------------------------------------------------------------------------------------- - // operators and non-member functions - // -------------------------------------------------------------------------------------------------------------------------- - - [[nodiscard]] inline bool operator==(uuid const& lhs, - uuid const& rhs) noexcept - { - return lhs.data == rhs.data; - } - - [[nodiscard]] inline bool operator!=(uuid const& lhs, - uuid const& rhs) noexcept - { - return !(lhs == rhs); - } - - [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept - { - return lhs.data < rhs.data; - } - - template - [[nodiscard]] inline std::basic_string to_string( - uuid const& id) - { - std::basic_string uustr{detail::empty_guid}; - - for (size_t i = 0, index = 0; i < 36; ++i) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - continue; - } - uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; - uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; - index++; - } - - return uustr; - } - - template - std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id) - { - s << to_string(id); - return s; - } - - inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept - { - lhs.swap(rhs); - } - - // -------------------------------------------------------------------------------------------------------------------------- - // namespace IDs that could be used for generating name-based uuids - // -------------------------------------------------------------------------------------------------------------------------- - - // Name string is a fully-qualified domain name - static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is a URL - static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an ISO OID (See https://oidref.com/, - // https://en.wikipedia.org/wiki/Object_identifier) - static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an X.500 DN, in DER or a text output format (See - // https://en.wikipedia.org/wiki/X.500, - // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) - static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid generators - // -------------------------------------------------------------------------------------------------------------------------- - -#ifdef UUID_SYSTEM_GENERATOR - class uuid_system_generator - { - public: - using result_type = uuid; - - uuid operator()() - { -#ifdef _WIN32 - - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); - - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } - - std::array bytes = { - {static_cast((newId.Data1 >> 24) & 0xFF), - static_cast((newId.Data1 >> 16) & 0xFF), - static_cast((newId.Data1 >> 8) & 0xFF), - static_cast((newId.Data1) & 0xFF), - - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), - - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), - - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__linux__) || defined(__unix__) - - uuid_t id; - uuid_generate(id); - - std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], - id[6], id[7], id[8], id[9], id[10], - id[11], id[12], id[13], id[14], id[15]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array arrbytes = { - {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, - bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, - bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, - bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; -#else - return uuid{}; -#endif - } - }; -#endif - - template - class basic_uuid_random_generator - { - public: - using engine_type = UniformRandomNumberGenerator; - - explicit basic_uuid_random_generator(engine_type& gen) - : generator(&gen, [](auto) {}) - { - } - explicit basic_uuid_random_generator(engine_type* gen) - : generator(gen, [](auto) {}) - { - } - - [[nodiscard]] uuid operator()() - { - alignas(uint32_t) uint8_t bytes[16]; - for (int i = 0; i < 16; i += 4) - *reinterpret_cast(bytes + i) = distribution(*generator); - - // variant must be 10xxxxxx - bytes[8] &= 0xBF; - bytes[8] |= 0x80; - - // version must be 0100xxxx - bytes[6] &= 0x4F; - bytes[6] |= 0x40; - - return uuid{std::begin(bytes), std::end(bytes)}; - } - - private: - std::uniform_int_distribution distribution; - std::shared_ptr generator; - }; - - using uuid_random_generator = basic_uuid_random_generator; - - class uuid_name_generator - { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept - : nsuuid(namespace_uuid) - { - } - - template - [[nodiscard]] uuid operator()(StringType const& name) - { - reset(); - process_characters(detail::to_string_view(name)); - return make_uuid(); - } - - private: - void reset() - { - hasher.reset(); - std::byte bytes[16]; - auto nsbytes = nsuuid.as_bytes(); - std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); - hasher.process_bytes(bytes, 16); - } - - template - void process_characters(std::basic_string_view const str) - { - for (uint32_t c : str) - { - hasher.process_byte(static_cast(c & 0xFF)); - if constexpr (!std::is_same_v) - { - hasher.process_byte(static_cast((c >> 8) & 0xFF)); - hasher.process_byte(static_cast((c >> 16) & 0xFF)); - hasher.process_byte(static_cast((c >> 24) & 0xFF)); - } - } - } - - [[nodiscard]] uuid make_uuid() - { - detail::sha1::digest8_t digest; - hasher.get_digest_bytes(digest); - - // variant must be 0b10xxxxxx - digest[8] &= 0xBF; - digest[8] |= 0x80; - - // version must be 0b0101xxxx - digest[6] &= 0x5F; - digest[6] |= 0x50; - - return uuid{digest, digest + 16}; - } - - private: - uuid nsuuid; - detail::sha1 hasher; - }; - -#ifdef UUID_TIME_GENERATOR - // !!! DO NOT USE THIS IN PRODUCTION - // this implementation is unreliable for good uuids - class uuid_time_generator - { - using mac_address = std::array; - - std::optional device_address; - - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } - -#ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) - return false; - std::vector buf(len); - auto pips = reinterpret_cast(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) - return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; -#endif - - return device_address.has_value(); - } - - [[nodiscard]] long long get_time_intervals() - { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = - std::chrono::duration_cast(diff).count(); - return ns / 100; - } - - [[nodiscard]] static unsigned short get_clock_sequence() - { - static std::mt19937 clock_gen(std::random_device{}()); - static std::uniform_int_distribution clock_dis; - static std::atomic_ushort clock_sequence = clock_dis(clock_gen); - return clock_sequence++; - } - - public: - [[nodiscard]] uuid operator()() - { - if (get_mac_address()) - { - std::array data; - - auto tm = get_time_intervals(); - - auto clock_seq = get_clock_sequence(); - - auto ptm = reinterpret_cast(&tm); - - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); - - memcpy(&data[8], &clock_seq, 2); - - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; - - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; - - memcpy(&data[10], &device_address.value()[0], 6); - - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } - - return {}; - } - }; -#endif -} // namespace uuids - -namespace std -{ - template <> - struct hash - { - using argument_type = uuids::uuid; - using result_type = std::size_t; - - [[nodiscard]] result_type operator()(argument_type const& uuid) const - { -#ifdef UUID_HASH_STRING_BASED - std::hash hasher; - return static_cast(hasher(uuids::to_string(uuid))); -#else - uint64_t l = static_cast(uuid.data[0]) << 56 | - static_cast(uuid.data[1]) << 48 | - static_cast(uuid.data[2]) << 40 | - static_cast(uuid.data[3]) << 32 | - static_cast(uuid.data[4]) << 24 | - static_cast(uuid.data[5]) << 16 | - static_cast(uuid.data[6]) << 8 | - static_cast(uuid.data[7]); - uint64_t h = static_cast(uuid.data[8]) << 56 | - static_cast(uuid.data[9]) << 48 | - static_cast(uuid.data[10]) << 40 | - static_cast(uuid.data[11]) << 32 | - static_cast(uuid.data[12]) << 24 | - static_cast(uuid.data[13]) << 16 | - static_cast(uuid.data[14]) << 8 | - static_cast(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) - { - return result_type(l ^ h); - } - else - { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } -#endif - } - }; -} // namespace std - -#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Common/Version.hxx b/Common/Version.hxx deleted file mode 100644 index 377a688..0000000 --- a/Common/Version.hxx +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define kDistVersion "v1.20" diff --git a/Doc/Inside 64x0.pdf b/Doc/Inside 64x0.pdf new file mode 100644 index 0000000..bcd6782 Binary files /dev/null and b/Doc/Inside 64x0.pdf differ diff --git a/Doc/asm-specs.txt b/Doc/asm-specs.txt new file mode 100644 index 0000000..a0c42bf --- /dev/null +++ b/Doc/asm-specs.txt @@ -0,0 +1,11 @@ +==================== +X86 ASSEMBLER SPECS +==================== + +WHAT TO DO: + Provide a complete support of x86-64 with: + + - org directive. + - 64-bit and 32-bit registers. + - basic instructions (load, store, jump to) + - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Doc/havp.txt b/Doc/havp.txt new file mode 100644 index 0000000..12fcec5 --- /dev/null +++ b/Doc/havp.txt @@ -0,0 +1,13 @@ +HAVP - Harvard Audio/Video Processor + +- Encoding: IBAD + +- Data path = 24 + - 16: sound data + - 8: information data + +- Register size: 32 +- Store strategy: shift registers. +- Standard registers: [ r0, r9 ] +- Floating point registers: [ f0, f2 ] +- Builtin SRAM: 512kb diff --git a/Doc/notice.txt b/Doc/notice.txt new file mode 100644 index 0000000..23691da --- /dev/null +++ b/Doc/notice.txt @@ -0,0 +1,4 @@ +The X64000 draft papers +They contain thing that might appear through the next iteration of 64k. + +Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Doc/vnrp.txt b/Doc/vnrp.txt new file mode 100644 index 0000000..e17b494 --- /dev/null +++ b/Doc/vnrp.txt @@ -0,0 +1,17 @@ +VNRP - Von Neumann, RISC Processor + +- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs + +- Data path = 128-bit (register data) +- Addressing = 58-bit physical address size. + +- Registers (128-bit) = r0, r19 +- Float/Vector registers (128-bit) = f0, f9 + +- Out of order (superscalar also added to the equation) = Yes +- Superscalar = Yes + +- L1 cache: 16kb (8 instr, 8 data) +- L2 cache: 1024kb (512 instr, 512 data) + +- Clock speed: 1 Ghz diff --git a/Sources/32asm.cc b/Sources/32asm.cc index 82d23e6..a3e2cbb 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -19,10 +19,10 @@ #define __ASM_NEED_32x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 6287b3e..baa6ef4 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -19,10 +19,10 @@ #define __ASM_NEED_64x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 36f56a8..75a9b10 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -10,9 +10,9 @@ /// BUGS: ? /// TODO: -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 1952f54..61399a4 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -4,8 +4,8 @@ ------------------------------------------- */ -#include -#include +#include +#include /** * @file AssemblyFactory.cxx diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index f6fdb41..240835e 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include using namespace CompilerKit; diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index 9ddd3a2..acadde2 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include #define kZero64Section ".zero64" #define kCode64Section ".code64" diff --git a/Sources/String.cc b/Sources/String.cc index 38bd444..ece3ecf 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -18,7 +18,7 @@ * */ -#include +#include #include namespace CompilerKit { diff --git a/Sources/bpp.cc b/Sources/bpp.cc index aa0b72a..f523597 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -9,8 +9,8 @@ /// BUGS: 0 -#include -#include +#include +#include #include #include #include diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 349d543..2986375 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 97b6a82..9323d31 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -16,8 +16,8 @@ #define kSplashCxx() \ kPrintF(kWhite "%s\n", "SoftwareLabs C++ Compiler, Copyright SoftwareLabs.") -#include -#include +#include +#include #include #include #include diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index a451a0a..ada2830 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 391c63f..26269f4 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -27,10 +27,10 @@ #define kAssemblerPragmaSymStr "#" #define kAssemblerPragmaSym '#' -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/link.cc b/Sources/link.cc index e0a49cf..6ed2db5 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -13,23 +13,23 @@ /// note: Do not look up for anything with .code64/.data64/.zero64! /// It will be loaded when program will start up! -#include +#include //! Assembler Kit -#include +#include //! Preferred Executable Format -#include -#include +#include +#include #include #include #include //! Dist version -#include +#include //! Advanced Executable Object Format -#include +#include //! C++ I/O headers. #include diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index ad99611..d008296 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -7,9 +7,9 @@ * ======================================================== */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 89de014..1edeaaa 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -17,12 +17,12 @@ #define __ASM_NEED_PPC__ 1 -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include #include diff --git a/docs/Inside 64x0.pdf b/docs/Inside 64x0.pdf deleted file mode 100644 index bcd6782..0000000 Binary files a/docs/Inside 64x0.pdf and /dev/null differ diff --git a/docs/asm-specs.txt b/docs/asm-specs.txt deleted file mode 100644 index a0c42bf..0000000 --- a/docs/asm-specs.txt +++ /dev/null @@ -1,11 +0,0 @@ -==================== -X86 ASSEMBLER SPECS -==================== - -WHAT TO DO: - Provide a complete support of x86-64 with: - - - org directive. - - 64-bit and 32-bit registers. - - basic instructions (load, store, jump to) - - flushable into object-code and flat binary. \ No newline at end of file diff --git a/docs/havp.txt b/docs/havp.txt deleted file mode 100644 index 12fcec5..0000000 --- a/docs/havp.txt +++ /dev/null @@ -1,13 +0,0 @@ -HAVP - Harvard Audio/Video Processor - -- Encoding: IBAD - -- Data path = 24 - - 16: sound data - - 8: information data - -- Register size: 32 -- Store strategy: shift registers. -- Standard registers: [ r0, r9 ] -- Floating point registers: [ f0, f2 ] -- Builtin SRAM: 512kb diff --git a/docs/notice.txt b/docs/notice.txt deleted file mode 100644 index 23691da..0000000 --- a/docs/notice.txt +++ /dev/null @@ -1,4 +0,0 @@ -The X64000 draft papers -They contain thing that might appear through the next iteration of 64k. - -Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/docs/vnrp.txt b/docs/vnrp.txt deleted file mode 100644 index e17b494..0000000 --- a/docs/vnrp.txt +++ /dev/null @@ -1,17 +0,0 @@ -VNRP - Von Neumann, RISC Processor - -- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs - -- Data path = 128-bit (register data) -- Addressing = 58-bit physical address size. - -- Registers (128-bit) = r0, r19 -- Float/Vector registers (128-bit) = f0, f9 - -- Out of order (superscalar also added to the equation) = Yes -- Superscalar = Yes - -- L1 cache: 16kb (8 instr, 8 data) -- L2 cache: 1024kb (512 instr, 512 data) - -- Clock speed: 1 Ghz diff --git a/posix.make b/posix.make index 119457d..be1abb8 100644 --- a/posix.make +++ b/posix.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Common -I./ -I./Sources/Detail +COMMON_INC=-I./Comm -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 LINK_SRC=Sources/link.cc LINK_OUTPUT=Output/link.exec diff --git a/win64.make b/win64.make index 0315371..a345da0 100644 --- a/win64.make +++ b/win64.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Common -I./ -I./Sources/Detail +COMMON_INC=-I./Comm -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 -Xlinker -s LINK_SRC=Sources/link.cc LINK_OUTPUT=Output/link.exe -- cgit v1.2.3 From 9c02ac7a15d18da351baa81b25ebd8c967b4e5ee Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 11 Jun 2024 09:56:25 +0200 Subject: MHR-21: Update copyright holder. Signed-off-by: Amlal El Mahrouss --- Comm/AsmKit/AsmKit.hpp | 2 +- Comm/AsmKit/CPU/32x0.hpp | 2 +- Comm/AsmKit/CPU/64x0.hpp | 2 +- Comm/AsmKit/CPU/amd64.hpp | 2 +- Comm/CompilerKit.hpp | 2 +- Comm/Defines.hpp | 2 +- Comm/ParserKit.hpp | 2 +- Comm/Public/SDK/CRT/__mpcc_alloca.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_defines.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_exception.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_hint.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_malloc.hxx | 2 +- Comm/StdKit/AE.hpp | 2 +- Comm/StdKit/ErrorID.hpp | 2 +- Comm/StdKit/ErrorOr.hpp | 2 +- Comm/StdKit/PEF.hpp | 2 +- Comm/StdKit/Ref.hpp | 4 ++-- Comm/StdKit/String.hpp | 2 +- Comm/StdKit/XCOFF.hxx | 4 ++-- ReadMe.md | 2 +- Sources/32asm.cc | 4 ++-- Sources/64asm.cc | 6 +++--- Sources/64x0-cc.cc | 8 ++++---- Sources/AssemblyFactory.cc | 6 +++--- Sources/Detail/asmutils.hxx | 2 +- Sources/Detail/compilerutils.hxx | 2 +- Sources/String.cc | 4 ++-- Sources/bpp.cc | 8 ++++---- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 16 ++++++++-------- Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 10 +++++----- Sources/link.cc | 10 +++++----- Sources/power-cc.cc | 6 +++--- Sources/ppcasm.cc | 8 ++++---- posix.make | 10 +++++----- win64.make | 4 ++-- 37 files changed, 76 insertions(+), 76 deletions(-) (limited to 'Sources') diff --git a/Comm/AsmKit/AsmKit.hpp b/Comm/AsmKit/AsmKit.hpp index 1801130..6fbacfa 100644 --- a/Comm/AsmKit/AsmKit.hpp +++ b/Comm/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/32x0.hpp b/Comm/AsmKit/CPU/32x0.hpp index 0013752..e469dda 100644 --- a/Comm/AsmKit/CPU/32x0.hpp +++ b/Comm/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/64x0.hpp b/Comm/AsmKit/CPU/64x0.hpp index e2e03c8..10d12d8 100644 --- a/Comm/AsmKit/CPU/64x0.hpp +++ b/Comm/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/amd64.hpp b/Comm/AsmKit/CPU/amd64.hpp index d461574..63ed1b3 100644 --- a/Comm/AsmKit/CPU/amd64.hpp +++ b/Comm/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/CompilerKit.hpp b/Comm/CompilerKit.hpp index b9de089..25a1e66 100644 --- a/Comm/CompilerKit.hpp +++ b/Comm/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Defines.hpp b/Comm/Defines.hpp index d76620c..8c47bd0 100644 --- a/Comm/Defines.hpp +++ b/Comm/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/ParserKit.hpp b/Comm/ParserKit.hpp index 9109d32..8b66995 100644 --- a/Comm/ParserKit.hpp +++ b/Comm/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx index a1c638e..19ebaaf 100644 --- a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_defines.hxx b/Comm/Public/SDK/CRT/__mpcc_defines.hxx index 5560410..c05ee73 100644 --- a/Comm/Public/SDK/CRT/__mpcc_defines.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_exception.hxx b/Comm/Public/SDK/CRT/__mpcc_exception.hxx index 9366102..a2539eb 100644 --- a/Comm/Public/SDK/CRT/__mpcc_exception.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_hint.hxx b/Comm/Public/SDK/CRT/__mpcc_hint.hxx index ee14711..db58203 100644 --- a/Comm/Public/SDK/CRT/__mpcc_hint.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx index 2731868..db3075f 100644 --- a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/StdKit/AE.hpp b/Comm/StdKit/AE.hpp index 505ed77..d06a8ca 100644 --- a/Comm/StdKit/AE.hpp +++ b/Comm/StdKit/AE.hpp @@ -2,7 +2,7 @@ * ======================================================== * * MPCC - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/ErrorID.hpp b/Comm/StdKit/ErrorID.hpp index bea70ae..698b66b 100644 --- a/Comm/StdKit/ErrorID.hpp +++ b/Comm/StdKit/ErrorID.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/ErrorOr.hpp b/Comm/StdKit/ErrorOr.hpp index 0125f82..04f013d 100644 --- a/Comm/StdKit/ErrorOr.hpp +++ b/Comm/StdKit/ErrorOr.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/PEF.hpp b/Comm/StdKit/PEF.hpp index e790d6a..9198b30 100644 --- a/Comm/StdKit/PEF.hpp +++ b/Comm/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Comm/StdKit/Ref.hpp b/Comm/StdKit/Ref.hpp index f4a11c0..3ccb983 100644 --- a/Comm/StdKit/Ref.hpp +++ b/Comm/StdKit/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -12,7 +12,7 @@ namespace CompilerKit { - // @author SoftwareLabs + // @author Zeta Electronics Corporation // @brief Reference class, refers to a pointer of data in static memory. template class Ref final diff --git a/Comm/StdKit/String.hpp b/Comm/StdKit/String.hpp index c6589cc..e495219 100644 --- a/Comm/StdKit/String.hpp +++ b/Comm/StdKit/String.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/XCOFF.hxx b/Comm/StdKit/XCOFF.hxx index fee1888..7e57514 100644 --- a/Comm/StdKit/XCOFF.hxx +++ b/Comm/StdKit/XCOFF.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation File: XCOFF.hpp Purpose: XCOFF for NewOS. @@ -38,4 +38,4 @@ namespace CompilerKit } XCoffFileHeader; } // namespace CompilerKit -#endif // ifndef __XCOFF__ \ No newline at end of file +#endif // ifndef __XCOFF__ diff --git a/ReadMe.md b/ReadMe.md index ba91d98..a8650ee 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -13,4 +13,4 @@ make -f .make all ``` -##### Copyright SoftwareLabs, all rights reserved. +##### Copyright Zeta Electronics Corporation, all rights reserved. diff --git a/Sources/32asm.cc b/Sources/32asm.cc index a3e2cbb..0dd6f7c 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 32asm.cxx -// @author SoftwareLabs +// @author Zeta Electronics Corporation // @brief 32x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string diff --git a/Sources/64asm.cc b/Sources/64asm.cc index baa6ef4..859bfd4 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 64asm.cxx -// @author SoftwareLabs +// @author Zeta Electronics Corporation // @brief 64x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string @@ -110,7 +110,7 @@ MPCC_MODULE(NewOSAssembler64000) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 SoftwareLabs.\n"; + "2024 Zeta Electronics Corporation.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 75a9b10..b981cb8 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -27,9 +27,9 @@ /* C driver */ /* This is part of MPCC C SDK. */ -/* (c) SoftwareLabs */ +/* (c) Zeta Electronics Corporation */ -/// @author SoftwareLabs (amlel) +/// @author Zeta Electronics Corporation (amlel) /// @file 64x0-cc.cc /// @brief 64x0 C Compiler. @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) Zeta Electronics Corporation\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 61399a4..232fcc0 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ @@ -9,12 +9,12 @@ /** * @file AssemblyFactory.cxx - * @author SoftwareLabs (amlal@mahrouss.com) + * @author Zeta Electronics Corporation (amlal@mahrouss.com) * @brief Assembler Kit * @version 0.1 * @date 2024-01-27 * - * @copyright Copyright (c) 2024, SoftwareLabs + * @copyright Copyright (c) 2024, Zeta Electronics Corporation * */ diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index 240835e..c531126 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index acadde2..fdcf141 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Sources/String.cc b/Sources/String.cc index ece3ecf..5a8f3ed 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 SoftwareLabs + * @copyright Copyright (c) 2024 Zeta Electronics Corporation * */ diff --git a/Sources/bpp.cc b/Sources/bpp.cc index f523597..9dcd2d3 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -2,7 +2,7 @@ * ======================================================== * * bpp - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -19,7 +19,7 @@ #define kMacroPrefix '%' -// @author SoftwareLabs (amlel) +// @author Zeta Electronics Corporation (amlel) // @file bpp.cc // @brief C preprocessor. @@ -812,12 +812,12 @@ MPCC_MODULE(NewOSPreprocessor) { if (argv[index][0] == '-') { if (strcmp(argv[index], "-v") == 0) { - printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); + printf("%s\n", "bpp v1.11, (c) Zeta Electronics Corporation"); return 0; } if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) SoftwareLabs"); + printf("%s\n", "bpp v1.11, (c) Zeta Electronics Corporation"); printf("%s\n", "-working-dir : set directory to working path."); printf("%s\n", "-include-dir : add directory to include path."); printf("%s\n", "-def : def macro."); diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 2986375..7e1cc0e 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 9323d31..611507f 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -2,7 +2,7 @@ * ======================================================== * * cplusplus - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "SoftwareLabs C++ Compiler, Copyright SoftwareLabs.") + kPrintF(kWhite "%s\n", "Zeta Electronics Corporation C++ Compiler, Copyright Zeta Electronics Corporation.") #include #include @@ -29,11 +29,11 @@ #define kOk 0 -/* SoftwareLabs C++ driver */ +/* Zeta Electronics Corporation C++ driver */ /* This is part of MPCC C++ compiler. */ -/* (c) SoftwareLabs */ +/* (c) Zeta Electronics Corporation */ -/// @author SoftwareLabs (amlel) +/// @author Zeta Electronics Corporation (amlel) /// @file cc.cc /// @brief Optimized C++ Compiler. /// @todo Throw error for scoped inside scoped variables when they get referenced outside. @@ -170,7 +170,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for SoftwareLabs C++ */ +/* @brief C++ compiler backend for Zeta Electronics Corporation C++ */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: @@ -316,7 +316,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, ch = '_'; } - syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; + syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; ++kLevelFunction; break; @@ -704,7 +704,7 @@ static void cxx_print_help() { kSplashCxx(); kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.softwarelabs.com/developer/cplusplus\n"); + kPrintF("%s", "www.Zeta Electronics Corporation.com/developer/cplusplus\n"); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index ada2830..a731431 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 26269f4..b805c95 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ ///////////////////////////////////////////////////////////////////////////////////////// /// @file i64asm.cxx -/// @author SoftwareLabs +/// @author Zeta Electronics Corporation /// @brief AMD64 Assembler. /// REMINDER: when dealing with an undefined symbol use (string @@ -175,13 +175,13 @@ MPCC_MODULE(NewOSAssemblerAMD64) if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 SoftwareLabs.\n"; + "(c) 2024 Zeta Electronics Corporation.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " - "SoftwareLabs.\n"; + "Zeta Electronics Corporation.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; @@ -1300,7 +1300,7 @@ bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, } } } - + if (bits == 64 || bits == 32) { if (!hasRBasedRegs && bits >= 32) diff --git a/Sources/link.cc b/Sources/link.cc index 6ed2db5..08e9dd0 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ /// @file link.cc -/// @author SoftwareLabs (amlel) -/// @brief SoftwareLabs Linker. +/// @author Zeta Electronics Corporation (amlel) +/// @brief Zeta Electronics Corporation Linker. /// Last Rev: Sat Feb 24 CET 2024 @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "SoftwareLabs Linker %s, (c) SoftwareLabs 2024\n" +#define kLinkerVersion "Zeta Electronics Corporation Linker %s, (c) Zeta Electronics Corporation 2024\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -184,7 +184,7 @@ MPCC_MODULE(NewOSLinker) { pef_container.Count = 0UL; pef_container.Kind = CompilerKit::kPefKindExec; pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // SoftwareLabs Linker + pef_container.Linker = kLinkerId; // Zeta Electronics Corporation Linker pef_container.Abi = kAbi; // Multi-Processor UX ABI pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; pef_container.Magic[1] = kPefMagic[1]; diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index d008296..6148ad0 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright SoftwareLabs, all rights reserved. + * Copyright Zeta Electronics Corporation, all rights reserved. * * ======================================================== */ @@ -22,7 +22,7 @@ #define kOk 0 -/// @author SoftwareLabs (amlel) +/// @author Zeta Electronics Corporation (amlel) /// @file cc.cc /// @brief POWER C Compiler. @@ -1531,7 +1531,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) SoftwareLabs\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) Zeta Electronics Corporation\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 1edeaaa..53c99c1 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright SoftwareLabs + Copyright Zeta Electronics Corporation ------------------------------------------- */ ///////////////////////////////////////////////////////////////////////////////////////// /// @file ppcasm.cxx -/// @author SoftwareLabs +/// @author Zeta Electronics Corporation /// @brief POWER Assembler. /// REMINDER: when dealing with an undefined symbol use (string @@ -115,11 +115,11 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " - "2024 SoftwareLabs.\n"; + "2024 Zeta Electronics Corporation.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "ppcasm: POWER Assembler.\nppcasm: Copyright (c) 2024 " - "SoftwareLabs.\n"; + "Zeta Electronics Corporation.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; kStdOut << "-binary: Output as flat binary.\n"; diff --git a/posix.make b/posix.make index be1abb8..bc8f81e 100644 --- a/posix.make +++ b/posix.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright SoftwareLabs, all rights reserved. + # Copyright Zeta Electronics Corporation, all rights reserved. # # ======================================================== # @@ -72,9 +72,9 @@ linker: .PHONY: help help: - @echo "Compiler - MPCC Compiler Suite." - @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - SoftwareLabs Linkers." + @echo "Compiler - Zeta Electronics Corporation Compiler Suite." + @echo "Preprocessor - Zeta Electronics Corporation Preprocessor Suite." + @echo "linker - Zeta Electronics Corporation Linkers." @echo "clean - Clean objects and executables." .PHONY: clean @@ -88,5 +88,5 @@ clean: rm -rf *.obj rm -rf Output/*.exec rm -rf *.exec - + # Last rev 8-1-24 diff --git a/win64.make b/win64.make index e1819a9..8493db6 100644 --- a/win64.make +++ b/win64.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright SoftwareLabs, all rights reserved. + # Copyright Zeta Electronics Corporation, all rights reserved. # # ======================================================== # @@ -72,7 +72,7 @@ linker: help: @echo "Compiler - MPCC Compiler Suite." @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - SoftwareLabs Linkers." + @echo "linker - Zeta Electronics Corporation Linkers." @echo "clean - Clean objects and executables." .PHONY: clean -- cgit v1.2.3 From 4ba42279946a3f819406f8aebf960201a74f8bd3 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Fri, 14 Jun 2024 23:50:01 +0200 Subject: MHR-21: work in progress arm64 support, made a structure to describe opcodes. Signed-off-by: Amlal EL Mahrouss --- Comm/AsmKit/CPU/amd64.hpp | 27 ++++++++++--------- Comm/AsmKit/CPU/arm64.hpp | 27 +++++++++++++++++++ Comm/AsmKit/CPU/ppc.hpp | 10 +++++++ Comm/Public/SDK/CRT/__mpcc_defines.hxx | 24 +++++++---------- Sources/64asm.cc | 2 +- Sources/i64asm.cc | 2 +- Sources/link.cc | 2 +- Sources/ppcasm.cc | 2 +- codetools.10x | 48 ++++++++++++++++++++++++++++++++++ 9 files changed, 112 insertions(+), 32 deletions(-) create mode 100644 Comm/AsmKit/CPU/arm64.hpp create mode 100644 codetools.10x (limited to 'Sources') diff --git a/Comm/AsmKit/CPU/amd64.hpp b/Comm/AsmKit/CPU/amd64.hpp index 63ed1b3..17b515b 100644 --- a/Comm/AsmKit/CPU/amd64.hpp +++ b/Comm/AsmKit/CPU/amd64.hpp @@ -39,18 +39,19 @@ struct CpuOpcodeAMD64 inline std::vector kOpcodesAMD64 = { kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF)}; + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF) +}; #define kAsmRegisterLimit 15 diff --git a/Comm/AsmKit/CPU/arm64.hpp b/Comm/AsmKit/CPU/arm64.hpp new file mode 100644 index 0000000..a6b558a --- /dev/null +++ b/Comm/AsmKit/CPU/arm64.hpp @@ -0,0 +1,27 @@ +/* ------------------------------------------- + +Copyright Zeta Electronics Corporation + +------------------------------------------- */ + +#pragma once + +#include + +/// @brief ARM64 encoding support. +/// @file CPU/arm64.hpp + +struct CpuOpcodeArm64; + +/// @brief ARM64 opcode header. +struct CpuOpcodeArm64 final +{ + uint8_t fOpcode; // opcode + uint8_t fRegisterLeft; // left register index + uint8_t fRegisterRight; // right register index + bool fRegisterLeftHooked; + bool fRegisterRightHooked; + uint32_t fImmediateValue; // immediate 32-bit value + bool fImmediateValueHooked; +}; + diff --git a/Comm/AsmKit/CPU/ppc.hpp b/Comm/AsmKit/CPU/ppc.hpp index c4265da..4afbf5a 100644 --- a/Comm/AsmKit/CPU/ppc.hpp +++ b/Comm/AsmKit/CPU/ppc.hpp @@ -1,3 +1,13 @@ +/* ------------------------------------------- + + Some modifications are copyrighted under: + Zeta Electronics Corporation + + Original author: + Apple Inc + +------------------------------------------- */ + #pragma once #include diff --git a/Comm/Public/SDK/CRT/__mpcc_defines.hxx b/Comm/Public/SDK/CRT/__mpcc_defines.hxx index c05ee73..a526fd3 100644 --- a/Comm/Public/SDK/CRT/__mpcc_defines.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_defines.hxx @@ -30,8 +30,9 @@ typedef char* caddr_t; #ifdef __GNUC__ #include #define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#define __packed__ __attribute__((packed)) #elif defined(__MPCC__) - +#define __packed__ __mpcc_packed__ #define __alloca(sz) __mpcc_alloca(sz) #endif @@ -41,24 +42,17 @@ typedef char* caddr_t; #define __init_decl() \ extern "C" \ { + + #define __fini_decl() \ - } \ - ; + }; \ + + #else #define __init_decl() #define __fini_decl() #endif -#if __has_builtin(__builtin_alloca) -#define alloca(sz) __builtin_alloca(sz) -#ifdef __alloca -#undef __alloca -#endif -#define __alloca alloca -#else -#warning alloca not detected (MPCC) -#endif - typedef long long off_t; typedef unsigned long long uoff_t; @@ -71,7 +65,7 @@ typedef union float_cast { }; float f; -} __attribute__((packed)) float_cast_t; +} __packed__ float_cast_t; typedef union double_cast { struct @@ -82,7 +76,7 @@ typedef union double_cast { }; double f; -} __attribute__((packed)) double_cast_t; +} __packed__ double_cast_t; #endif // ifndef __GNUC__ diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 859bfd4..9f56570 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 64asm.cxx -// @author Zeta Electronics Corporation +// @author Amlal EL Mahrouss // @brief 64x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index b805c95..b10be54 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -7,7 +7,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// /// @file i64asm.cxx -/// @author Zeta Electronics Corporation +/// @author Amlal EL Mahrouss /// @brief AMD64 Assembler. /// REMINDER: when dealing with an undefined symbol use (string diff --git a/Sources/link.cc b/Sources/link.cc index 08e9dd0..296ada5 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -5,7 +5,7 @@ ------------------------------------------- */ /// @file link.cc -/// @author Zeta Electronics Corporation (amlel) +/// @author Amlal EL Mahrouss (amlel) /// @brief Zeta Electronics Corporation Linker. /// Last Rev: Sat Feb 24 CET 2024 diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 53c99c1..7f51c72 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -7,7 +7,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// /// @file ppcasm.cxx -/// @author Zeta Electronics Corporation +/// @author Amlal EL Mahrouss /// @brief POWER Assembler. /// REMINDER: when dealing with an undefined symbol use (string diff --git a/codetools.10x b/codetools.10x new file mode 100644 index 0000000..2961860 --- /dev/null +++ b/codetools.10x @@ -0,0 +1,48 @@ + + + + *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, + + true + true + true + false + false + false + + + + + + + + + + + + + false + + Debug + Release + + + x64 + Win32 + + + C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include + C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\ATLMFC\include + C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include + C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt + C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um + C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared + C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt + C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt + C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um + + + + + + -- cgit v1.2.3 From 0e6112e21e42b81f44521db24206ab5f1a9fc212 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Sun, 16 Jun 2024 10:28:30 +0200 Subject: MHR-21: win64: Source file path doesnt get recognized on windows (BUG) Signed-off-by: Amlal EL Mahrouss --- Comm/ParserKit.hpp | 2 ++ Sources/AssemblyFactory.cc | 7 +++--- Sources/bpp.cc | 2 +- Sources/cplusplus.cc | 53 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 48 insertions(+), 16 deletions(-) (limited to 'Sources') diff --git a/Comm/ParserKit.hpp b/Comm/ParserKit.hpp index 8b66995..bc0ab54 100644 --- a/Comm/ParserKit.hpp +++ b/Comm/ParserKit.hpp @@ -49,7 +49,9 @@ namespace ParserKit eKeywordKindFunctionStart, eKeywordKindFunctionEnd, eKeywordKindVariable, + eKeywordKindVariablePtr, eKeywordKindType, + eKeywordKindTypePtr, eKeywordKindExpressionBegin, eKeywordKindExpressionEnd, eKeywordKindArgSeparator, diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 232fcc0..891712d 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -9,7 +9,7 @@ /** * @file AssemblyFactory.cxx - * @author Zeta Electronics Corporation (amlal@mahrouss.com) + * @author amlal (amlal@softwarelabs.com) * @brief Assembler Kit * @version 0.1 * @date 2024-01-27 @@ -25,7 +25,7 @@ namespace CompilerKit { - //! @brief Compile for specific format (ELF, PEF, ZBIN) + ///! @brief Compile for specific format (ELF, PEF, ZBIN) Int32 AssemblyFactory::Compile(std::string& sourceFile, const Int32& arch) noexcept { @@ -35,7 +35,7 @@ namespace CompilerKit return fMounted->CompileToFormat(sourceFile, arch); } - //! @brief mount assembly backend. + ///! @brief mount assembly backend. void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { if (mountPtr) @@ -44,6 +44,7 @@ namespace CompilerKit } } + ///! @brief Unmount assembler. AssemblyInterface* AssemblyFactory::Unmount() noexcept { auto mount_prev = fMounted; diff --git a/Sources/bpp.cc b/Sources/bpp.cc index 9dcd2d3..adaec63 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -892,7 +892,7 @@ MPCC_MODULE(NewOSPreprocessor) { std::cout << e.what() << '\n'; } - return 0; + return 1; } // Last rev 8-1-24 diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 611507f..6dad1b0 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Zeta Electronics Corporation C++ Compiler, Copyright Zeta Electronics Corporation.") + kPrintF(kWhite "%s\n", "Zeta Optimized C++ Compiler, Copyright Zeta Electronics Corporation.") #include #include @@ -26,6 +26,7 @@ #include #include #include +#include #define kOk 0 @@ -207,7 +208,7 @@ namespace detail const char* CompilerBackendCPlusPlus::Language() { - return "ISO C++"; + return "Zeta C++"; } static std::vector kRegisterMap; @@ -225,6 +226,13 @@ static std::vector cRegisters = { "r15", }; +static std::vector cRegistersCall = { + "rcx", + "rdx", + "r8", + "r9", +}; + ///////////////////////////////////////////////////////////////////////////////////////// /// @name Compile @@ -658,9 +666,30 @@ public: dest += ch; } + if (dest.empty()) + { + dest = "CXX-MPCC-"; + + std::random_device rd; + auto seed_data = std::array {}; + + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator(generator); + + auto id = gen(); + dest += uuids::to_string(id); + } + std::vector exts = kAsmFileExts; + dest += exts[3]; + std::cout << dest; + kState.fOutputAssembly = std::make_unique(dest); auto fmt = CompilerKit::current_date(); @@ -736,16 +765,16 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); kKeywords.push_back({.keyword_name = "void", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); -- cgit v1.2.3 From 6b5ae61362ebc1f71d4284c90aa62c20640abdd7 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Sun, 16 Jun 2024 12:25:16 +0200 Subject: MHR-21: Add ARM64 type for PEF executables. - Can now target PEF files. - Need an ARM64 assembler now. Signed-off-by: Amlal EL Mahrouss --- Comm/StdKit/PEF.hpp | 1 + Sources/cplusplus.cc | 4 ++-- Sources/link.cc | 13 ++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'Sources') diff --git a/Comm/StdKit/PEF.hpp b/Comm/StdKit/PEF.hpp index 9198b30..911d903 100644 --- a/Comm/StdKit/PEF.hpp +++ b/Comm/StdKit/PEF.hpp @@ -39,6 +39,7 @@ namespace CompilerKit kPefArch64000, /* 64x0 RISC architecture. */ kPefArch32000, kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, kPefArchInvalid = 0xFF, }; diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 6dad1b0..db065de 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Zeta Optimized C++ Compiler, Copyright Zeta Electronics Corporation.") + kPrintF(kWhite "%s\n", "Zeta Optimized C++ Compiler, Copyright Zeta Electronics Corporation 2024, all rights reserved.") #include #include @@ -733,7 +733,7 @@ static void cxx_print_help() { kSplashCxx(); kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.Zeta Electronics Corporation.com/developer/cplusplus\n"); + kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/Sources/link.cc b/Sources/link.cc index 296ada5..757b26a 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Zeta Electronics Corporation Linker %s, (c) Zeta Electronics Corporation 2024\n" +#define kLinkerVersion "Zeta Linker %s, (c) Zeta Electronics Corporation 2024, all rights reserved.\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -89,7 +89,8 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "-64x0: Output as a 64x0 PEF.\n"; kStdOut << "-amd64: Output as a AMD64 PEF.\n"; kStdOut << "-rv64: Output as a RISC-V PEF.\n"; - kStdOut << "-ppc64: Output as a POWER PEF.\n"; + kStdOut << "-power64: Output as a POWER PEF.\n"; + kStdOut << "-arm64: Output as a ARM64 PEF.\n"; kStdOut << "-output-file: Select the output file name.\n"; return 0; @@ -116,6 +117,10 @@ MPCC_MODULE(NewOSLinker) { kArch = CompilerKit::kPefArchPowerPC; continue; + } else if (StringCompare(argv[i], "-arm64") == 0) { + kArch = CompilerKit::kPefArchARM64; + + continue; } else if (StringCompare(argv[i], "-verbose") == 0) { kVerbose = true; @@ -160,9 +165,11 @@ MPCC_MODULE(NewOSLinker) { kStdOut << "link: no input files." << std::endl; return MPCC_EXEC_ERROR; } else { + namespace fs = std::filesystem; + // check for existing files, if they don't throw an error. for (auto &obj : kObjectList) { - if (!std::filesystem::exists(obj)) { + if (!fs::exists(obj)) { // if filesystem doesn't find file // -> throw error. kStdOut << "link: no such file: " << obj << std::endl; -- cgit v1.2.3 From 1f0f80532b0a3016e947996e196a78d33dd4fe3f Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Tue, 25 Jun 2024 09:13:26 +0200 Subject: C++: Implementing classes and namespace support. Signed-off-by: Amlal EL Mahrouss --- Sources/cplusplus.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index db065de..03aaeb8 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Zeta Optimized C++ Compiler, Copyright Zeta Electronics Corporation 2024, all rights reserved.") + kPrintF(kWhite "%s\n", "ZECC C++, (c) RCM 2024, all rights reserved.") #include #include @@ -31,7 +31,7 @@ #define kOk 0 /* Zeta Electronics Corporation C++ driver */ -/* This is part of MPCC C++ compiler. */ +/* This is part of ZECC C++ compiler. */ /* (c) Zeta Electronics Corporation */ /// @author Zeta Electronics Corporation (amlel) -- cgit v1.2.3 From ba4d598a093657b5c4b43d77a49bb9ec744b83fc Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Thu, 27 Jun 2024 10:18:09 +0200 Subject: WIP: objective-c keywords for C++ compiler. Orthodox C++: https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b Signed-off-by: Amlal EL Mahrouss --- Sources/cplusplus.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 03aaeb8..5f67e96 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "%s\n", "ZECC C++, (c) RCM 2024, all rights reserved.") +kPrintF(kWhite "%s\n", "ZECC C++, (c) 2024 Zeta Electronics, all rights reserved.") #include #include -- cgit v1.2.3 From 41ed44141820405e4b083fec4fd8fab5d60073aa Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Thu, 27 Jun 2024 11:30:13 +0200 Subject: IMP: New PEF calling convention. Signed-off-by: Amlal EL Mahrouss --- Sources/cplusplus.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 5f67e96..5cdb3fc 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -16,6 +16,8 @@ #define kSplashCxx() \ kPrintF(kWhite "%s\n", "ZECC C++, (c) 2024 Zeta Electronics, all rights reserved.") +// import, @free_at_exit { ... }, fn foo() -> auto { ... } + #include #include #include @@ -216,8 +218,8 @@ static std::vector kRegisterMap; static size_t kLevelFunction = 0UL; static std::vector cRegisters = { - "r8", - "r9", + "rbx", + "rsi", "r10", "r11", "r12", @@ -226,11 +228,17 @@ static std::vector cRegisters = { "r15", }; +/// @brief The PEF calling convention (caller must save rax, rbp) +/// @note callee must return via **rax**. static std::vector cRegistersCall = { "rcx", "rdx", "r8", "r9", + "xmm8", + "xmm9", + "xmm10", + "xmm11", }; ///////////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From 5ca81bdde78a60d6a909e36c55c4a2a9a43a3f8c Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Fri, 28 Jun 2024 11:23:06 +0200 Subject: FIX: author names and add Qt files. Signed-off-by: Amlal EL Mahrouss --- Sources/64x0-cc.cc | 4 ++-- Sources/bpp.cc | 6 +++--- Sources/cplusplus.cc | 2 +- Sources/power-cc.cc | 4 ++-- codetools.cflags | 1 + codetools.config | 2 ++ codetools.creator | 1 + codetools.cxxflags | 1 + codetools.files | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++ codetools.includes | 2 ++ 10 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 codetools.cflags create mode 100644 codetools.config create mode 100644 codetools.creator create mode 100644 codetools.cxxflags create mode 100644 codetools.files create mode 100644 codetools.includes (limited to 'Sources') diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index b981cb8..4be1292 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -29,7 +29,7 @@ /* This is part of MPCC C SDK. */ /* (c) Zeta Electronics Corporation */ -/// @author Zeta Electronics Corporation (amlel) +/// @author Amlal El Mahrouss (amlel) /// @file 64x0-cc.cc /// @brief 64x0 C Compiler. diff --git a/Sources/bpp.cc b/Sources/bpp.cc index adaec63..31e60d8 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -19,9 +19,9 @@ #define kMacroPrefix '%' -// @author Zeta Electronics Corporation (amlel) -// @file bpp.cc -// @brief C preprocessor. +/// @author Amlal El Mahrouss (amlel) +/// @file bpp.cc +/// @brief Preprocessor. typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, std::ofstream &pp_out); diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 5cdb3fc..12847dc 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -36,7 +36,7 @@ kPrintF(kWhite "%s\n", "ZECC C++, (c) 2024 Zeta Electronics, all rights reserved /* This is part of ZECC C++ compiler. */ /* (c) Zeta Electronics Corporation */ -/// @author Zeta Electronics Corporation (amlel) +/// @author Amlal El Mahrouss (amlel) /// @file cc.cc /// @brief Optimized C++ Compiler. /// @todo Throw error for scoped inside scoped variables when they get referenced outside. diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index 6148ad0..a90c596 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -19,10 +18,11 @@ #include #include #include +#include #define kOk 0 -/// @author Zeta Electronics Corporation (amlel) +/// @author Amlal El Mahrouss (amlel) /// @file cc.cc /// @brief POWER C Compiler. diff --git a/codetools.cflags b/codetools.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/codetools.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/codetools.config b/codetools.config new file mode 100644 index 0000000..e0284f4 --- /dev/null +++ b/codetools.config @@ -0,0 +1,2 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 diff --git a/codetools.creator b/codetools.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/codetools.creator @@ -0,0 +1 @@ +[General] diff --git a/codetools.cxxflags b/codetools.cxxflags new file mode 100644 index 0000000..e23b2ae --- /dev/null +++ b/codetools.cxxflags @@ -0,0 +1 @@ +-std=c++20 diff --git a/codetools.files b/codetools.files new file mode 100644 index 0000000..211a290 --- /dev/null +++ b/codetools.files @@ -0,0 +1,61 @@ +.clang-format +Comm/AsmKit/AsmKit.hpp +Comm/AsmKit/CPU/32x0.hpp +Comm/AsmKit/CPU/64x0.hpp +Comm/AsmKit/CPU/amd64.hpp +Comm/AsmKit/CPU/arm64.hpp +Comm/AsmKit/CPU/ppc.hpp +Comm/CompilerKit.hpp +Comm/Defines.hpp +Comm/ParserKit.hpp +Comm/Public/SDK/CRT/__mpcc_alloca.hxx +Comm/Public/SDK/CRT/__mpcc_defines.hxx +Comm/Public/SDK/CRT/__mpcc_exception.hxx +Comm/Public/SDK/CRT/__mpcc_hint.hxx +Comm/Public/SDK/CRT/__mpcc_malloc.hxx +Comm/Public/SDK/CRT/__mpcc_power.inc +Comm/StdKit/AE.hpp +Comm/StdKit/ELF.hpp +Comm/StdKit/ErrorID.hpp +Comm/StdKit/ErrorOr.hpp +Comm/StdKit/PEF.hpp +Comm/StdKit/Ref.hpp +Comm/StdKit/String.hpp +Comm/StdKit/XCOFF.hxx +Comm/UUID.hpp +Comm/Version.hxx +Doc/asm-specs.txt +Doc/havp.txt +Doc/notice.txt +Doc/vnrp.txt +Doxyfile +Examples/Example64k.s +Examples/ExampleAMD64.asm +Examples/ExampleAMD64_Return.asm +Examples/ExampleCDialect.S +Examples/ExampleCDialect.cc +Examples/ExampleCPlusPlus.cxx +Examples/ExampleCPlusPlus.s +Examples/ExamplePowerPC.S +MailMap +ReadMe.md +Sources/32asm.cc +Sources/64asm.cc +Sources/64x0-cc.cc +Sources/AssemblyFactory.cc +Sources/Detail/ReadMe.md +Sources/Detail/asmutils.hxx +Sources/Detail/compilerutils.hxx +Sources/String.cc +Sources/bpp.cc +Sources/coff2ae.cc +Sources/compile_flags.txt +Sources/cplusplus.cc +Sources/elf2ae.cc +Sources/i64asm.cc +Sources/link.cc +Sources/power-cc.cc +Sources/ppcasm.cc +posix.make +run_format.sh +win64.make diff --git a/codetools.includes b/codetools.includes new file mode 100644 index 0000000..a9a0fb5 --- /dev/null +++ b/codetools.includes @@ -0,0 +1,2 @@ +./Comm +./ -- cgit v1.2.3 From 12f3049c5eda64c8ced549e23ac1a22f04bc702f Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Fri, 28 Jun 2024 13:15:35 +0200 Subject: IMP: Use XEN brand for assembler. Signed-off-by: Amlal EL Mahrouss --- Sources/ppcasm.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'Sources') diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 7f51c72..8d5f088 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -19,15 +19,14 @@ #include #include +#include #include #include -#include #include -#include #include -#include +#include #include -#include +#include #include ///////////////////// @@ -113,12 +112,12 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { for (size_t i = 1; i < argc; ++i) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " + kStdOut << "ppcasm: POWER64/XEN Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " "2024 Zeta Electronics Corporation.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "ppcasm: POWER Assembler.\nppcasm: Copyright (c) 2024 " + kStdOut << "ppcasm: POWER64/XEN Assembler.\nppcasm: Copyright (c) 2024 " "Zeta Electronics Corporation.\n"; kStdOut << "-version: Print program version.\n"; kStdOut << "-verbose: Print verbose output.\n"; -- cgit v1.2.3 From 0495962407af7f89b72e41c8b099cfba51d68e08 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Thu, 4 Jul 2024 16:23:57 +0200 Subject: MHR-36: Finishing C++ compiler Signed-off-by: Amlal EL Mahrouss --- .gitignore | 2 ++ Sources/64x0-cc.cc | 4 ++-- Sources/String.cc | 16 +++++++++------- Sources/ppcasm.cc | 4 ++-- 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'Sources') diff --git a/.gitignore b/.gitignore index c8ab9fa..69f191e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ local.properties .loadpath .recommenders +*.creator.user + # NewOS/MP-UX executable *.exec *.bin diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 4be1292..9c32953 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -23,8 +23,6 @@ #include #include -#define kOk 0 - /* C driver */ /* This is part of MPCC C SDK. */ /* (c) Zeta Electronics Corporation */ @@ -41,6 +39,8 @@ ///////////////////// +#define kOk (0) + #define kBlank "\e[0;30m" #define kRed "\e[0;31m" #define kWhite "\e[0;97m" diff --git a/Sources/String.cc b/Sources/String.cc index 5a8f3ed..c7185ca 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -19,7 +19,6 @@ */ #include -#include namespace CompilerKit { CharType *StringView::Data() { return m_Data; } @@ -80,10 +79,13 @@ StringView StringBuilder::Construct(const CharType *data) { const char *StringBuilder::FromInt(const char *fmt, int i) { if (!fmt) return ("-1"); - char *ret = new char[8 + string_length(fmt)]; + auto ret_len = 8 + string_length(fmt); + char *ret = new char[ret_len]; if (!ret) return ("-1"); + memset(ret, 0, ret_len); + CharType result[8]; if (!to_str(result, sizeof(int), i)) { delete[] ret; @@ -150,18 +152,18 @@ bool StringBuilder::Equals(const char *lhs, const char *rhs) { return true; } -const char *StringBuilder::Format(const char *fmt, const char *fmt2) { - if (!fmt || !fmt2) return ("?"); +const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { + if (!fmt || !fmtRight) return ("?"); - char *ret = new char[string_length(fmt2) + string_length(fmt2)]; + char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; if (!ret) return ("?"); for (SizeType idx = 0; idx < string_length(fmt); ++idx) { if (fmt[idx] == '%') { SizeType result_cnt = idx; - for (SizeType y_idx = 0; y_idx < string_length(fmt2); ++y_idx) { - ret[result_cnt] = fmt2[y_idx]; + for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { + ret[result_cnt] = fmtRight[y_idx]; ++result_cnt; } diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 8d5f088..f8e47d7 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -43,11 +43,11 @@ #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) +constexpr auto cPowerIPAlignment = 0x4U; + static CharType kOutputArch = CompilerKit::kPefArchPowerPC; static Boolean kOutputAsBinary = false; -constexpr auto cPowerIPAlignment = 0x4U; - static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; -- cgit v1.2.3 From 7a9da2133cb0f9b72fa81577efc4ece81ca44020 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Sat, 6 Jul 2024 09:53:31 +0200 Subject: MHR-36: NDK, Update Linker and C++ driver. Signed-off-by: Amlal El Mahrouss --- Doxyfile | 4 ++-- Sources/compile_flags.txt | 2 +- Sources/cplusplus.cc | 45 ++++++++++++++++++--------------------------- Sources/link.cc | 2 +- 4 files changed, 22 insertions(+), 31 deletions(-) (limited to 'Sources') diff --git a/Doxyfile b/Doxyfile index 2fddb4b..c91e98b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = NewOS SDK +PROJECT_NAME = NDK # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -54,7 +54,7 @@ PROJECT_NUMBER = 2.0.0 # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "MPCC" +PROJECT_BRIEF = "NewOS Developer Kit" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 diff --git a/Sources/compile_flags.txt b/Sources/compile_flags.txt index 028be9d..f9acaba 100644 --- a/Sources/compile_flags.txt +++ b/Sources/compile_flags.txt @@ -1,5 +1,5 @@ -std=c++20 -I../ --I../StdKit +-I../Comm -I./ -I./Detail/ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 12847dc..39e5441 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -14,7 +14,7 @@ #define kPrintF printf #define kSplashCxx() \ -kPrintF(kWhite "%s\n", "ZECC C++, (c) 2024 Zeta Electronics, all rights reserved.") +kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") // import, @free_at_exit { ... }, fn foo() -> auto { ... } @@ -193,30 +193,8 @@ static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; static std::vector kCompilerVariables; static std::vector kCompilerFunctions; -/// detail namespaces - -namespace detail -{ - union number_cast final { - number_cast(UInt64 raw) - : raw(raw) - { - } - - char number[8]; - UInt64 raw; - }; -} // namespace detail - -const char* CompilerBackendCPlusPlus::Language() -{ - return "Zeta C++"; -} - static std::vector kRegisterMap; -static size_t kLevelFunction = 0UL; - static std::vector cRegisters = { "rbx", "rsi", @@ -226,6 +204,10 @@ static std::vector cRegisters = { "r13", "r14", "r15", + "xmm12", + "xmm13", + "xmm14", + "xmm15", }; /// @brief The PEF calling convention (caller must save rax, rbp) @@ -241,10 +223,19 @@ static std::vector cRegistersCall = { "xmm11", }; +static size_t kLevelFunction = 0UL; + +/// detail namespaces + +const char* CompilerBackendCPlusPlus::Language() +{ + return "Zeta C++"; +} + ///////////////////////////////////////////////////////////////////////////////////////// /// @name Compile -/// @brief Generate MASM from a C++ source. +/// @brief Generate MASM assembly from a C++ source. ///////////////////////////////////////////////////////////////////////////////////////// @@ -677,12 +668,12 @@ public: if (dest.empty()) { dest = "CXX-MPCC-"; - + std::random_device rd; auto seed_data = std::array {}; - + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); std::mt19937 generator(seq); diff --git a/Sources/link.cc b/Sources/link.cc index 757b26a..4c459b5 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Zeta Linker %s, (c) Zeta Electronics Corporation 2024, all rights reserved.\n" +#define kLinkerVersion "Zeta Linker Driver %s, (c) Zeta Electronics Corporation 2024, all rights reserved.\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) -- cgit v1.2.3 From 39e7d2b66636762b74376bce203a7fa70f0c3abd Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 10 Jul 2024 09:40:33 +0200 Subject: MHR-36: Bumping repository. Signed-off-by: Amlal El Mahrouss --- Sources/AssemblyFactory.cc | 4 ++-- Sources/cplusplus.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Sources') diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index 891712d..faa4847 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -8,8 +8,8 @@ #include /** - * @file AssemblyFactory.cxx - * @author amlal (amlal@softwarelabs.com) + * @file AssemblyFactory.cc + * @author amlal (amlal@zeta.com) * @brief Assembler Kit * @version 0.1 * @date 2024-01-27 diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 39e5441..b881cb2 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -16,7 +16,7 @@ #define kSplashCxx() \ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") -// import, @free_at_exit { ... }, fn foo() -> auto { ... } +// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } #include #include @@ -54,7 +54,7 @@ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all ///////////////////////////////////// -// INTERNAL STUFF OF THE C COMPILER +// INTERNALS OF THE C COMPILER ///////////////////////////////////// -- cgit v1.2.3 From b8631c559cdce12b9677ab88627b2a9cffbab627 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 10 Jul 2024 18:17:49 +0200 Subject: [DOCS] Update documentation. Signed-off-by: Amlal El Mahrouss --- Sources/cplusplus.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index b881cb2..15b6803 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -58,6 +58,7 @@ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all ///////////////////////////////////// +/// @internal namespace detail { struct CompilerRegisterMap final @@ -173,7 +174,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for Zeta Electronics Corporation C++ */ +/* @brief C++ compiler backend for the Zeta C++ driver */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: @@ -187,7 +188,7 @@ public: const char* Language() override; }; -/// compiler variables +/// @internal compiler variables static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; static std::vector kCompilerVariables; -- cgit v1.2.3 From d4d0541861d3f95fee182bef5b79f572d3bcb164 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 11 Jul 2024 10:53:04 +0200 Subject: [MHR-36] Fix toolchain, new app logo, refactor drivers. Signed-off-by: Amlal El Mahrouss --- .gitignore | 16 +- Comm/Defines.hpp | 10 +- Comm/Version.hxx | 2 +- Icons/app-logo.ico | Bin 108478 -> 4865 bytes Sources/32asm.cc | 2 +- Sources/64asm.cc | 4 +- Sources/64x0-cc.cc | 32 +- Sources/bpp.cc | 25 +- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 31 +- Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 22 +- Sources/link.cc | 1258 +++++++++++++++++++++++++++----------------------- Sources/power-cc.cc | 2 +- Sources/ppcasm.cc | 22 +- posix.make | 30 +- 16 files changed, 782 insertions(+), 678 deletions(-) (limited to 'Sources') diff --git a/.gitignore b/.gitignore index 69f191e..a181dc3 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,20 @@ replay_pid* Drivers/Output/Tests/*.masm +Output/32link +Output/64asm +Output/64link +Output/64x0-cc +Output/bpp +Output/cplusplus +Output/i64asm +Output/i64link +Output/link +Output/power-cc +Output/ppc-cc +Output/ppcasm +Output/ppclink + .vs docs/html @@ -131,7 +145,7 @@ Cloud9.creator.user .cproject .settings/org.eclipse.cdt.codan.core.prefs .settings/org.eclipse.core.resources.prefs -.settings/org.eclipse.core.runtime.prefs +.settings/org.eclipse.core.runtime.prefs # HDD *.hdd diff --git a/Comm/Defines.hpp b/Comm/Defines.hpp index 8c47bd0..a6f0260 100644 --- a/Comm/Defines.hpp +++ b/Comm/Defines.hpp @@ -136,12 +136,12 @@ typedef char char_type; ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ } -#ifdef __MODULE_NEED__ -#define MPCC_MODULE(name) int name(int argc, char** argv) +#ifdef __NDK_MODULE__ +#define NDK_MODULE(name) int name(int argc, char** argv) #else -#define MPCC_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __MODULE_NEED__ */ +#define NDK_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __NDK_MODULE__ */ -#pragma scalar_storage_order big - endian +#pragma scalar_storage_order big-endian #endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Comm/Version.hxx b/Comm/Version.hxx index 377a688..ab02cf6 100644 --- a/Comm/Version.hxx +++ b/Comm/Version.hxx @@ -1,3 +1,3 @@ #pragma once -#define kDistVersion "v1.20" +#define kDistVersion "v1.21" diff --git a/Icons/app-logo.ico b/Icons/app-logo.ico index dbdcdee..2ab3d5b 100644 Binary files a/Icons/app-logo.ico and b/Icons/app-logo.ico differ diff --git a/Sources/32asm.cc b/Sources/32asm.cc index 0dd6f7c..b043447 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -49,4 +49,4 @@ ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssembler32000) { return 0; } +NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 9f56570..384a086 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -10,7 +10,7 @@ // @file 64asm.cxx // @author Amlal EL Mahrouss -// @brief 64x0 Assembler. +// @brief 64x000 Assembler. // REMINDER: when dealing with an undefined symbol use (string // size):LinkerFindSymbol:(string) so that ld will look for it. @@ -105,7 +105,7 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssembler64000) { +NDK_MODULE(NewOSAssembler64000) { for (size_t i = 1; i < argc; ++i) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 9c32953..9f73b1b 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -24,7 +24,7 @@ #include /* C driver */ -/* This is part of MPCC C SDK. */ +/* This is part of the NDK. */ /* (c) Zeta Electronics Corporation */ /// @author Amlal El Mahrouss (amlel) @@ -1325,13 +1325,13 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +class AssemblyCCInterface final : public CompilerKit::AssemblyInterface { public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + MPCC_COPY_DEFAULT(AssemblyCCInterface); [[maybe_unused]] static Int32 Arch() noexcept { @@ -1340,7 +1340,7 @@ public: Int32 CompileToFormat(std::string& src, Int32 arch) override { - if (arch != AssemblyMountpointCLang::Arch()) + if (arch != AssemblyCCInterface::Arch()) return -1; if (kCompilerBackend == nullptr) @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Zeta Electronics Corporation\n", kDistVersion) + kPrintF(kWhite "Zeta C Driver, %s, (c) Zeta Electronics Corporation\n", kDistVersion) static void cc_print_help() { @@ -1524,7 +1524,7 @@ static void cc_print_help() #define kExt ".c" -MPCC_MODULE(NewOSCompilerCLang64x0) +NDK_MODULE(NewOSCompilerCLang64x0) { kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); @@ -1535,7 +1535,7 @@ MPCC_MODULE(NewOSCompilerCLang64x0) bool skip = false; - kFactory.Mount(new AssemblyMountpointCLang()); + kFactory.Mount(new AssemblyCCInterface()); kMachine = CompilerKit::AssemblyFactory::kArch64x0; kCompilerBackend = new CompilerBackendCLang(); @@ -1547,30 +1547,30 @@ MPCC_MODULE(NewOSCompilerCLang64x0) continue; } - if (argv[index][0] == '-') + if (argv[index][0] == '/') { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) { kSplashCxx(); return kOk; } - if (strcmp(argv[index], "-verbose") == 0) + if (strcmp(argv[index], "/verbose") == 0) { kState.fVerbose = true; continue; } - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) { cc_print_help(); return kOk; } - if (strcmp(argv[index], "-dialect") == 0) + if (strcmp(argv[index], "/dialect") == 0) { if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; @@ -1578,7 +1578,7 @@ MPCC_MODULE(NewOSCompilerCLang64x0) return kOk; } - if (strcmp(argv[index], "-fmax-exceptions") == 0) + if (strcmp(argv[index], "/fmax-exceptions") == 0) { try { diff --git a/Sources/bpp.cc b/Sources/bpp.cc index 31e60d8..d703748 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -775,7 +775,7 @@ void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSPreprocessor) { +NDK_MODULE(NewOSPreprocessor) { try { bool skip = false; bool double_skip = false; @@ -810,23 +810,24 @@ MPCC_MODULE(NewOSPreprocessor) { continue; } - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0) { + if (argv[index][0] == '/') { + if (strcmp(argv[index], "/version") == 0) { printf("%s\n", "bpp v1.11, (c) Zeta Electronics Corporation"); return 0; } - if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) Zeta Electronics Corporation"); - printf("%s\n", "-working-dir : set directory to working path."); - printf("%s\n", "-include-dir : add directory to include path."); - printf("%s\n", "-def : def macro."); - printf("%s\n", "-version: print the version."); + if (strcmp(argv[index], "/help") == 0) { + printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) Zeta Electronics Corporation"); + printf("%s\n", "/working-dir : set directory to working path."); + printf("%s\n", "/include-dir : add directory to include path."); + printf("%s\n", "/def : def macro."); + printf("%s\n", "/version: print the version."); + printf("%s\n", "/help: show help."); return 0; } - if (strcmp(argv[index], "-include-dir") == 0) { + if (strcmp(argv[index], "/include-dir") == 0) { std::string inc = argv[index + 1]; skip = true; @@ -834,13 +835,13 @@ MPCC_MODULE(NewOSPreprocessor) { kIncludes.push_back(inc); } - if (strcmp(argv[index], "-working-dir") == 0) { + if (strcmp(argv[index], "/working-dir") == 0) { std::string inc = argv[index + 1]; skip = true; kWorkingDir = inc; } - if (strcmp(argv[index], "-def") == 0 && argv[index + 1] != nullptr && + if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && argv[index + 2] != nullptr) { std::string macro_key = argv[index + 1]; diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 7e1cc0e..0bf17e6 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -20,4 +20,4 @@ ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSCOFFToAE) { return 0; } +NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 15b6803..59b5dcf 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -630,22 +630,23 @@ _MpccOkay: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface +class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface { public: - explicit AssemblyMountpointClang() = default; - ~AssemblyMountpointClang() override = default; + explicit AssemblyCPlusPlusInterface() = default; + ~AssemblyCPlusPlusInterface() override = default; - MPCC_COPY_DEFAULT(AssemblyMountpointClang); + MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); - [[maybe_unused]] static Int32 Arch() noexcept + [[maybe_unused]] + static Int32 Arch() noexcept { return CompilerKit::AssemblyFactory::kArchAMD64; } Int32 CompileToFormat(std::string& src, Int32 arch) override { - if (arch != AssemblyMountpointClang::Arch()) + if (arch != AssemblyCPlusPlusInterface::Arch()) return -1; if (kCompilerBackend == nullptr) @@ -743,7 +744,7 @@ static void cxx_print_help() ".cpp", ".cxx", ".cc", ".c++", ".cp" \ } -MPCC_MODULE(CompilerCPlusPlus) +NDK_MODULE(CompilerCPlusPlus) { bool skip = false; @@ -801,12 +802,12 @@ MPCC_MODULE(CompilerCPlusPlus) kKeywords.push_back({.keyword_name = ">=", .keyword_kind = ParserKit::eKeywordKindGreaterEq}); kKeywords.push_back({.keyword_name = "<=", .keyword_kind = ParserKit::eKeywordKindLessEq}); - kFactory.Mount(new AssemblyMountpointClang()); + kFactory.Mount(new AssemblyCPlusPlusInterface()); kCompilerBackend = new CompilerBackendCPlusPlus(); for (auto index = 1UL; index < argc; ++index) { - if (argv[index][0] == '-') + if (argv[index][0] == '/') { if (skip) { @@ -814,28 +815,28 @@ MPCC_MODULE(CompilerCPlusPlus) continue; } - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) { kSplashCxx(); return kOk; } - if (strcmp(argv[index], "-verbose") == 0) + if (strcmp(argv[index], "/verbose") == 0) { kState.fVerbose = true; continue; } - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) { cxx_print_help(); return kOk; } - if (strcmp(argv[index], "-dialect") == 0) + if (strcmp(argv[index], "/dialect") == 0) { if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; @@ -843,7 +844,7 @@ MPCC_MODULE(CompilerCPlusPlus) return kOk; } - if (strcmp(argv[index], "-max-errors") == 0) + if (strcmp(argv[index], "/max-errors") == 0) { try { diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index a731431..ede28a2 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -19,4 +19,4 @@ ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSELFToAE) { return 0; } +NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index b10be54..f0dd459 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -128,7 +128,7 @@ namespace detail ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssemblerAMD64) +NDK_MODULE(NewOSAssemblerAMD64) { //////////////// CPU OPCODES BEGIN //////////////// @@ -170,30 +170,30 @@ MPCC_MODULE(NewOSAssemblerAMD64) for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') + if (argv[i][0] == '/') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " "(c) 2024 Zeta Electronics Corporation.\n"; return 0; } - else if (strcmp(argv[i], "-h") == 0) + else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: Copyright (c) 2024 " + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " "Zeta Electronics Corporation.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; return 0; } - else if (strcmp(argv[i], "-binary") == 0) + else if (strcmp(argv[i], "/binary") == 0) { kOutputAsBinary = true; continue; } - else if (strcmp(argv[i], "-verbose") == 0) + else if (strcmp(argv[i], "/verbose") == 0) { kVerbose = true; continue; diff --git a/Sources/link.cc b/Sources/link.cc index 4c459b5..0114484 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -10,7 +10,7 @@ /// Last Rev: Sat Feb 24 CET 2024 -/// note: Do not look up for anything with .code64/.data64/.zero64! +/// @note Do not look up for anything with .code64/.data64/.zero64! /// It will be loaded when program will start up! #include @@ -39,610 +39,700 @@ #define StringCompare(DST, SRC) strcmp(DST, SRC) -#define kPefNoCpu 0U +#define kPefNoCpu 0U #define kPefNoSubCpu 0U -#define kWhite "\e[0;97m" +#define kWhite "\e[0;97m" #define kStdOut (std::cout << kWhite) #define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId 0x5046FF -#define kLinkerAbiContainer "Container:Abi:" +#define kLinkerId 0x5046FF +#define kLinkerAbiContainer "Container:Abi:" -enum { kStandardAbi = 0x5046 /* PF */ }; +enum +{ + kStandardAbi = 0x5046 /* PF */ +}; static std::string kOutput; -static Int32 kAbi = kStandardAbi; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArch64000; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; -static Bool kVerbose = false; +static Int32 kAbi = kStandardAbi; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = CompilerKit::kPefArch64000; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; +static Bool kVerbose = false; /* link is to be found, mld is to be found at runtime. */ -static const char *kLdDefineSymbol = ":UndefinedSymbol:"; -static const char *kLdDynamicSym = ":RuntimeSymbol:"; +static const char* kLdDefineSymbol = ":UndefinedSymbol:"; +static const char* kLdDynamicSym = ":RuntimeSymbol:"; /* object code and list. */ static std::vector kObjectList; -static std::vector kObjectBytes; +static std::vector kObjectBytes; -#define kPrintF printf +#define kPrintF printf #define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) -MPCC_MODULE(NewOSLinker) { - bool is_executable = true; +NDK_MODULE(NewOSLinker) +{ + bool is_executable = true; - /** + /** * @brief parse flags and such. * */ - for (size_t i = 1; i < argc; ++i) { - if (StringCompare(argv[i], "-h") == 0) { - kLinkerSplash(); - kStdOut << "-version: Show program version.\n"; - kStdOut << "-verbose: Enable program trace.\n"; - kStdOut << "-shared: Output as a shared PEF.\n"; - kStdOut << "-fat-bin: Output as a FAT PEF.\n"; - kStdOut << "-32x0: Output as a 32x0 PEF.\n"; - kStdOut << "-64x0: Output as a 64x0 PEF.\n"; - kStdOut << "-amd64: Output as a AMD64 PEF.\n"; - kStdOut << "-rv64: Output as a RISC-V PEF.\n"; - kStdOut << "-power64: Output as a POWER PEF.\n"; - kStdOut << "-arm64: Output as a ARM64 PEF.\n"; - kStdOut << "-output-file: Select the output file name.\n"; - - return 0; - } else if (StringCompare(argv[i], "-v") == 0) { - kLinkerSplash(); - return 0; - } else if (StringCompare(argv[i], "-fat-bin") == 0) { - kFatBinaryEnable = true; - - continue; - } else if (StringCompare(argv[i], "-64x0") == 0) { - kArch = CompilerKit::kPefArch64000; - - continue; - } else if (StringCompare(argv[i], "-amd64") == 0) { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } else if (StringCompare(argv[i], "-32x0") == 0) { - kArch = CompilerKit::kPefArch32000; - - continue; - } else if (StringCompare(argv[i], "-power64") == 0) { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } else if (StringCompare(argv[i], "-arm64") == 0) { - kArch = CompilerKit::kPefArchARM64; - - continue; - } else if (StringCompare(argv[i], "-verbose") == 0) { - kVerbose = true; - - continue; - } else if (StringCompare(argv[i], "-shared") == 0) { - if (kOutput.empty()) { - continue; - } - - if (kOutput.find(kPefExt) != std::string::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } else if (StringCompare(argv[i], "-output-file") == 0) { - kOutput = argv[i + 1]; - ++i; - - continue; - } else { - if (argv[i][0] == '-') { - kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return MPCC_EXEC_ERROR; - } - - kObjectList.emplace_back(argv[i]); - - continue; - } - } - - if (kOutput.empty()) { - kStdOut << "link: no output filename set." << std::endl; - return MPCC_EXEC_ERROR; - } - - // sanity check. - if (kObjectList.empty()) { - kStdOut << "link: no input files." << std::endl; - return MPCC_EXEC_ERROR; - } else { - namespace fs = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto &obj : kObjectList) { - if (!fs::exists(obj)) { - // if filesystem doesn't find file - // -> throw error. - kStdOut << "link: no such file: " << obj << std::endl; - return MPCC_EXEC_ERROR; - } - } - } - - // PEF expects a valid architecture when outputing a binary. - if (kArch == 0) { - kStdOut << "link: no target architecture set, can't continue." << std::endl; - return MPCC_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = CompilerKit::kPefKindExec; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Zeta Electronics Corporation Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - - std::ofstream outputFc(kOutput, std::ofstream::binary); - - if (outputFc.bad()) { - if (kVerbose) { - kStdOut << "link: error: " << strerror(errno) << "\n"; - } - - return MPCC_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector commandHdrsList; - CompilerKit::Utils::AEReadableProtocol readProto{}; - - for (const auto &i : kObjectList) { - if (!std::filesystem::exists(i)) continue; - - CompilerKit::AEHeader hdr{}; - - readProto.FP = std::ifstream(i, std::ifstream::binary); - readProto.FP >> hdr; - - auto ae_header = hdr; - - if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && - ae_header.fSize == sizeof(CompilerKit::AEHeader)) { - if (ae_header.fArch != kArch) { - if (kVerbose) kStdOut << "link: info: is this a FAT binary? : "; - - if (!kFatBinaryEnable) { - if (kVerbose) kStdOut << "No.\n"; - - kStdOut << "link: error: object " << i - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - std::remove(kOutput.c_str()); - return MPCC_FAT_ERROR; - } else { - if (kVerbose) { - kStdOut << "Yes.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= ae_header.fArch; - std::size_t cnt = ae_header.fCount; - - if (kVerbose) - kStdOut << "link: object header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - char_type *raw_ae_records = - new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; - memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto *ae_records = readProto.Read(raw_ae_records, cnt); - for (size_t ae_record_index = 0; ae_record_index < cnt; - ++ae_record_index) { - CompilerKit::PEFCommandHeader command_header{0}; - size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; - - memcpy(command_header.Name, ae_records[ae_record_index].fName, - kPefNameLen); - - // check this header if it's any valid. - if (std::string(command_header.Name).find(".code64") == - std::string::npos && - std::string(command_header.Name).find(".data64") == - std::string::npos && - std::string(command_header.Name).find(".zero64") == - std::string::npos) { - if (std::string(command_header.Name).find(kPefStart) == - std::string::npos && - *command_header.Name == 0) { - if (std::string(command_header.Name).find(kLdDefineSymbol) != - std::string::npos) { - goto ld_mark_header; - } else { - continue; - } - } - } - - if (std::string(command_header.Name).find(kPefStart) != - std::string::npos && - std::string(command_header.Name).find(".code64") != - std::string::npos) { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offsetOfData; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; - command_header.Cpu = ae_header.fArch; - command_header.SubCpu = ae_header.fSubArch; - - if (kVerbose) { - kStdOut << "link: object record: " - << ae_records[ae_record_index].fName << " was marked.\n"; - - kStdOut << "link: object record offset: " << command_header.Offset << "\n"; - } - - commandHdrsList.emplace_back(command_header); - } - - delete[] raw_ae_records; - - std::vector bytes; - bytes.resize(ae_header.fCodeSize); - - readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); - readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); - - for (auto &byte : bytes) { - kObjectBytes.push_back(byte); - } - - readProto.FP.close(); - - continue; - } - - kStdOut << "link: not an object: " << i << std::endl; - std::remove(kOutput.c_str()); - - // don't continue, it is a fatal error. - return MPCC_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - outputFc << pef_container; - - if (kVerbose) { - kStdOut << "link: wrote container header.\n"; - } - - outputFc.seekp(std::streamsize(pef_container.HdrSz)); + for (size_t i = 1; i < argc; ++i) + { + if (StringCompare(argv[i], "/help") == 0) + { + kLinkerSplash(); + kStdOut << "/version: Show linker version.\n"; + kStdOut << "/help: Show linker help.\n"; + kStdOut << "/verbose: Enable linker trace.\n"; + kStdOut << "/shared: Output as a shared PEF.\n"; + kStdOut << "/fat-bin: Output as a FAT PEF.\n"; + kStdOut << "/32x0: Output as a 32x0 PEF.\n"; + kStdOut << "/64x0: Output as a 64x0 PEF.\n"; + kStdOut << "/amd64: Output as a AMD64 PEF.\n"; + kStdOut << "/rv64: Output as a RISC-V PEF.\n"; + kStdOut << "/power64: Output as a POWER PEF.\n"; + kStdOut << "/arm64: Output as a ARM64 PEF.\n"; + kStdOut << "/output-file: Select the output file name.\n"; + + return 0; + } + else if (StringCompare(argv[i], "/version") == 0) + { + kLinkerSplash(); + return 0; + } + else if (StringCompare(argv[i], "/fat-bin") == 0) + { + kFatBinaryEnable = true; + + continue; + } + else if (StringCompare(argv[i], "/64x0") == 0) + { + kArch = CompilerKit::kPefArch64000; + + continue; + } + else if (StringCompare(argv[i], "/amd64") == 0) + { + kArch = CompilerKit::kPefArchAMD64; + + continue; + } + else if (StringCompare(argv[i], "/32x0") == 0) + { + kArch = CompilerKit::kPefArch32000; + + continue; + } + else if (StringCompare(argv[i], "/power64") == 0) + { + kArch = CompilerKit::kPefArchPowerPC; + + continue; + } + else if (StringCompare(argv[i], "/arm64") == 0) + { + kArch = CompilerKit::kPefArchARM64; + + continue; + } + else if (StringCompare(argv[i], "/verbose") == 0) + { + kVerbose = true; + + continue; + } + else if (StringCompare(argv[i], "/shared") == 0) + { + if (kOutput.empty()) + { + continue; + } + + if (kOutput.find(kPefExt) != std::string::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } + else if (StringCompare(argv[i], "/output-file") == 0) + { + kOutput = argv[i + 1]; + ++i; + + continue; + } + else + { + if (argv[i][0] == '/') + { + kStdOut << "link: unknown flag: " << argv[i] << "\n"; + return MPCC_EXEC_ERROR; + } + + kObjectList.emplace_back(argv[i]); + + continue; + } + } + + if (kOutput.empty()) + { + kStdOut << "link: no output filename set." << std::endl; + return MPCC_EXEC_ERROR; + } + + // sanity check. + if (kObjectList.empty()) + { + kStdOut << "link: no input files." << std::endl; + return MPCC_EXEC_ERROR; + } + else + { + namespace fs = std::filesystem; + + // check for existing files, if they don't throw an error. + for (auto& obj : kObjectList) + { + if (!fs::exists(obj)) + { + // if filesystem doesn't find file + // -> throw error. + kStdOut << "link: no such file: " << obj << std::endl; + return MPCC_EXEC_ERROR; + } + } + } + + // PEF expects a valid architecture when outputing a binary. + if (kArch == 0) + { + kStdOut << "link: no target architecture set, can't continue." << std::endl; + return MPCC_EXEC_ERROR; + } + + CompilerKit::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = CompilerKit::kPefKindExec; + pef_container.SubCpu = kSubArch; + pef_container.Linker = kLinkerId; // Zeta Electronics Corporation Linker + pef_container.Abi = kAbi; // Multi-Processor UX ABI + pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; + pef_container.Magic[1] = kPefMagic[1]; + pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; + pef_container.Magic[3] = kPefMagic[3]; + pef_container.Version = kPefVersion; + + // specify the start address, can be 0x10000 + pef_container.Start = kLinkerDefaultOrigin; + pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); + + std::ofstream outputFc(kOutput, std::ofstream::binary); + + if (outputFc.bad()) + { + if (kVerbose) + { + kStdOut << "link: error: " << strerror(errno) << "\n"; + } + + return MPCC_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector commandHdrsList; + CompilerKit::Utils::AEReadableProtocol readProto{}; + + for (const auto& i : kObjectList) + { + if (!std::filesystem::exists(i)) + continue; + + CompilerKit::AEHeader hdr{}; + + readProto.FP = std::ifstream(i, std::ifstream::binary); + readProto.FP >> hdr; + + auto ae_header = hdr; + + if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && + ae_header.fSize == sizeof(CompilerKit::AEHeader)) + { + if (ae_header.fArch != kArch) + { + if (kVerbose) + kStdOut << "link: info: is this a FAT binary? : "; + + if (!kFatBinaryEnable) + { + if (kVerbose) + kStdOut << "No.\n"; + + kStdOut << "link: error: object " << i + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + std::remove(kOutput.c_str()); + return MPCC_FAT_ERROR; + } + else + { + if (kVerbose) + { + kStdOut << "Yes.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= ae_header.fArch; + std::size_t cnt = ae_header.fCount; + + if (kVerbose) + kStdOut << "link: object header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = + new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); + + auto* ae_records = readProto.Read(raw_ae_records, cnt); + for (size_t ae_record_index = 0; ae_record_index < cnt; + ++ae_record_index) + { + CompilerKit::PEFCommandHeader command_header{0}; + size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; + + memcpy(command_header.Name, ae_records[ae_record_index].fName, + kPefNameLen); + + // check this header if it's any valid. + if (std::string(command_header.Name).find(".code64") == + std::string::npos && + std::string(command_header.Name).find(".data64") == + std::string::npos && + std::string(command_header.Name).find(".zero64") == + std::string::npos) + { + if (std::string(command_header.Name).find(kPefStart) == + std::string::npos && + *command_header.Name == 0) + { + if (std::string(command_header.Name).find(kLdDefineSymbol) != + std::string::npos) + { + goto ld_mark_header; + } + else + { + continue; + } + } + } + + if (std::string(command_header.Name).find(kPefStart) != + std::string::npos && + std::string(command_header.Name).find(".code64") != + std::string::npos) + { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offsetOfData; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = ae_header.fArch; + command_header.SubCpu = ae_header.fSubArch; + + if (kVerbose) + { + kStdOut << "link: object record: " + << ae_records[ae_record_index].fName << " was marked.\n"; + + kStdOut << "link: object record offset: " << command_header.Offset << "\n"; + } + + commandHdrsList.emplace_back(command_header); + } + + delete[] raw_ae_records; + + std::vector bytes; + bytes.resize(ae_header.fCodeSize); + + readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); + readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); + + for (auto& byte : bytes) + { + kObjectBytes.push_back(byte); + } + + readProto.FP.close(); + + continue; + } + + kStdOut << "link: not an object: " << i << std::endl; + std::remove(kOutput.c_str()); + + // don't continue, it is a fatal error. + return MPCC_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + outputFc << pef_container; + + if (kVerbose) + { + kStdOut << "link: wrote container header.\n"; + } + + outputFc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector not_found; + std::vector symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& commandHdr : commandHdrsList) + { + // check if this symbol needs to be resolved. + if (std::string(commandHdr.Name).find(kLdDefineSymbol) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; + + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it == not_found.end()) + { + not_found.emplace_back(commandHdr.Name); + } + } + + symbols.emplace_back(commandHdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); + ++not_found_idx) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdrsList[not_found_idx].Name)); + it != not_found.end()) + { + std::string symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) + continue; + + // erase the lookup prefix. + symbol_imp.erase( + 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != std::string::npos) + symbol_imp.erase(symbol_imp.find('$'), 1); + + // the reason we do is because, this may not match the symbol, and we need + // to look for other matching symbols. + for (auto& commandHdr : commandHdrsList) + { + if (std::string(commandHdr.Name).find(symbol_imp) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDefineSymbol) == + std::string::npos) + { + std::string undefined_symbol = commandHdr.Name; + auto result_of_sym = + undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - std::vector not_found; - std::vector symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - for (auto &commandHdr : commandHdrsList) { - // check if this symbol needs to be resolved. - if (std::string(commandHdr.Name).find(kLdDefineSymbol) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) { - if (kVerbose) - kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; - - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it == not_found.end()) { - not_found.emplace_back(commandHdr.Name); - } - } - - symbols.emplace_back(commandHdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); - ++not_found_idx) { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdrsList[not_found_idx].Name)); - it != not_found.end()) { - std::string symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) continue; - - // erase the lookup prefix. - symbol_imp.erase( - 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != std::string::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto &commandHdr : commandHdrsList) { - if (std::string(commandHdr.Name).find(symbol_imp) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDefineSymbol) == - std::string::npos) { - std::string undefined_symbol = commandHdr.Name; - auto result_of_sym = - undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) { - if (result_of_sym[i] != symbol_imp[i]) goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) - kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) { - if (kVerbose) - kStdOut - << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " - "against your compiler's runtime library.\n"; - - kStdOut << "link: undefined entrypoint " << kPefStart - << " for executable: " << kOutput << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader dateHeader{}; - - time_t timestamp = time(nullptr); - - std::string timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strcpy(dateHeader.Name, timeStampStr.c_str()); - - dateHeader.Flags = 0; - dateHeader.Kind = CompilerKit::kPefZero; - dateHeader.Offset = outputFc.tellp(); - dateHeader.Size = timeStampStr.size(); - - commandHdrsList.push_back(dateHeader); - - CompilerKit::PEFCommandHeader abiHeader{}; - - std::string abi = kLinkerAbiContainer; - - switch (kArch) { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "MHRA"; - break; - } - default: { - abi += " IDK"; - break; - } - } - - memcpy(abiHeader.Name, abi.c_str(), abi.size()); - - abiHeader.Size = abi.size(); - abiHeader.Offset = outputFc.tellp(); - abiHeader.Flags = 0; - abiHeader.Kind = CompilerKit::kPefLinkerID; - - commandHdrsList.push_back(abiHeader); - - CompilerKit::PEFCommandHeader uuidHeader{}; - - std::random_device rd; - - auto seedData = std::array{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), - uuidStr.size()); - - uuidHeader.Size = 16; - uuidHeader.Offset = outputFc.tellp(); - uuidHeader.Flags = 0; - uuidHeader.Kind = CompilerKit::kPefZero; - - commandHdrsList.push_back(uuidHeader); - - // prepare a symbol vector. - std::vector undefSymbols; - std::vector duplSymbols; - std::vector resolveSymbols; - - constexpr Int32 cPaddingOffset = 16; - - size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; - commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) { - if (std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - std::string symbolName = commandHdrsList[commandHeaderIndex].Name; - - if (!symbolName.empty()) { - undefSymbols.emplace_back(symbolName); - } - - commandHdrsList[commandHeaderIndex].Offset += previousOffset; - previousOffset += commandHdrsList[commandHeaderIndex].Size; - - std::string name = commandHdrsList[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kPefStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != std::string::npos && - name.find(".code64") != std::string::npos) { - pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; - auto tellCurPos = outputFc.tellp(); - - outputFc.seekp(0); - outputFc << pef_container; - - outputFc.seekp(tellCurPos); - } - - if (kVerbose) { - kStdOut << "link: command header name: " << - name << "\n"; - kStdOut << "link: real address of command header content: " << - commandHdrsList[commandHeaderIndex].Offset << "\n"; - } - - outputFc << commandHdrsList[commandHeaderIndex]; - - for (size_t subCommandHeaderIndex = 0UL; - subCommandHeaderIndex < commandHdrsList.size(); - ++subCommandHeaderIndex) { - if (subCommandHeaderIndex == commandHeaderIndex) continue; - - if (std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) { - if (kVerbose) { - kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto &commandHdr = commandHdrsList[subCommandHeaderIndex]; - - if (commandHdr.Name == - std::string(commandHdrsList[commandHeaderIndex].Name)) { - if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), - commandHdr.Name) == duplSymbols.cend()) { - duplSymbols.emplace_back(commandHdr.Name); - } - - if (kVerbose) - kStdOut << "link: found duplicate symbol: " << commandHdr.Name - << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!duplSymbols.empty()) { - for (auto &symbol : duplSymbols) { - kStdOut << "link: multiple symbols of " << symbol << ".\n"; - } - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto byte : kObjectBytes) { - outputFc << byte; - } - - if (kVerbose) kStdOut << "link: wrote contents of: " << kOutput << "\n"; - - // step 3: check if we have those symbols - - std::vector unrefSyms; - - for (auto &commandHdr : commandHdrsList) { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it != not_found.end()) { - unrefSyms.emplace_back(commandHdr.Name); - } - } - - if (!unrefSyms.empty()) { - for (auto &unreferenced_symbol : unrefSyms) { - kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; - } - } - - if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || - !unrefSyms.empty()) { - if (kVerbose) - kStdOut << "link: file: " << kOutput - << ", is corrupt, removing file...\n"; - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - return 0; + for (int i = 0; result_of_sym[i] != 0; ++i) + { + if (result_of_sym[i] != symbol_imp[i]) + goto ld_continue_search; + } + + not_found.erase(it); + + if (kVerbose) + kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) + { + if (kVerbose) + kStdOut + << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " + "against your compiler's runtime library.\n"; + + kStdOut << "link: undefined entrypoint " << kPefStart + << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + CompilerKit::PEFCommandHeader dateHeader{}; + + time_t timestamp = time(nullptr); + + std::string timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strcpy(dateHeader.Name, timeStampStr.c_str()); + + dateHeader.Flags = 0; + dateHeader.Kind = CompilerKit::kPefZero; + dateHeader.Offset = outputFc.tellp(); + dateHeader.Size = timeStampStr.size(); + + commandHdrsList.push_back(dateHeader); + + CompilerKit::PEFCommandHeader abiHeader{}; + + std::string abi = kLinkerAbiContainer; + + switch (kArch) + { + case CompilerKit::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case CompilerKit::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case CompilerKit::kPefArch32000: + case CompilerKit::kPefArch64000: { + abi += "MHRA"; + break; + } + default: { + abi += " IDK"; + break; + } + } + + memcpy(abiHeader.Name, abi.c_str(), abi.size()); + + abiHeader.Size = abi.size(); + abiHeader.Offset = outputFc.tellp(); + abiHeader.Flags = 0; + abiHeader.Kind = CompilerKit::kPefLinkerID; + + commandHdrsList.push_back(abiHeader); + + CompilerKit::PEFCommandHeader uuidHeader{}; + + std::random_device rd; + + auto seedData = std::array{}; + std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); + std::seed_seq seq(std::begin(seedData), std::end(seedData)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid id = gen(); + auto uuidStr = uuids::to_string(id); + + memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), + uuidStr.size()); + + uuidHeader.Size = 16; + uuidHeader.Offset = outputFc.tellp(); + uuidHeader.Flags = 0; + uuidHeader.Kind = CompilerKit::kPefZero; + + commandHdrsList.push_back(uuidHeader); + + // prepare a symbol vector. + std::vector undefSymbols; + std::vector duplSymbols; + std::vector resolveSymbols; + + constexpr Int32 cPaddingOffset = 16; + + size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; + commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) + { + if (std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + std::string symbolName = commandHdrsList[commandHeaderIndex].Name; + + if (!symbolName.empty()) + { + undefSymbols.emplace_back(symbolName); + } + + commandHdrsList[commandHeaderIndex].Offset += previousOffset; + previousOffset += commandHdrsList[commandHeaderIndex].Size; + + std::string name = commandHdrsList[commandHeaderIndex].Name; + + /// so this is valid when we get to the entrypoint. + /// it is always a code64 container. And should equal to kPefStart as well. + /// this chunk of code updates the pef_container.Start with the updated offset. + if (name.find(kPefStart) != std::string::npos && + name.find(".code64") != std::string::npos) + { + pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; + auto tellCurPos = outputFc.tellp(); + + outputFc.seekp(0); + outputFc << pef_container; + + outputFc.seekp(tellCurPos); + } + + if (kVerbose) + { + kStdOut << "link: command header name: " << name << "\n"; + kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; + } + + outputFc << commandHdrsList[commandHeaderIndex]; + + for (size_t subCommandHeaderIndex = 0UL; + subCommandHeaderIndex < commandHdrsList.size(); + ++subCommandHeaderIndex) + { + if (subCommandHeaderIndex == commandHeaderIndex) + continue; + + if (std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + { + kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; + + if (commandHdr.Name == + std::string(commandHdrsList[commandHeaderIndex].Name)) + { + if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), + commandHdr.Name) == duplSymbols.cend()) + { + duplSymbols.emplace_back(commandHdr.Name); + } + + if (kVerbose) + kStdOut << "link: found duplicate symbol: " << commandHdr.Name + << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!duplSymbols.empty()) + { + for (auto& symbol : duplSymbols) + { + kStdOut << "link: multiple symbols of " << symbol << ".\n"; + } + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + // step 2.5: write program bytes. + + for (auto byte : kObjectBytes) + { + outputFc << byte; + } + + if (kVerbose) + kStdOut << "link: wrote contents of: " << kOutput << "\n"; + + // step 3: check if we have those symbols + + std::vector unrefSyms; + + for (auto& commandHdr : commandHdrsList) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it != not_found.end()) + { + unrefSyms.emplace_back(commandHdr.Name); + } + } + + if (!unrefSyms.empty()) + { + for (auto& unreferenced_symbol : unrefSyms) + { + kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; + } + } + + if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || + !unrefSyms.empty()) + { + if (kVerbose) + kStdOut << "link: file: " << kOutput + << ", is corrupt, removing file...\n"; + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + return 0; } // Last rev 13-1-24 diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index a90c596..ac5d84b 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -1542,7 +1542,7 @@ static void cc_print_help() #define kExt ".c" -MPCC_MODULE(NewOSCompilerCLangPowerPC) +NDK_MODULE(NewOSCompilerCLangPowerPC) { kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index f8e47d7..0aec82d 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -108,26 +108,26 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssemblerPowerPC) { +NDK_MODULE(NewOSAssemblerPowerPC) { for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "ppcasm: POWER64/XEN Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " "2024 Zeta Electronics Corporation.\n"; return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "ppcasm: POWER64/XEN Assembler.\nppcasm: Copyright (c) 2024 " + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: Copyright (c) 2024 " "Zeta Electronics Corporation.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; + kStdOut << "/version,/v: print program version.\n"; + kStdOut << "/verbose: print verbose output.\n"; + kStdOut << "/binary: output as flat binary.\n"; return 0; - } else if (strcmp(argv[i], "-binary") == 0) { + } else if (strcmp(argv[i], "/binary") == 0) { kOutputAsBinary = true; continue; - } else if (strcmp(argv[i], "-verbose") == 0) { + } else if (strcmp(argv[i], "/verbose") == 0) { kVerbose = true; continue; } diff --git a/posix.make b/posix.make index bc8f81e..34fa367 100644 --- a/posix.make +++ b/posix.make @@ -10,40 +10,40 @@ COMMON_INC=-I./Comm -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 LINK_SRC=Sources/link.cc -LINK_OUTPUT=Output/link.exec -LINK_ALT_OUTPUT=Output/64link.exec -LINK_ALT_3_OUTPUT=Output/i64link.exec -LINK_ALT_2_OUTPUT=Output/32link.exec -LINK_ALT_4_OUTPUT=Output/ppclink.exec +LINK_OUTPUT=Output/link +LINK_ALT_OUTPUT=Output/64link +LINK_ALT_3_OUTPUT=Output/i64link +LINK_ALT_2_OUTPUT=Output/32link +LINK_ALT_4_OUTPUT=Output/ppclink PP_SRC=Sources/bpp.cc -PP_OUTPUT=Output/bpp.exec +PP_OUTPUT=Output/bpp SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc # C++ Compiler (AMD64) AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) -AMD64_CXX_OUTPUT=Output/cplusplus.exec +AMD64_CXX_OUTPUT=Output/cplusplus # C Compiler (POWER) 64X0_CC_SRC=Sources/64x0-cc.cc $(SRC_COMMON) -64X0_CC_OUTPUT=Output/64x0-cc.exec +64X0_CC_OUTPUT=Output/64x0-cc # C Compiler (Our own RISC) PPC_CC_SRC=Sources/power-cc.cc $(SRC_COMMON) -PPC_CC_OUTPUT=Output/power-cc.exec +PPC_CC_OUTPUT=Output/power-cc # 64x0 Assembler (Our Own RISC) ASM_SRC=Sources/64asm.cc $(SRC_COMMON) -ASM_OUTPUT=Output/64asm.exec +ASM_OUTPUT=Output/64asm # AMD64 Assembler (Intel CISC) IASM_SRC=Sources/i64asm.cc $(SRC_COMMON) -IASM_OUTPUT=Output/i64asm.exec +IASM_OUTPUT=Output/i64asm # Power4 Assembler (IBM RISC) PPCASM_SRC=Sources/ppcasm.cc $(SRC_COMMON) -PPCASM_OUTPUT=Output/ppcasm.exec +PPCASM_OUTPUT=Output/ppcasm .PHONY: all all: pre-processor compiler linker @@ -72,8 +72,8 @@ linker: .PHONY: help help: - @echo "Compiler - Zeta Electronics Corporation Compiler Suite." - @echo "Preprocessor - Zeta Electronics Corporation Preprocessor Suite." + @echo "compiler - Zeta Electronics Corporation Compiler Suite." + @echo "pre-processor - Zeta Electronics Corporation Preprocessor Suite." @echo "linker - Zeta Electronics Corporation Linkers." @echo "clean - Clean objects and executables." @@ -86,7 +86,5 @@ clean: rm -f $(IASM_OUTPUT) rm -f $(LINK_OUTPUT) rm -rf *.obj - rm -rf Output/*.exec - rm -rf *.exec # Last rev 8-1-24 -- cgit v1.2.3 From 6653cfe50690dc4f53c8bec30cdb7d40ef9b62a4 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 12 Jul 2024 04:33:08 +0200 Subject: [IMP] Needs to be merged with stable. Signed-off-by: Amlal El Mahrouss --- Comm/AsmKit/AsmKit.hpp | 2 +- Comm/AsmKit/CPU/32x0.hpp | 2 +- Comm/AsmKit/CPU/64x0.hpp | 2 +- Comm/AsmKit/CPU/amd64.hpp | 2 +- Comm/AsmKit/CPU/arm64.hpp | 3 +-- Comm/AsmKit/CPU/ppc.hpp | 4 ++-- Comm/CompilerKit.hpp | 2 +- Comm/Defines.hpp | 2 +- Comm/ParserKit.hpp | 2 +- Comm/Public/SDK/CRT/__mpcc_alloca.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_defines.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_exception.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_hint.hxx | 2 +- Comm/Public/SDK/CRT/__mpcc_malloc.hxx | 2 +- Comm/StdKit/AE.hpp | 2 +- Comm/StdKit/ErrorID.hpp | 2 +- Comm/StdKit/ErrorOr.hpp | 2 +- Comm/StdKit/PEF.hpp | 2 +- Comm/StdKit/Ref.hpp | 4 ++-- Comm/StdKit/String.hpp | 2 +- Comm/StdKit/XCOFF.hxx | 2 +- Doc/Inside 64x0.pdf | Bin 64675 -> 0 bytes Doc/asm-specs.txt | 11 ----------- Doc/havp.txt | 13 ------------- Doc/notice.txt | 4 ---- Doc/vnrp.txt | 17 ----------------- Icons/app-logo.ico | Bin 4865 -> 0 bytes Notes/Inside 64x0.pdf | Bin 0 -> 64675 bytes Notes/asm-specs.txt | 11 +++++++++++ Notes/havp.txt | 13 +++++++++++++ Notes/notice.txt | 4 ++++ Notes/vnrp.txt | 17 +++++++++++++++++ ReadMe.md | 7 +++++-- Sources/32asm.cc | 4 ++-- Sources/64asm.cc | 4 ++-- Sources/64x0-cc.cc | 6 +++--- Sources/AssemblyFactory.cc | 4 ++-- Sources/Detail/asmutils.hxx | 2 +- Sources/Detail/compilerutils.hxx | 2 +- Sources/String.cc | 4 ++-- Sources/bpp.cc | 6 +++--- Sources/coff2ae.cc | 2 +- Sources/cplusplus.cc | 6 +++--- Sources/elf2ae.cc | 2 +- Sources/i64asm.cc | 6 +++--- Sources/link.cc | 8 ++++---- Sources/power-cc.cc | 4 ++-- Sources/ppcasm.cc | 6 +++--- posix.make | 8 ++++---- win64.make | 8 ++++---- 50 files changed, 114 insertions(+), 112 deletions(-) delete mode 100644 Doc/Inside 64x0.pdf delete mode 100644 Doc/asm-specs.txt delete mode 100644 Doc/havp.txt delete mode 100644 Doc/notice.txt delete mode 100644 Doc/vnrp.txt delete mode 100644 Icons/app-logo.ico create mode 100644 Notes/Inside 64x0.pdf create mode 100644 Notes/asm-specs.txt create mode 100644 Notes/havp.txt create mode 100644 Notes/notice.txt create mode 100644 Notes/vnrp.txt (limited to 'Sources') diff --git a/Comm/AsmKit/AsmKit.hpp b/Comm/AsmKit/AsmKit.hpp index 6fbacfa..38b418c 100644 --- a/Comm/AsmKit/AsmKit.hpp +++ b/Comm/AsmKit/AsmKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/32x0.hpp b/Comm/AsmKit/CPU/32x0.hpp index e469dda..7b93a94 100644 --- a/Comm/AsmKit/CPU/32x0.hpp +++ b/Comm/AsmKit/CPU/32x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/64x0.hpp b/Comm/AsmKit/CPU/64x0.hpp index 10d12d8..b8bafb9 100644 --- a/Comm/AsmKit/CPU/64x0.hpp +++ b/Comm/AsmKit/CPU/64x0.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/amd64.hpp b/Comm/AsmKit/CPU/amd64.hpp index 17b515b..06dc1da 100644 --- a/Comm/AsmKit/CPU/amd64.hpp +++ b/Comm/AsmKit/CPU/amd64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/AsmKit/CPU/arm64.hpp b/Comm/AsmKit/CPU/arm64.hpp index a6b558a..8dd5204 100644 --- a/Comm/AsmKit/CPU/arm64.hpp +++ b/Comm/AsmKit/CPU/arm64.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- -Copyright Zeta Electronics Corporation +Copyright ZKA Technologies ------------------------------------------- */ @@ -24,4 +24,3 @@ struct CpuOpcodeArm64 final uint32_t fImmediateValue; // immediate 32-bit value bool fImmediateValueHooked; }; - diff --git a/Comm/AsmKit/CPU/ppc.hpp b/Comm/AsmKit/CPU/ppc.hpp index 4afbf5a..e3ea6c5 100644 --- a/Comm/AsmKit/CPU/ppc.hpp +++ b/Comm/AsmKit/CPU/ppc.hpp @@ -1,7 +1,7 @@ /* ------------------------------------------- - Some modifications are copyrighted under: - Zeta Electronics Corporation + Some modifications are copyrighted under: + ZKA Technologies Original author: Apple Inc diff --git a/Comm/CompilerKit.hpp b/Comm/CompilerKit.hpp index 25a1e66..177e424 100644 --- a/Comm/CompilerKit.hpp +++ b/Comm/CompilerKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Defines.hpp b/Comm/Defines.hpp index a6f0260..31c1998 100644 --- a/Comm/Defines.hpp +++ b/Comm/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/ParserKit.hpp b/Comm/ParserKit.hpp index bc0ab54..4c3f483 100644 --- a/Comm/ParserKit.hpp +++ b/Comm/ParserKit.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx index 19ebaaf..02b3123 100644 --- a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_defines.hxx b/Comm/Public/SDK/CRT/__mpcc_defines.hxx index a526fd3..19ed8a4 100644 --- a/Comm/Public/SDK/CRT/__mpcc_defines.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_exception.hxx b/Comm/Public/SDK/CRT/__mpcc_exception.hxx index a2539eb..4a9f84a 100644 --- a/Comm/Public/SDK/CRT/__mpcc_exception.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_exception.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_hint.hxx b/Comm/Public/SDK/CRT/__mpcc_hint.hxx index db58203..02dbc94 100644 --- a/Comm/Public/SDK/CRT/__mpcc_hint.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_hint.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx index db3075f..eeaa67b 100644 --- a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx +++ b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/StdKit/AE.hpp b/Comm/StdKit/AE.hpp index d06a8ca..ee39e56 100644 --- a/Comm/StdKit/AE.hpp +++ b/Comm/StdKit/AE.hpp @@ -2,7 +2,7 @@ * ======================================================== * * MPCC - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/ErrorID.hpp b/Comm/StdKit/ErrorID.hpp index 698b66b..abaac85 100644 --- a/Comm/StdKit/ErrorID.hpp +++ b/Comm/StdKit/ErrorID.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/ErrorOr.hpp b/Comm/StdKit/ErrorOr.hpp index 04f013d..4097cc9 100644 --- a/Comm/StdKit/ErrorOr.hpp +++ b/Comm/StdKit/ErrorOr.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/PEF.hpp b/Comm/StdKit/PEF.hpp index 911d903..85044b2 100644 --- a/Comm/StdKit/PEF.hpp +++ b/Comm/StdKit/PEF.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Comm/StdKit/Ref.hpp b/Comm/StdKit/Ref.hpp index 3ccb983..e655ccb 100644 --- a/Comm/StdKit/Ref.hpp +++ b/Comm/StdKit/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -12,7 +12,7 @@ namespace CompilerKit { - // @author Zeta Electronics Corporation + // @author ZKA Technologies // @brief Reference class, refers to a pointer of data in static memory. template class Ref final diff --git a/Comm/StdKit/String.hpp b/Comm/StdKit/String.hpp index e495219..7e62bc5 100644 --- a/Comm/StdKit/String.hpp +++ b/Comm/StdKit/String.hpp @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ diff --git a/Comm/StdKit/XCOFF.hxx b/Comm/StdKit/XCOFF.hxx index 7e57514..4b25484 100644 --- a/Comm/StdKit/XCOFF.hxx +++ b/Comm/StdKit/XCOFF.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies File: XCOFF.hpp Purpose: XCOFF for NewOS. diff --git a/Doc/Inside 64x0.pdf b/Doc/Inside 64x0.pdf deleted file mode 100644 index bcd6782..0000000 Binary files a/Doc/Inside 64x0.pdf and /dev/null differ diff --git a/Doc/asm-specs.txt b/Doc/asm-specs.txt deleted file mode 100644 index a0c42bf..0000000 --- a/Doc/asm-specs.txt +++ /dev/null @@ -1,11 +0,0 @@ -==================== -X86 ASSEMBLER SPECS -==================== - -WHAT TO DO: - Provide a complete support of x86-64 with: - - - org directive. - - 64-bit and 32-bit registers. - - basic instructions (load, store, jump to) - - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Doc/havp.txt b/Doc/havp.txt deleted file mode 100644 index 12fcec5..0000000 --- a/Doc/havp.txt +++ /dev/null @@ -1,13 +0,0 @@ -HAVP - Harvard Audio/Video Processor - -- Encoding: IBAD - -- Data path = 24 - - 16: sound data - - 8: information data - -- Register size: 32 -- Store strategy: shift registers. -- Standard registers: [ r0, r9 ] -- Floating point registers: [ f0, f2 ] -- Builtin SRAM: 512kb diff --git a/Doc/notice.txt b/Doc/notice.txt deleted file mode 100644 index 23691da..0000000 --- a/Doc/notice.txt +++ /dev/null @@ -1,4 +0,0 @@ -The X64000 draft papers -They contain thing that might appear through the next iteration of 64k. - -Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Doc/vnrp.txt b/Doc/vnrp.txt deleted file mode 100644 index e17b494..0000000 --- a/Doc/vnrp.txt +++ /dev/null @@ -1,17 +0,0 @@ -VNRP - Von Neumann, RISC Processor - -- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs - -- Data path = 128-bit (register data) -- Addressing = 58-bit physical address size. - -- Registers (128-bit) = r0, r19 -- Float/Vector registers (128-bit) = f0, f9 - -- Out of order (superscalar also added to the equation) = Yes -- Superscalar = Yes - -- L1 cache: 16kb (8 instr, 8 data) -- L2 cache: 1024kb (512 instr, 512 data) - -- Clock speed: 1 Ghz diff --git a/Icons/app-logo.ico b/Icons/app-logo.ico deleted file mode 100644 index 2ab3d5b..0000000 Binary files a/Icons/app-logo.ico and /dev/null differ diff --git a/Notes/Inside 64x0.pdf b/Notes/Inside 64x0.pdf new file mode 100644 index 0000000..bcd6782 Binary files /dev/null and b/Notes/Inside 64x0.pdf differ diff --git a/Notes/asm-specs.txt b/Notes/asm-specs.txt new file mode 100644 index 0000000..a0c42bf --- /dev/null +++ b/Notes/asm-specs.txt @@ -0,0 +1,11 @@ +==================== +X86 ASSEMBLER SPECS +==================== + +WHAT TO DO: + Provide a complete support of x86-64 with: + + - org directive. + - 64-bit and 32-bit registers. + - basic instructions (load, store, jump to) + - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Notes/havp.txt b/Notes/havp.txt new file mode 100644 index 0000000..12fcec5 --- /dev/null +++ b/Notes/havp.txt @@ -0,0 +1,13 @@ +HAVP - Harvard Audio/Video Processor + +- Encoding: IBAD + +- Data path = 24 + - 16: sound data + - 8: information data + +- Register size: 32 +- Store strategy: shift registers. +- Standard registers: [ r0, r9 ] +- Floating point registers: [ f0, f2 ] +- Builtin SRAM: 512kb diff --git a/Notes/notice.txt b/Notes/notice.txt new file mode 100644 index 0000000..23691da --- /dev/null +++ b/Notes/notice.txt @@ -0,0 +1,4 @@ +The X64000 draft papers +They contain thing that might appear through the next iteration of 64k. + +Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Notes/vnrp.txt b/Notes/vnrp.txt new file mode 100644 index 0000000..e17b494 --- /dev/null +++ b/Notes/vnrp.txt @@ -0,0 +1,17 @@ +VNRP - Von Neumann, RISC Processor + +- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs + +- Data path = 128-bit (register data) +- Addressing = 58-bit physical address size. + +- Registers (128-bit) = r0, r19 +- Float/Vector registers (128-bit) = f0, f9 + +- Out of order (superscalar also added to the equation) = Yes +- Superscalar = Yes + +- L1 cache: 16kb (8 instr, 8 data) +- L2 cache: 1024kb (512 instr, 512 data) + +- Clock speed: 1 Ghz diff --git a/ReadMe.md b/ReadMe.md index ae705e2..60e7433 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,16 +1,19 @@ # NDK +## Install + Start by cloning the repo: ``` git clone git@bitbucket.org:mahrouss/codetools.git ``` -and +And then: ``` make -f .make all ``` +You can now use the programs. -##### Copyright Zeta Electronics Corporation, all rights reserved. +##### Copyright ZKA Technologies, all rights reserved. diff --git a/Sources/32asm.cc b/Sources/32asm.cc index b043447..d32ab0b 100644 --- a/Sources/32asm.cc +++ b/Sources/32asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 32asm.cxx -// @author Zeta Electronics Corporation +// @author ZKA Technologies // @brief 32x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 384a086..0a89e6a 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ @@ -110,7 +110,7 @@ NDK_MODULE(NewOSAssembler64000) { if (argv[i][0] == '-') { if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 Zeta Electronics Corporation.\n"; + "ZKA Technologies.\n"; return 0; } else if (strcmp(argv[i], "-h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc index 9f73b1b..efbf68f 100644 --- a/Sources/64x0-cc.cc +++ b/Sources/64x0-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -25,7 +25,7 @@ /* C driver */ /* This is part of the NDK. */ -/* (c) Zeta Electronics Corporation */ +/* (c) ZKA Technologies */ /// @author Amlal El Mahrouss (amlel) /// @file 64x0-cc.cc @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "Zeta C Driver, %s, (c) Zeta Electronics Corporation\n", kDistVersion) + kPrintF(kWhite "Zeta C Driver, %s, (c) ZKA Technologies\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc index faa4847..35d8cbd 100644 --- a/Sources/AssemblyFactory.cc +++ b/Sources/AssemblyFactory.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ @@ -14,7 +14,7 @@ * @version 0.1 * @date 2024-01-27 * - * @copyright Copyright (c) 2024, Zeta Electronics Corporation + * @copyright Copyright (c) 2024, ZKA Technologies * */ diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index c531126..00bfbd7 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index fdcf141..4c46727 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Sources/String.cc b/Sources/String.cc index c7185ca..accc1af 100644 --- a/Sources/String.cc +++ b/Sources/String.cc @@ -2,7 +2,7 @@ * ======================================================== * * CompilerKit - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -14,7 +14,7 @@ * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 Zeta Electronics Corporation + * @copyright Copyright (c) ZKA Technologies * */ diff --git a/Sources/bpp.cc b/Sources/bpp.cc index d703748..1aefc33 100644 --- a/Sources/bpp.cc +++ b/Sources/bpp.cc @@ -2,7 +2,7 @@ * ======================================================== * * bpp - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -812,12 +812,12 @@ NDK_MODULE(NewOSPreprocessor) { if (argv[index][0] == '/') { if (strcmp(argv[index], "/version") == 0) { - printf("%s\n", "bpp v1.11, (c) Zeta Electronics Corporation"); + printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); return 0; } if (strcmp(argv[index], "/help") == 0) { - printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) Zeta Electronics Corporation"); + printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) ZKA Technologies"); printf("%s\n", "/working-dir : set directory to working path."); printf("%s\n", "/include-dir : add directory to include path."); printf("%s\n", "/def : def macro."); diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc index 0bf17e6..71f5bba 100644 --- a/Sources/coff2ae.cc +++ b/Sources/coff2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc index 59b5dcf..4059413 100644 --- a/Sources/cplusplus.cc +++ b/Sources/cplusplus.cc @@ -2,7 +2,7 @@ * ======================================================== * * cplusplus - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -32,9 +32,9 @@ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all #define kOk 0 -/* Zeta Electronics Corporation C++ driver */ +/* ZKA Technologies C++ driver */ /* This is part of ZECC C++ compiler. */ -/* (c) Zeta Electronics Corporation */ +/* (c) ZKA Technologies */ /// @author Amlal El Mahrouss (amlel) /// @file cc.cc diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc index ede28a2..70ab104 100644 --- a/Sources/elf2ae.cc +++ b/Sources/elf2ae.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index f0dd459..c0dd351 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ @@ -175,13 +175,13 @@ NDK_MODULE(NewOSAssemblerAMD64) if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 Zeta Electronics Corporation.\n"; + "(c) ZKA Technologies.\n"; return 0; } else if (strcmp(argv[i], "/h") == 0) { kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " - "Zeta Electronics Corporation.\n"; + "ZKA Technologies.\n"; kStdOut << "/version: Print program version.\n"; kStdOut << "/verbose: Print verbose output.\n"; kStdOut << "/binary: Output as flat binary.\n"; diff --git a/Sources/link.cc b/Sources/link.cc index 0114484..d94cbf1 100644 --- a/Sources/link.cc +++ b/Sources/link.cc @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ /// @file link.cc /// @author Amlal EL Mahrouss (amlel) -/// @brief Zeta Electronics Corporation Linker. +/// @brief ZKA Technologies Linker. /// Last Rev: Sat Feb 24 CET 2024 @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Zeta Linker Driver %s, (c) Zeta Electronics Corporation 2024, all rights reserved.\n" +#define kLinkerVersion "Zeta Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -229,7 +229,7 @@ NDK_MODULE(NewOSLinker) pef_container.Count = 0UL; pef_container.Kind = CompilerKit::kPefKindExec; pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Zeta Electronics Corporation Linker + pef_container.Linker = kLinkerId; // ZKA Technologies Linker pef_container.Abi = kAbi; // Multi-Processor UX ABI pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; pef_container.Magic[1] = kPefMagic[1]; diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc index ac5d84b..332fa53 100644 --- a/Sources/power-cc.cc +++ b/Sources/power-cc.cc @@ -2,7 +2,7 @@ * ======================================================== * * cc - * Copyright Zeta Electronics Corporation, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -1531,7 +1531,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Zeta Electronics Corporation\n", kDistVersion) + kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index 0aec82d..5f015d5 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Zeta Electronics Corporation + Copyright ZKA Technologies ------------------------------------------- */ @@ -114,11 +114,11 @@ NDK_MODULE(NewOSAssemblerPowerPC) { if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: " << kDistVersion << "\nppcasm: " "Copyright (c) " - "2024 Zeta Electronics Corporation.\n"; + "ZKA Technologies.\n"; return 0; } else if (strcmp(argv[i], "/h") == 0) { kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: Copyright (c) 2024 " - "Zeta Electronics Corporation.\n"; + "ZKA Technologies.\n"; kStdOut << "/version,/v: print program version.\n"; kStdOut << "/verbose: print verbose output.\n"; kStdOut << "/binary: output as flat binary.\n"; diff --git a/posix.make b/posix.make index 34fa367..8a17a58 100644 --- a/posix.make +++ b/posix.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright Zeta Electronics Corporation, all rights reserved. + # Copyright ZKA Technologies, all rights reserved. # # ======================================================== # @@ -72,9 +72,9 @@ linker: .PHONY: help help: - @echo "compiler - Zeta Electronics Corporation Compiler Suite." - @echo "pre-processor - Zeta Electronics Corporation Preprocessor Suite." - @echo "linker - Zeta Electronics Corporation Linkers." + @echo "compiler - ZKA Technologies Compiler Suite." + @echo "pre-processor - ZKA Technologies Preprocessor Suite." + @echo "linker - ZKA Technologies Linkers." @echo "clean - Clean objects and executables." .PHONY: clean diff --git a/win64.make b/win64.make index 8493db6..37d762a 100644 --- a/win64.make +++ b/win64.make @@ -2,7 +2,7 @@ # ======================================================== # # MPCC - # Copyright Zeta Electronics Corporation, all rights reserved. + # Copyright ZKA Technologies, all rights reserved. # # ======================================================== # @@ -70,9 +70,9 @@ linker: .PHONY: help help: - @echo "Compiler - MPCC Compiler Suite." - @echo "Preprocessor - MPCC Preprocessor Suite." - @echo "linker - Zeta Electronics Corporation Linkers." + @echo "compiler - ZKA Compiler Suite." + @echo "pre-processor - ZKA Preprocessor Suite." + @echo "linker - ZKA Linkers." @echo "clean - Clean objects and executables." .PHONY: clean -- cgit v1.2.3 From d764e44d4b43392a86a1c7c0ab1ad455fafc3294 Mon Sep 17 00:00:00 2001 From: Amlal Date: Wed, 17 Jul 2024 18:36:07 +0200 Subject: [IMP] Much better source tree. Signed-off-by: Amlal --- .vscode/c_cpp_properties.json | 60 +- Comm/AsmKit/AsmKit.hpp | 217 --- Comm/AsmKit/CPU/32x0.hpp | 95 -- Comm/AsmKit/CPU/64x0.hpp | 108 -- Comm/AsmKit/CPU/amd64.hpp | 57 - Comm/AsmKit/CPU/arm64.hpp | 26 - Comm/AsmKit/CPU/ppc.hpp | 1929 --------------------------- Comm/CompilerKit.hpp | 33 - Comm/Defines.hpp | 147 -- Comm/ParserKit.hpp | 173 --- Comm/Public/SDK/CRT/__mpcc_alloca.hxx | 15 - Comm/Public/SDK/CRT/__mpcc_defines.hxx | 83 -- Comm/Public/SDK/CRT/__mpcc_exception.hxx | 27 - Comm/Public/SDK/CRT/__mpcc_hint.hxx | 20 - Comm/Public/SDK/CRT/__mpcc_malloc.hxx | 30 - Comm/Public/SDK/CRT/__mpcc_power.inc | 35 - Comm/StdKit/AE.hpp | 143 -- Comm/StdKit/ELF.hpp | 389 ------ Comm/StdKit/ErrorID.hpp | 22 - Comm/StdKit/ErrorOr.hpp | 61 - Comm/StdKit/PEF.hpp | 133 -- Comm/StdKit/Ref.hpp | 91 -- Comm/StdKit/String.hpp | 90 -- Comm/StdKit/XCOFF.hxx | 41 - Comm/UUID.hpp | 983 -------------- Comm/Version.hxx | 3 - Examples/ExampleCDialect.S | 2 +- Headers/AsmKit/AsmKit.hpp | 217 +++ Headers/AsmKit/CPU/32x0.hpp | 95 ++ Headers/AsmKit/CPU/64x0.hpp | 108 ++ Headers/AsmKit/CPU/amd64.hpp | 57 + Headers/AsmKit/CPU/arm64.hpp | 26 + Headers/AsmKit/CPU/ppc.hpp | 1929 +++++++++++++++++++++++++++ Headers/Defines.hpp | 147 ++ Headers/Macros.hpp | 33 + Headers/ParserKit.hpp | 173 +++ Headers/Public/SDK/CRT/__mpcc_alloca.hxx | 15 + Headers/Public/SDK/CRT/__mpcc_defines.hxx | 83 ++ Headers/Public/SDK/CRT/__mpcc_exception.hxx | 27 + Headers/Public/SDK/CRT/__mpcc_hint.hxx | 20 + Headers/Public/SDK/CRT/__mpcc_malloc.hxx | 30 + Headers/Public/SDK/CRT/__mpcc_power.inc | 35 + Headers/StdKit/AE.hpp | 143 ++ Headers/StdKit/ELF.hpp | 389 ++++++ Headers/StdKit/ErrorID.hpp | 22 + Headers/StdKit/ErrorOr.hpp | 61 + Headers/StdKit/PEF.hpp | 134 ++ Headers/StdKit/Ref.hpp | 91 ++ Headers/StdKit/String.hpp | 90 ++ Headers/StdKit/XCOFF.hxx | 41 + Headers/UUID.hpp | 983 ++++++++++++++ Headers/Version.hxx | 3 + Notes/ASM specs.txt | 11 + Notes/HAVP DSP.txt | 13 + Notes/Notice.txt | 4 + Notes/RISC CPU.txt | 17 + Notes/asm-specs.txt | 11 - Notes/havp.txt | 13 - Notes/notice.txt | 4 - Notes/vnrp.txt | 17 - Sources/32asm.cc | 52 - Sources/32asm.cxx | 52 + Sources/64asm.cc | 954 ------------- Sources/64asm.cxx | 954 +++++++++++++ Sources/64x0-cc.cc | 1627 ---------------------- Sources/64x0-cc.cxx | 1627 ++++++++++++++++++++++ Sources/AssemblyFactory.cc | 59 - Sources/AssemblyFactory.cxx | 59 + Sources/Detail/asmutils.hxx | 4 +- Sources/Detail/compilerutils.hxx | 4 +- Sources/String.cc | 200 --- Sources/String.cxx | 200 +++ Sources/bpp.cc | 899 ------------- Sources/bpp.cxx | 899 +++++++++++++ Sources/coff2ae.cc | 23 - Sources/coff2ae.cxx | 23 + Sources/compile_flags.txt | 2 +- Sources/cplusplus.cc | 905 ------------- Sources/cplusplus.cxx | 905 +++++++++++++ Sources/elf2ae.cc | 22 - Sources/elf2ae.cxx | 22 + Sources/i64asm.cc | 1484 --------------------- Sources/i64asm.cxx | 1484 +++++++++++++++++++++ Sources/link.cc | 738 ---------- Sources/link.cxx | 741 ++++++++++ Sources/power-cc.cc | 1645 ----------------------- Sources/power-cc.cxx | 1645 +++++++++++++++++++++++ Sources/ppcasm.cc | 976 -------------- Sources/ppcasm.cxx | 976 ++++++++++++++ codetools.files | 78 +- codetools.includes | 2 +- posix.make | 20 +- win64.make | 20 +- 93 files changed, 14680 insertions(+), 14676 deletions(-) delete mode 100644 Comm/AsmKit/AsmKit.hpp delete mode 100644 Comm/AsmKit/CPU/32x0.hpp delete mode 100644 Comm/AsmKit/CPU/64x0.hpp delete mode 100644 Comm/AsmKit/CPU/amd64.hpp delete mode 100644 Comm/AsmKit/CPU/arm64.hpp delete mode 100644 Comm/AsmKit/CPU/ppc.hpp delete mode 100644 Comm/CompilerKit.hpp delete mode 100644 Comm/Defines.hpp delete mode 100644 Comm/ParserKit.hpp delete mode 100644 Comm/Public/SDK/CRT/__mpcc_alloca.hxx delete mode 100644 Comm/Public/SDK/CRT/__mpcc_defines.hxx delete mode 100644 Comm/Public/SDK/CRT/__mpcc_exception.hxx delete mode 100644 Comm/Public/SDK/CRT/__mpcc_hint.hxx delete mode 100644 Comm/Public/SDK/CRT/__mpcc_malloc.hxx delete mode 100644 Comm/Public/SDK/CRT/__mpcc_power.inc delete mode 100644 Comm/StdKit/AE.hpp delete mode 100644 Comm/StdKit/ELF.hpp delete mode 100644 Comm/StdKit/ErrorID.hpp delete mode 100644 Comm/StdKit/ErrorOr.hpp delete mode 100644 Comm/StdKit/PEF.hpp delete mode 100644 Comm/StdKit/Ref.hpp delete mode 100644 Comm/StdKit/String.hpp delete mode 100644 Comm/StdKit/XCOFF.hxx delete mode 100644 Comm/UUID.hpp delete mode 100644 Comm/Version.hxx create mode 100644 Headers/AsmKit/AsmKit.hpp create mode 100644 Headers/AsmKit/CPU/32x0.hpp create mode 100644 Headers/AsmKit/CPU/64x0.hpp create mode 100644 Headers/AsmKit/CPU/amd64.hpp create mode 100644 Headers/AsmKit/CPU/arm64.hpp create mode 100644 Headers/AsmKit/CPU/ppc.hpp create mode 100644 Headers/Defines.hpp create mode 100644 Headers/Macros.hpp create mode 100644 Headers/ParserKit.hpp create mode 100644 Headers/Public/SDK/CRT/__mpcc_alloca.hxx create mode 100644 Headers/Public/SDK/CRT/__mpcc_defines.hxx create mode 100644 Headers/Public/SDK/CRT/__mpcc_exception.hxx create mode 100644 Headers/Public/SDK/CRT/__mpcc_hint.hxx create mode 100644 Headers/Public/SDK/CRT/__mpcc_malloc.hxx create mode 100644 Headers/Public/SDK/CRT/__mpcc_power.inc create mode 100644 Headers/StdKit/AE.hpp create mode 100644 Headers/StdKit/ELF.hpp create mode 100644 Headers/StdKit/ErrorID.hpp create mode 100644 Headers/StdKit/ErrorOr.hpp create mode 100644 Headers/StdKit/PEF.hpp create mode 100644 Headers/StdKit/Ref.hpp create mode 100644 Headers/StdKit/String.hpp create mode 100644 Headers/StdKit/XCOFF.hxx create mode 100644 Headers/UUID.hpp create mode 100644 Headers/Version.hxx create mode 100644 Notes/ASM specs.txt create mode 100644 Notes/HAVP DSP.txt create mode 100644 Notes/Notice.txt create mode 100644 Notes/RISC CPU.txt delete mode 100644 Notes/asm-specs.txt delete mode 100644 Notes/havp.txt delete mode 100644 Notes/notice.txt delete mode 100644 Notes/vnrp.txt delete mode 100644 Sources/32asm.cc create mode 100644 Sources/32asm.cxx delete mode 100644 Sources/64asm.cc create mode 100644 Sources/64asm.cxx delete mode 100644 Sources/64x0-cc.cc create mode 100644 Sources/64x0-cc.cxx delete mode 100644 Sources/AssemblyFactory.cc create mode 100644 Sources/AssemblyFactory.cxx delete mode 100644 Sources/String.cc create mode 100644 Sources/String.cxx delete mode 100644 Sources/bpp.cc create mode 100644 Sources/bpp.cxx delete mode 100644 Sources/coff2ae.cc create mode 100644 Sources/coff2ae.cxx delete mode 100644 Sources/cplusplus.cc create mode 100644 Sources/cplusplus.cxx delete mode 100644 Sources/elf2ae.cc create mode 100644 Sources/elf2ae.cxx delete mode 100644 Sources/i64asm.cc create mode 100644 Sources/i64asm.cxx delete mode 100644 Sources/link.cc create mode 100644 Sources/link.cxx delete mode 100644 Sources/power-cc.cc create mode 100644 Sources/power-cc.cxx delete mode 100644 Sources/ppcasm.cc create mode 100644 Sources/ppcasm.cxx (limited to 'Sources') diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 696e195..c520968 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,31 +1,31 @@ { - "configurations": [ - { - "name": "Macintosh (CLang)", - "includePath": [ - "${workspaceFolder}/Comm/**", - "${workspaceFolder}/Sources/Detail/**", - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/clang", - "cStandard": "c17", - "cppStandard": "c++20", - "intelliSenseMode": "macos-clang-arm64" - }, - { - "name": "Windows (Cygwin)", - "includePath": [ - "${workspaceFolder}/Comm/**", - "${workspaceFolder}/Sources/Detail/**", - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "C:/cygwin64/bin/g++.exe", - "cStandard": "c17", - "cppStandard": "c++20", - "intelliSenseMode": "windows-gcc-x64" - } - ], - "version": 4 -} \ No newline at end of file + "configurations": [ + { + "name": "Macintosh (CLang)", + "includePath": [ + "${workspaceFolder}/Headers/**", + "${workspaceFolder}/Sources/Detail/**", + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "macos-clang-arm64" + }, + { + "name": "Windows (Cygwin)", + "includePath": [ + "${workspaceFolder}/Headers/**", + "${workspaceFolder}/Sources/Detail/**", + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "C:/cygwin64/bin/g++.exe", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "windows-gcc-x64" + } + ], + "version": 4 +} diff --git a/Comm/AsmKit/AsmKit.hpp b/Comm/AsmKit/AsmKit.hpp deleted file mode 100644 index 38b418c..0000000 --- a/Comm/AsmKit/AsmKit.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include -#include - -namespace CompilerKit -{ - // - // @brief Frontend to Assembly mountpoint. - // - class AssemblyInterface - { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - MPCC_COPY_DEFAULT(AssemblyInterface); - - //@ brief compile to object file. - // Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; - }; - - /// @brief Simple assembly factory - class AssemblyFactory final - { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - MPCC_COPY_DEFAULT(AssemblyFactory); - - public: - enum - { - kArchAMD64, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchUnknown, - }; - - Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; - }; - - union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; - }; - - union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) - : raw(raw) - { - } - ~NumberCast64() - { - raw = 0; - } - - CharType number[8]; - UInt64 raw; - }; - - union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) - : raw(raw) - { - } - ~NumberCast32() - { - raw = 0; - } - - CharType number[4]; - UInt32 raw; - }; - - union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) - : raw(raw) - { - } - ~NumberCast16() - { - raw = 0; - } - - CharType number[2]; - UInt16 raw; - }; - - union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) - : raw(raw) - { - } - ~NumberCast8() - { - raw = 0; - } - - CharType number; - UInt8 raw; - }; - - class EncoderInterface - { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - MPCC_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string& line, const std::string& file) = 0; - virtual bool WriteLine(std::string& line, const std::string& file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; - }; - -#ifdef __ASM_NEED_AMD64__ - - class EncoderAMD64 final : public EncoderInterface - { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - MPCC_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); - }; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_64x0__ - - class Encoder64x0 final : public EncoderInterface - { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - MPCC_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - - class Encoder32x0 final : public EncoderInterface - { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - MPCC_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - - class EncoderPowerPC final : public EncoderInterface - { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - MPCC_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/Comm/AsmKit/CPU/32x0.hpp b/Comm/AsmKit/CPU/32x0.hpp deleted file mode 100644 index 7b93a94..0000000 --- a/Comm/AsmKit/CPU/32x0.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @brief 32x0 support. -// @file CPU/32x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 - -#define kAsmByte 0 -#define kAsmHWord 1 -#define kAsmWord 2 - -struct CpuCode32x0 -{ - const char fName[32]; - char fOpcode; - char fSize; - char fFunct3; - char fFunct7; -}; - -#define kAsmDWordStr ".dword" /* 64 bit */ -#define kAsmWordStr ".word" /* 32-bit */ -#define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ - -inline std::vector kOpcodes32x0 = { - kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. - kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch - kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers - kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp - kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. - kAsmOpcodeDecl("cls", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR. - kAsmOpcodeDecl("rts", 0b0111011, 0b110, - kAsmImmediate) // pull stack and return form CR. - kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt -}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: TODO: find one -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Comm/AsmKit/CPU/64x0.hpp b/Comm/AsmKit/CPU/64x0.hpp deleted file mode 100644 index b8bafb9..0000000 --- a/Comm/AsmKit/CPU/64x0.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -// @brief 64x0 support. -// @file CPU/64x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 - -typedef char e64k_character_t; -typedef uint8_t e64k_num_t; - -struct CpuOpcode64x0 -{ - const e64k_character_t fName[32]; - e64k_num_t fOpcode; - e64k_num_t fFunct3; - e64k_num_t fFunct7; -}; - -inline std::vector kOpcodes64x0 = { - kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) - kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) - kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL/JUMP ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Comm/AsmKit/CPU/amd64.hpp b/Comm/AsmKit/CPU/amd64.hpp deleted file mode 100644 index 06dc1da..0000000 --- a/Comm/AsmKit/CPU/amd64.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @brief AMD64 support. -// @file CPU/amd64.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, - -typedef char i64_character_t; -typedef uint8_t i64_byte_t; -typedef uint16_t i64_hword_t; -typedef uint32_t i64_word_t; - -struct CpuOpcodeAMD64 -{ - std::string fName; - i64_byte_t fPrefixBytes[4]; - i64_hword_t fOpcode; - i64_hword_t fModReg; - i64_word_t fDisplacment; - i64_word_t fImmediate; -}; - -/// these two are edge cases -#define kAsmIntOpcode 0xCC -#define kasmIntOpcodeAlt 0xCD - -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 -#define kJumpLimitStandardLimit 0xEB - -inline std::vector kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF) -}; - -#define kAsmRegisterLimit 15 diff --git a/Comm/AsmKit/CPU/arm64.hpp b/Comm/AsmKit/CPU/arm64.hpp deleted file mode 100644 index 8dd5204..0000000 --- a/Comm/AsmKit/CPU/arm64.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* ------------------------------------------- - -Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -/// @brief ARM64 encoding support. -/// @file CPU/arm64.hpp - -struct CpuOpcodeArm64; - -/// @brief ARM64 opcode header. -struct CpuOpcodeArm64 final -{ - uint8_t fOpcode; // opcode - uint8_t fRegisterLeft; // left register index - uint8_t fRegisterRight; // right register index - bool fRegisterLeftHooked; - bool fRegisterRightHooked; - uint32_t fImmediateValue; // immediate 32-bit value - bool fImmediateValueHooked; -}; diff --git a/Comm/AsmKit/CPU/ppc.hpp b/Comm/AsmKit/CPU/ppc.hpp deleted file mode 100644 index e3ea6c5..0000000 --- a/Comm/AsmKit/CPU/ppc.hpp +++ /dev/null @@ -1,1929 +0,0 @@ -/* ------------------------------------------- - - Some modifications are copyrighted under: - ZKA Technologies - - Original author: - Apple Inc - -------------------------------------------- */ - -#pragma once - -#include - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -/* - * These defines are use in the cpus field of the instructions. If the field - * is zero it can execute on all cpus. The defines are or'ed together. This - * information is used to set the cpusubtype in the resulting object file. - */ -#define CPU601 0x1 -#define IMPL64 0x2 -#define OPTIONAL 0x4 -#define VMX 0x8 -#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ -#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ - -enum optype -{ - NONE, /* no operand */ - JBSR, /* jbsr pseudo op */ - PCREL, /* PC relative (branch offset) */ - BADDR, /* Branch address (sign extended absolute address) */ - D, /* 16 bit displacement */ - DS, /* 14 bit displacement (double word) */ - SI, /* signed 16 bit immediate */ - UI, /* unsigned 16 bit immediate */ - HI, /* high 16 bit immediate (with truncation) */ - GREG, /* general register */ - G0REG, /* general register r1-r31 or 0 */ - FREG, /* float register */ - VREG, /* vector register */ - SGREG, /* segment register */ - SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ - BCND, /* branch condition opcode */ - CRF, /* condition register field */ - CRFONLY, /* condition register field only no expression allowed */ - sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ - mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ - NUM, /* number */ - SNUM, /* signed number */ - NUM0, /* number (where 1< - -#define SizeType size_t - -#define VoidPtr void* -#define voidPtr VoidPtr - -#define UIntPtr uintptr_t - -#define Int64 int64_t -#define UInt64 uint64_t - -#define Int32 int -#define UInt32 unsigned - -#define Bool bool - -#define Int16 int16_t -#define UInt16 uint16_t - -#define Int8 int8_t -#define UInt8 uint8_t - -#define CharType char -#define Boolean bool - -#include -#include -#include - -#define nullPtr std::nullptr_t - -#define MUST_PASS(E) assert(E) - -#ifndef __FORCE_STRLEN -#define __FORCE_STRLEN 1 - -#define string_length(len) strlen(len) -#endif - -#ifndef __FORCE_MEMCPY -#define __FORCE_MEMCPY 1 - -#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) -#endif - -#define MPCC_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define MPCC_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define MPCC_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define MPCC_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#include -#include -#include -#include - -namespace CompilerKit -{ - inline constexpr int BASE_YEAR = 1900; - - inline std::string current_date() noexcept - { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); - - return fmt; - } - - inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept - { - if (limit == 0) - return false; - - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; - - while (limit != 1) - { - ret = ret % 10; - str[cnt] = ret; - - ++cnt; - --limit; - --ret; - } - - str[copy_limit] = '\0'; - return true; - } -} // namespace CompilerKit - -#define PACKED __attribute__((packed)) - -typedef char char_type; - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { \ - ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ - } - -#ifdef __NDK_MODULE__ -#define NDK_MODULE(name) int name(int argc, char** argv) -#else -#define NDK_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __NDK_MODULE__ */ - -#pragma scalar_storage_order big-endian - -#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Comm/ParserKit.hpp b/Comm/ParserKit.hpp deleted file mode 100644 index 4c3f483..0000000 --- a/Comm/ParserKit.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -namespace ParserKit -{ - using namespace CompilerKit; - - /// @brief Compiler backend, implements a frontend, such as C, C++... - /// See Toolchain, for some examples. - class CompilerBackend - { - public: - explicit CompilerBackend() = default; - virtual ~CompilerBackend() = default; - - MPCC_COPY_DEFAULT(CompilerBackend); - - // NOTE: cast this to your user defined ast. - typedef void* AstType; - - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - - virtual bool Compile(const std::string& text, const char* file) = 0; - - //! @brief What language are we dealing with? - virtual const char* Language() - { - return "Invalid Language"; - } - }; - - struct SyntaxLeafList; - struct SyntaxLeafList; - struct CompilerKeyword; - - /// we want to do that because to separate keywords. - enum KeywordKind - { - eKeywordKindNamespace, - eKeywordKindFunctionStart, - eKeywordKindFunctionEnd, - eKeywordKindVariable, - eKeywordKindVariablePtr, - eKeywordKindType, - eKeywordKindTypePtr, - eKeywordKindExpressionBegin, - eKeywordKindExpressionEnd, - eKeywordKindArgSeparator, - eKeywordKindBodyStart, - eKeywordKindBodyEnd, - eKeywordKindClass, - eKeywordKindPtrAccess, - eKeywordKindAccess, - eKeywordKindIf, - eKeywordKindElse, - eKeywordKindElseIf, - eKeywordKindVariableAssign, - eKeywordKindVariableDec, - eKeywordKindVariableInc, - eKeywordKindConstant, - eKeywordKindTypedef, - eKeywordKindEndInstr, - eKeywordKindSpecifier, - eKeywordKindInvalid, - eKeywordKindReturn, - eKeywordKindCommentInline, - eKeywordKindCommentMultiLineStart, - eKeywordKindCommentMultiLineEnd, - eKeywordKindEq, - eKeywordKindNotEq, - eKeywordKindGreaterEq, - eKeywordKindLessEq, - eKeywordKindPtr, - }; - - /// \brief Compiler keyword information struct. - struct CompilerKeyword - { - std::string keyword_name; - KeywordKind keyword_kind = eKeywordKindInvalid; - }; - struct SyntaxLeafList final - { - struct SyntaxLeaf final - { - Int32 fUserType; -#ifdef __PK_USE_STRUCT_INSTEAD__ - CompilerKeyword fUserData; -#else - std::string fUserData; -#endif - - std::string fUserValue; - struct SyntaxLeaf* fNext; - }; - - std::vector fLeafList; - SizeType fNumLeafs; - - size_t SizeOf() - { - return fNumLeafs; - } - std::vector& Get() - { - return fLeafList; - } - SyntaxLeaf& At(size_t index) - { - return fLeafList[index]; - } - }; - - /// find the perfect matching word in a haystack. - /// \param haystack base string - /// \param needle the string we search for. - /// \return if we found it or not. - inline bool find_word(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) - return true; - - if (index < 0 || index >= haystack.size()) - return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); - } - - /// find a word within strict conditions and returns a range of it. - /// \param haystack - /// \param needle - /// \return position of needle. - inline std::size_t find_word_range(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) - { - return index; - } - - return false; - } -} // namespace ParserKit diff --git a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx b/Comm/Public/SDK/CRT/__mpcc_alloca.hxx deleted file mode 100644 index 02b3123..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_alloca.hxx +++ /dev/null @@ -1,15 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -typedef void* ptr_type; -typedef __SIZE_TYPE__ size_type; - -inline void* __mpcc_alloca_gcc(size_type sz) -{ - return __builtin_alloca(sz); -} diff --git a/Comm/Public/SDK/CRT/__mpcc_defines.hxx b/Comm/Public/SDK/CRT/__mpcc_defines.hxx deleted file mode 100644 index 19ed8a4..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_defines.hxx +++ /dev/null @@ -1,83 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#ifndef __MPCC_DEF__ -#define __MPCC_DEF__ - -#ifndef __GNUC__ - -typedef __SIZE_TYPE__ size_t; - -#ifdef __LP64__ -typedef long int ssize_t; -#else -typedef int ssize_t; -#endif // __LP64__ - -typedef size_t ptrdiff_t; -typedef size_t uintptr_t; -typedef void* voidptr_t; -typedef void* any_t; -typedef char* caddr_t; - -#ifndef NULL -#define NULL ((voidptr_t)0) -#endif // !null - -#ifdef __GNUC__ -#include -#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) -#define __packed__ __attribute__((packed)) -#elif defined(__MPCC__) -#define __packed__ __mpcc_packed__ -#define __alloca(sz) __mpcc_alloca(sz) -#endif - -#define __deref(ptr) (*(ptr)) - -#ifdef __cplusplus -#define __init_decl() \ - extern "C" \ - { - - -#define __fini_decl() \ - }; \ - - -#else -#define __init_decl() -#define __fini_decl() -#endif - -typedef long long off_t; -typedef unsigned long long uoff_t; - -typedef union float_cast { - struct - { - unsigned int mantissa : 23; - unsigned int exponent : 8; - unsigned int sign : 1; - }; - - float f; -} __packed__ float_cast_t; - -typedef union double_cast { - struct - { - unsigned long long int mantissa : 52; - unsigned int exponent : 11; - unsigned int sign : 1; - }; - - double f; -} __packed__ double_cast_t; - -#endif // ifndef __GNUC__ - -#endif /* __MPCC_DEF__ */ diff --git a/Comm/Public/SDK/CRT/__mpcc_exception.hxx b/Comm/Public/SDK/CRT/__mpcc_exception.hxx deleted file mode 100644 index 4a9f84a..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_exception.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -/// This file is an implementation of __throw* family of functions. - -#include -#include -#include - -namespace std -{ - inline void __throw_general(void) - { - throw std::runtime_error("MPCC C++ Runtime error."); - } - - inline void __throw_domain_error(const char* error) - { - std::cout << "MPCC C++: Domain error: " << error << "\r"; - __throw_general(); - } -} // namespace std diff --git a/Comm/Public/SDK/CRT/__mpcc_hint.hxx b/Comm/Public/SDK/CRT/__mpcc_hint.hxx deleted file mode 100644 index 02dbc94..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_hint.hxx +++ /dev/null @@ -1,20 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#pragma compiler(hint_manifest) - -#define _Input -#define _Output - -#define _Optional - -#define _StrictCheckInput -#define _StrictCheckOutput - -#define _InOut -#define _StrictInOut diff --git a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx b/Comm/Public/SDK/CRT/__mpcc_malloc.hxx deleted file mode 100644 index eeaa67b..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_malloc.hxx +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -namespace stdx -{ - /// @brief allocate a new class. - /// @tparam KindClass the class type to allocate. - template - inline void* allocate(Args&&... args) - { - return new KindClass(std::forward(args)...); - } - - /// @brief free a class. - /// @tparam KindClass the class type to allocate. - template - inline void release(KindClass ptr) - { - if (!ptr) - return; - delete ptr; - } -} // namespace stdx diff --git a/Comm/Public/SDK/CRT/__mpcc_power.inc b/Comm/Public/SDK/CRT/__mpcc_power.inc deleted file mode 100644 index 9e4928c..0000000 --- a/Comm/Public/SDK/CRT/__mpcc_power.inc +++ /dev/null @@ -1,35 +0,0 @@ -# Path: SDK/__mpcc_power.inc -# Language: MPCC POWER Assembly support for GNU. -# Build Date: 2024-6-4 - -%ifdef __CODETOOLS__ - -%def lda li -%def sta stw -%def ldw li - -%def r0 0 -%def r1 1 -%def r2 2 -%def r3 3 -%def r4 4 -%def r5 5 -%def r6 6 -%def r7 7 -%def r8 8 -%def r9 9 -%def r10 10 -%def r11 11 -%def r12 12 -%def r13 13 -%def r14 14 -%def r15 15 -%def r16 16 -%def r17 17 -%def r18 18 -%def r19 19 -%def r20 20 - -%endif - -%def nop mr 0, 0 diff --git a/Comm/StdKit/AE.hpp b/Comm/StdKit/AE.hpp deleted file mode 100644 index ee39e56..0000000 --- a/Comm/StdKit/AE.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ======================================================== - * - * MPCC - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen 64 -#define kAEPad 8 -#define kAEMagLen 2 -#define kAEInvalidOpcode 0x00 - -// Advanced Executable File Format for MetroLink. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system -// loader. - -namespace CompilerKit -{ - // @brief Advanced Executable Header - // One thing to keep in mind. - // This object format, is reloctable. - typedef struct AEHeader final - { - CharType fMagic[kAEMagLen]; - CharType fArch; - CharType fSubArch; - SizeType fCount; - CharType fSize; - SizeType fStartCode; - SizeType fCodeSize; - CharType fPad[kAEPad]; - } PACKED AEHeader, *AEHeaderPtr; - - // @brief Advanced Executable Record. - // Could be data, code or bss. - // fKind must be filled with PEF fields. - - typedef struct AERecordHeader final - { - CharType fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - CharType fPad[kAEPad]; - } PACKED AERecordHeader, *AERecordHeaderPtr; - - enum - { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, - }; -} // namespace CompilerKit - -// provide operator<< for AE - -std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils -{ - /** - * @brief AE Reader protocol - * - */ - class AEReadableProtocol final - { - public: - std::ifstream FP; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - MPCC_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) - { - if (!raw) - return nullptr; - - return this->_Read(raw, sz * sizeof(AERecordHeader)); - } - - private: - /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ - template - TypeClass* _Read(char* raw, std::size_t sz) - { - FP.read(raw, std::streamsize(sz)); - return reinterpret_cast(raw); - } - }; -} // namespace CompilerKit::Utils diff --git a/Comm/StdKit/ELF.hpp b/Comm/StdKit/ELF.hpp deleted file mode 100644 index 4f0d0ae..0000000 --- a/Comm/StdKit/ELF.hpp +++ /dev/null @@ -1,389 +0,0 @@ -#pragma once - -#include -#include - -struct file; - -#ifndef elf_read_implies_exec -/* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif - -/* 32-bit ELF base types. */ -typedef uint32_t Elf32_Addr; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Word; - -/* 64-bit ELF base types. */ -typedef uintptr_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef int16_t Elf64_SHalf; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* These constants are for the segment types stored in the image headers */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff -#define PT_GNU_EH_FRAME 0x6474e550 - -#define PT_GNU_STACK (PT_LOOS + 0x474e551) - -/* These constants define the different elf file types */ -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 -#define ET_LOPROC 0xff00 -#define ET_HIPROC 0xffff - -/* This is the info that is needed to parse the dynamic section of the file */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_ENCODING 32 -#define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 -#define DT_VALRNGLO 0x6ffffd00 -#define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff - -/* This info is needed when parsing the symbol table */ -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 - -#define ELF_ST_BIND(x) ((x) >> 4) -#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_BIND(x) ELF_ST_BIND(x) -#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) -#define ELF64_ST_BIND(x) ELF_ST_BIND(x) -#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) - -typedef struct dynamic -{ - Elf32_Sword d_tag; - union { - Elf32_Sword d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* entry tag value */ - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - -/* The following are used with relocations */ -#define ELF32_R_SYM(x) ((x) >> 8) -#define ELF32_R_TYPE(x) ((x)&0xff) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i)&0xffffffff) - -typedef struct elf32_rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct elf64_rel -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ -} Elf64_Rel; - -typedef struct elf32_rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct elf64_rela -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ - Elf64_Sxword r_addend; /* Constant addend used to compute value */ -} Elf64_Rela; - -typedef struct elf32_sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct elf64_sym -{ - Elf64_Word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - Elf64_Half st_shndx; /* Associated section index */ - Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Xword st_size; /* Associated symbol size */ -} Elf64_Sym; - -#define EI_NIDENT 16 - -typedef struct elf32_hdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; /* Entry point */ - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Ehdr; - -typedef struct elf64_hdr -{ - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* These constants define the permissions on sections in the program - header, p_flags. */ -#define PF_R 0x4 -#define PF_W 0x2 -#define PF_X 0x1 - -typedef struct elf32_phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -typedef struct elf64_phdr -{ - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment, file & memory */ -} Elf64_Phdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_NUM 12 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xffffffff - -/* sh_flags */ -#define SHF_WRITE 0x1 -#define SHF_ALLOC 0x2 -#define SHF_EXECINSTR 0x4 -#define SHF_MASKPROC 0xf0000000 - -/* special section indexes */ -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_LOPROC 0xff00 -#define SHN_HIPROC 0xff1f -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_HIRESERVE 0xffff - -typedef struct -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; - -typedef struct elf64_shdr -{ - Elf64_Word sh_name; /* Section name, index in string tbl */ - Elf64_Word sh_type; /* Type of section */ - Elf64_Xword sh_flags; /* Miscellaneous section attributes */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Size of section in bytes */ - Elf64_Word sh_link; /* Index of another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -#define EI_MAG0 0 /* e_ident[] indexes */ -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_PAD 8 - -#define ELFMAG0 0x7f /* EI_MAG */ -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define ELFCLASSNONE 0 /* EI_CLASS */ -#define ELFCLASS32 1 -#define ELFCLASS64 2 -#define ELFCLASSNUM 3 - -#define ELFDATANONE 0 /* e_ident[EI_DATA] */ -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_NONE 0 /* e_version, EI_VERSION */ -#define EV_CURRENT 1 -#define EV_NUM 2 - -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 - -#ifndef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE -#endif - -/* Notes used in ET_CORE */ -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ -#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* POWER VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ - -/* Note header in a PT_NOTE section */ -typedef struct elf32_note -{ - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ -} Elf32_Nhdr; - -/* Note header in a PT_NOTE section */ -typedef struct elf64_note -{ - Elf64_Word n_namesz; /* Name size */ - Elf64_Word n_descsz; /* Content size */ - Elf64_Word n_type; /* Content type */ -} Elf64_Nhdr; diff --git a/Comm/StdKit/ErrorID.hpp b/Comm/StdKit/ErrorID.hpp deleted file mode 100644 index abaac85..0000000 --- a/Comm/StdKit/ErrorID.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -#define MPCC_EXEC_ERROR -30 -#define MPCC_FILE_NOT_FOUND -31 -#define MPCC_DIR_NOT_FOUND -32 -#define MPCC_FILE_EXISTS -33 -#define MPCC_TOO_LONG -34 -#define MPCC_INVALID_DATA -35 -#define MPCC_UNIMPLEMENTED -36 -#define MPCC_FAT_ERROR -37 diff --git a/Comm/StdKit/ErrorOr.hpp b/Comm/StdKit/ErrorOr.hpp deleted file mode 100644 index 4097cc9..0000000 --- a/Comm/StdKit/ErrorOr.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - using ErrorT = UInt32; - - template - class ErrorOr final - { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(Int32 err) - : mId(err) - { - } - - explicit ErrorOr(nullPtr Null) - { - } - - explicit ErrorOr(T Class) - : mRef(Class) - { - } - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref Leak() - { - return mRef; - } - - operator bool() - { - return mRef; - } - - private: - Ref mRef; - Int32 mId{0}; - }; - - using ErrorOrAny = ErrorOr; - -} // namespace CompilerKit diff --git a/Comm/StdKit/PEF.hpp b/Comm/StdKit/PEF.hpp deleted file mode 100644 index 85044b2..0000000 --- a/Comm/StdKit/PEF.hpp +++ /dev/null @@ -1,133 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @file PEF.hpp -// @brief Preferred Executable Format - -#define kPefMagic "Joy!" -#define kPefMagicFat "yoJ!" - -#define kPefExt ".exec" -#define kPefDylibExt ".lib" -#define kPefLibExt ".slib" -#define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" - -#define kPefMagicLen 5 - -#define kPefVersion 2 -#define kPefNameLen 255 - -#define kPefBaseOrigin (0x1000000) - -#define kPefStart "__ImageStart" - -namespace CompilerKit -{ - enum - { - kPefArchIntel86S = 100, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* 64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchARM64, - kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, - }; - - enum - { - kPefSubArchAMD, - kPefSubArchIntel, - kPefSubArchGeneric, - kPefSubArchIBM, - }; - - enum - { - kPefKindExec = 1, /* .exe */ - kPefKindSharedObject = 2, /* .lib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, - }; - - /* PEF container */ - typedef struct PEFContainer final - { - CharType Magic[kPefMagicLen]; - UInt32 Linker; - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - } PACKED PEFContainer; - - /* First PEFCommandHeader starts after PEFContainer */ - /* Last container is __exec_end */ - - /* PEF executable section and commands. */ - - typedef struct PEFCommandHeader final - { - CharType Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* file offset */ - SizeType Size; /* file size */ - } PACKED PEFCommandHeader; - - enum - { - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, - kPefInvalid = 0xFF, - }; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/Comm/StdKit/Ref.hpp b/Comm/StdKit/Ref.hpp deleted file mode 100644 index e655ccb..0000000 --- a/Comm/StdKit/Ref.hpp +++ /dev/null @@ -1,91 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -namespace CompilerKit -{ - // @author ZKA Technologies - // @brief Reference class, refers to a pointer of data in static memory. - template - class Ref final - { - public: - explicit Ref() = default; - ~Ref() = default; - - public: - explicit Ref(T cls, const bool& strong = false) - : m_Class(cls), m_Strong(strong) - { - } - - Ref& operator=(T ref) - { - m_Class = ref; - return *this; - } - - public: - T operator->() const - { - return m_Class; - } - - T& Leak() - { - return m_Class; - } - - T operator*() - { - return m_Class; - } - - bool IsStrong() const - { - return m_Strong; - } - - operator bool() - { - return m_Class; - } - - private: - T m_Class; - bool m_Strong{false}; - }; - - template - class NonNullRef final - { - public: - NonNullRef() = delete; - NonNullRef(nullPtr) = delete; - - explicit NonNullRef(T* ref) - : m_Ref(ref, true) - { - } - - Ref& operator->() - { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef& ref) = delete; - NonNullRef(const NonNullRef& ref) = default; - - private: - Ref m_Ref{nullptr}; - }; -} // namespace CompilerKit diff --git a/Comm/StdKit/String.hpp b/Comm/StdKit/String.hpp deleted file mode 100644 index 7e62bc5..0000000 --- a/Comm/StdKit/String.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - - class StringView final - { - public: - explicit StringView() = delete; - - explicit StringView(SizeType Sz) noexcept - : m_Sz(Sz) - { - m_Data = new char[Sz]; - assert(m_Data); - } - - ~StringView() noexcept - { - if (m_Data) - { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - MPCC_COPY_DEFAULT(StringView); - - CharType* Data(); - const CharType* CData() const; - SizeType Length() const; - - bool operator==(const CharType* rhs) const; - bool operator!=(const CharType* rhs) const; - - bool operator==(const StringView& rhs) const; - bool operator!=(const StringView& rhs) const; - - StringView& operator+=(const CharType* rhs); - StringView& operator+=(const StringView& rhs); - - operator bool() - { - return m_Data && m_Data[0] != 0; - } - - bool operator!() - { - return !m_Data || m_Data[0] == 0; - } - - private: - char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; - }; - - /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ - struct StringBuilder final - { - static StringView Construct(const CharType* data); - static const char* FromInt(const char* fmt, int n); - static const char* FromBool(const char* fmt, bool n); - static const char* Format(const char* fmt, const char* from); - static bool Equals(const char* lhs, const char* rhs); - }; -} // namespace CompilerKit diff --git a/Comm/StdKit/XCOFF.hxx b/Comm/StdKit/XCOFF.hxx deleted file mode 100644 index 4b25484..0000000 --- a/Comm/StdKit/XCOFF.hxx +++ /dev/null @@ -1,41 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - - File: XCOFF.hpp - Purpose: XCOFF for NewOS. - - Revision History: - - 04/07/24: Added file (amlel) - -------------------------------------------- */ - -#ifndef __XCOFF__ -#define __XCOFF__ - -#include - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit -{ - /// @brief XCoff identification header. - typedef struct XCoffFileHeader - { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header - } XCoffFileHeader; -} // namespace CompilerKit - -#endif // ifndef __XCOFF__ diff --git a/Comm/UUID.hpp b/Comm/UUID.hpp deleted file mode 100644 index 00b153b..0000000 --- a/Comm/UUID.hpp +++ /dev/null @@ -1,983 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus - -#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define LIBUUID_CPP20_OR_GREATER -#endif - -#endif - -#ifdef LIBUUID_CPP20_OR_GREATER -#include -#else -#include -#endif - -#ifdef _WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#ifdef UUID_TIME_GENERATOR -#include -#pragma comment(lib, "IPHLPAPI.lib") -#endif - -#elif defined(__linux__) || defined(__unix__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#elif defined(__APPLE__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#endif - -namespace uuids -{ -#ifdef __cpp_lib_span - template - using span = std::span; -#else - template - using span = gsl::span; -#endif - - namespace detail - { - template - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept - { - if (ch >= static_cast('0') && ch <= static_cast('9')) - return static_cast(ch - static_cast('0')); - if (ch >= static_cast('a') && ch <= static_cast('f')) - return static_cast(10 + ch - static_cast('a')); - if (ch >= static_cast('A') && ch <= static_cast('F')) - return static_cast(10 + ch - static_cast('A')); - return 0; - } - - template - [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast('0') && ch <= static_cast('9')) || - (ch >= static_cast('a') && ch <= static_cast('f')) || - (ch >= static_cast('A') && ch <= static_cast('F')); - } - - template - [[nodiscard]] constexpr std::basic_string_view to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template - [[nodiscard]] constexpr std::basic_string_view - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast(start); - const uint8_t* finish = static_cast(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast((bitCount >> 24) & 0xFF)); - process_byte(static_cast((bitCount >> 16) & 0xFF)); - process_byte(static_cast((bitCount >> 8) & 0xFF)); - process_byte(static_cast((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast(d32[0] >> 24); - digest[di++] = static_cast(d32[0] >> 16); - digest[di++] = static_cast(d32[0] >> 8); - digest[di++] = static_cast(d32[0] >> 0); - - digest[di++] = static_cast(d32[1] >> 24); - digest[di++] = static_cast(d32[1] >> 16); - digest[di++] = static_cast(d32[1] >> 8); - digest[di++] = static_cast(d32[1] >> 0); - - digest[di++] = static_cast(d32[2] >> 24); - digest[di++] = static_cast(d32[2] >> 16); - digest[di++] = static_cast(d32[2] >> 8); - digest[di++] = static_cast(d32[2] >> 0); - - digest[di++] = static_cast(d32[3] >> 24); - digest[di++] = static_cast(d32[3] >> 16); - digest[di++] = static_cast(d32[3] >> 8); - digest[di++] = static_cast(d32[3] >> 0); - - digest[di++] = static_cast(d32[4] >> 24); - digest[di++] = static_cast(d32[4] >> 16); - digest[di++] = static_cast(d32[4] >> 8); - digest[di++] = static_cast(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast(m_block[i * 4 + 0] << 24); - w[i] |= static_cast(m_block[i * 4 + 1] << 16); - w[i] |= static_cast(m_block[i * 4 + 2] << 8); - w[i] |= static_cast(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid[37] = - L"00000000-0000-0000-0000-000000000000"; - - template - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; - } // namespace detail - - // -------------------------------------------------------------------------------------------------------------------------- - // UUID format https://tools.ietf.org/html/rfc4122 - // -------------------------------------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------------------------------------- - // Field NDR Data Type Octet # Note - // -------------------------------------------------------------------------------------------------------------------------- - // time_low unsigned long 0 - 3 The low field - // of the timestamp. time_mid unsigned short 4 - 5 - // The middle field of the timestamp. time_hi_and_version unsigned - // short 6 - 7 The high field of the timestamp multiplexed - // with the version number. clock_seq_hi_and_reserved unsigned small 8 - // The high field of the clock sequence multiplexed with the variant. - // clock_seq_low unsigned small 9 The low - // field of the clock sequence. node character 10 - // - 15 The spatially unique node identifier. - // -------------------------------------------------------------------------------------------------------------------------- - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_low | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_mid | time_hi_and_version | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |clk_seq_hi_res | clk_seq_low | node (0-1) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | node (2-5) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // -------------------------------------------------------------------------------------------------------------------------- - // enumerations - // -------------------------------------------------------------------------------------------------------------------------- - - // indicated by a bit pattern in octet 8, marked with N in - // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx - enum class uuid_variant - { - // NCS backward compatibility (with the obsolete Apollo Network Computing - // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the - // UUID are a 48-bit timestamp (the number of 4 microsecond units of time - // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet - // is the "address family"; > the final 7 octets are a 56-bit host ID in the - // form specified by the address family - ncs, - - // RFC 4122/DCE 1.1 - // N bit pattern: 10xx - // > big-endian byte order - rfc, - - // Microsoft Corporation backward compatibility - // N bit pattern: 110x - // > little endian byte order - // > formely used in the Component Object Model (COM) library - microsoft, - - // reserved for possible future definition - // N bit pattern: 111x - reserved - }; - - // indicated by a bit pattern in octet 6, marked with M in - // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx - enum class uuid_version - { - none = 0, // only possible for nil or invalid uuids - time_based = 1, // The time-based version specified in RFC 4122 - dce_security = 2, // DCE Security version, with embedded POSIX UIDs. - name_based_md5 = - 3, // The name-based version specified in RFS 4122 with MD5 hashing - random_number_based = 4, // The randomly or pseudo-randomly generated version - // specified in RFS 4122 - name_based_sha1 = - 5 // The name-based version specified in RFS 4122 with SHA1 hashing - }; - - // Forward declare uuid & to_string so that we can declare to_string as a friend - // later. - class uuid; - template , class Allocator = std::allocator> - std::basic_string to_string(uuid const& id); - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid class - // -------------------------------------------------------------------------------------------------------------------------- - class uuid - { - public: - using value_type = uint8_t; - - constexpr uuid() noexcept = default; - - uuid(value_type (&arr)[16]) noexcept - { - std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); - } - - constexpr uuid(std::array const& arr) noexcept - : data{arr} - { - } - - explicit uuid(span bytes) - { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template - explicit uuid(ForwardIterator first, ForwardIterator last) - { - if (std::distance(first, last) == 16) - std::copy(first, last, std::begin(data)); - } - - [[nodiscard]] constexpr uuid_variant variant() const noexcept - { - if ((data[8] & 0x80) == 0x00) - return uuid_variant::ncs; - else if ((data[8] & 0xC0) == 0x80) - return uuid_variant::rfc; - else if ((data[8] & 0xE0) == 0xC0) - return uuid_variant::microsoft; - else - return uuid_variant::reserved; - } - - [[nodiscard]] constexpr uuid_version version() const noexcept - { - if ((data[6] & 0xF0) == 0x10) - return uuid_version::time_based; - else if ((data[6] & 0xF0) == 0x20) - return uuid_version::dce_security; - else if ((data[6] & 0xF0) == 0x30) - return uuid_version::name_based_md5; - else if ((data[6] & 0xF0) == 0x40) - return uuid_version::random_number_based; - else if ((data[6] & 0xF0) == 0x50) - return uuid_version::name_based_sha1; - else - return uuid_version::none; - } - - [[nodiscard]] constexpr bool is_nil() const noexcept - { - for (size_t i = 0; i < data.size(); ++i) - if (data[i] != 0) - return false; - return true; - } - - void swap(uuid& other) noexcept - { - data.swap(other.data); - } - - [[nodiscard]] inline span as_bytes() const - { - return span( - reinterpret_cast(data.data()), 16); - } - - template - [[nodiscard]] constexpr static bool is_valid_uuid( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) - return false; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template - [[nodiscard]] constexpr static std::optional from_string( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - std::array data{{0}}; - - if (str.empty()) - return {}; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return {}; - } - - if (firstDigit) - { - data[index] = static_cast(detail::hex2char(str[i]) << 4); - firstDigit = false; - } - else - { - data[index] = - static_cast(data[index] | detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return {}; - } - - return uuid{data}; - } - - private: - std::array data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template - friend std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id); - - template - friend std::basic_string to_string(uuid const& id); - - friend std::hash; - }; - - // -------------------------------------------------------------------------------------------------------------------------- - // operators and non-member functions - // -------------------------------------------------------------------------------------------------------------------------- - - [[nodiscard]] inline bool operator==(uuid const& lhs, - uuid const& rhs) noexcept - { - return lhs.data == rhs.data; - } - - [[nodiscard]] inline bool operator!=(uuid const& lhs, - uuid const& rhs) noexcept - { - return !(lhs == rhs); - } - - [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept - { - return lhs.data < rhs.data; - } - - template - [[nodiscard]] inline std::basic_string to_string( - uuid const& id) - { - std::basic_string uustr{detail::empty_guid}; - - for (size_t i = 0, index = 0; i < 36; ++i) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - continue; - } - uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; - uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; - index++; - } - - return uustr; - } - - template - std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id) - { - s << to_string(id); - return s; - } - - inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept - { - lhs.swap(rhs); - } - - // -------------------------------------------------------------------------------------------------------------------------- - // namespace IDs that could be used for generating name-based uuids - // -------------------------------------------------------------------------------------------------------------------------- - - // Name string is a fully-qualified domain name - static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is a URL - static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an ISO OID (See https://oidref.com/, - // https://en.wikipedia.org/wiki/Object_identifier) - static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an X.500 DN, in DER or a text output format (See - // https://en.wikipedia.org/wiki/X.500, - // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) - static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid generators - // -------------------------------------------------------------------------------------------------------------------------- - -#ifdef UUID_SYSTEM_GENERATOR - class uuid_system_generator - { - public: - using result_type = uuid; - - uuid operator()() - { -#ifdef _WIN32 - - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); - - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } - - std::array bytes = { - {static_cast((newId.Data1 >> 24) & 0xFF), - static_cast((newId.Data1 >> 16) & 0xFF), - static_cast((newId.Data1 >> 8) & 0xFF), - static_cast((newId.Data1) & 0xFF), - - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), - - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), - - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__linux__) || defined(__unix__) - - uuid_t id; - uuid_generate(id); - - std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], - id[6], id[7], id[8], id[9], id[10], - id[11], id[12], id[13], id[14], id[15]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array arrbytes = { - {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, - bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, - bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, - bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; -#else - return uuid{}; -#endif - } - }; -#endif - - template - class basic_uuid_random_generator - { - public: - using engine_type = UniformRandomNumberGenerator; - - explicit basic_uuid_random_generator(engine_type& gen) - : generator(&gen, [](auto) {}) - { - } - explicit basic_uuid_random_generator(engine_type* gen) - : generator(gen, [](auto) {}) - { - } - - [[nodiscard]] uuid operator()() - { - alignas(uint32_t) uint8_t bytes[16]; - for (int i = 0; i < 16; i += 4) - *reinterpret_cast(bytes + i) = distribution(*generator); - - // variant must be 10xxxxxx - bytes[8] &= 0xBF; - bytes[8] |= 0x80; - - // version must be 0100xxxx - bytes[6] &= 0x4F; - bytes[6] |= 0x40; - - return uuid{std::begin(bytes), std::end(bytes)}; - } - - private: - std::uniform_int_distribution distribution; - std::shared_ptr generator; - }; - - using uuid_random_generator = basic_uuid_random_generator; - - class uuid_name_generator - { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept - : nsuuid(namespace_uuid) - { - } - - template - [[nodiscard]] uuid operator()(StringType const& name) - { - reset(); - process_characters(detail::to_string_view(name)); - return make_uuid(); - } - - private: - void reset() - { - hasher.reset(); - std::byte bytes[16]; - auto nsbytes = nsuuid.as_bytes(); - std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); - hasher.process_bytes(bytes, 16); - } - - template - void process_characters(std::basic_string_view const str) - { - for (uint32_t c : str) - { - hasher.process_byte(static_cast(c & 0xFF)); - if constexpr (!std::is_same_v) - { - hasher.process_byte(static_cast((c >> 8) & 0xFF)); - hasher.process_byte(static_cast((c >> 16) & 0xFF)); - hasher.process_byte(static_cast((c >> 24) & 0xFF)); - } - } - } - - [[nodiscard]] uuid make_uuid() - { - detail::sha1::digest8_t digest; - hasher.get_digest_bytes(digest); - - // variant must be 0b10xxxxxx - digest[8] &= 0xBF; - digest[8] |= 0x80; - - // version must be 0b0101xxxx - digest[6] &= 0x5F; - digest[6] |= 0x50; - - return uuid{digest, digest + 16}; - } - - private: - uuid nsuuid; - detail::sha1 hasher; - }; - -#ifdef UUID_TIME_GENERATOR - // !!! DO NOT USE THIS IN PRODUCTION - // this implementation is unreliable for good uuids - class uuid_time_generator - { - using mac_address = std::array; - - std::optional device_address; - - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } - -#ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) - return false; - std::vector buf(len); - auto pips = reinterpret_cast(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) - return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; -#endif - - return device_address.has_value(); - } - - [[nodiscard]] long long get_time_intervals() - { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = - std::chrono::duration_cast(diff).count(); - return ns / 100; - } - - [[nodiscard]] static unsigned short get_clock_sequence() - { - static std::mt19937 clock_gen(std::random_device{}()); - static std::uniform_int_distribution clock_dis; - static std::atomic_ushort clock_sequence = clock_dis(clock_gen); - return clock_sequence++; - } - - public: - [[nodiscard]] uuid operator()() - { - if (get_mac_address()) - { - std::array data; - - auto tm = get_time_intervals(); - - auto clock_seq = get_clock_sequence(); - - auto ptm = reinterpret_cast(&tm); - - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); - - memcpy(&data[8], &clock_seq, 2); - - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; - - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; - - memcpy(&data[10], &device_address.value()[0], 6); - - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } - - return {}; - } - }; -#endif -} // namespace uuids - -namespace std -{ - template <> - struct hash - { - using argument_type = uuids::uuid; - using result_type = std::size_t; - - [[nodiscard]] result_type operator()(argument_type const& uuid) const - { -#ifdef UUID_HASH_STRING_BASED - std::hash hasher; - return static_cast(hasher(uuids::to_string(uuid))); -#else - uint64_t l = static_cast(uuid.data[0]) << 56 | - static_cast(uuid.data[1]) << 48 | - static_cast(uuid.data[2]) << 40 | - static_cast(uuid.data[3]) << 32 | - static_cast(uuid.data[4]) << 24 | - static_cast(uuid.data[5]) << 16 | - static_cast(uuid.data[6]) << 8 | - static_cast(uuid.data[7]); - uint64_t h = static_cast(uuid.data[8]) << 56 | - static_cast(uuid.data[9]) << 48 | - static_cast(uuid.data[10]) << 40 | - static_cast(uuid.data[11]) << 32 | - static_cast(uuid.data[12]) << 24 | - static_cast(uuid.data[13]) << 16 | - static_cast(uuid.data[14]) << 8 | - static_cast(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) - { - return result_type(l ^ h); - } - else - { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } -#endif - } - }; -} // namespace std - -#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Comm/Version.hxx b/Comm/Version.hxx deleted file mode 100644 index ab02cf6..0000000 --- a/Comm/Version.hxx +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define kDistVersion "v1.21" diff --git a/Examples/ExampleCDialect.S b/Examples/ExampleCDialect.S index 9d90d46..1eb2f82 100644 --- a/Examples/ExampleCDialect.S +++ b/Examples/ExampleCDialect.S @@ -1,4 +1,4 @@ -; Path: Examples/ExampleCDialect.cc +; Path: Examples/ExampleCDialect.cxx ; Language: MPCC assembly. (Generated from C++) ; Date: 2024-5-14 diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp new file mode 100644 index 0000000..b492ce8 --- /dev/null +++ b/Headers/AsmKit/AsmKit.hpp @@ -0,0 +1,217 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include +#include + +namespace CompilerKit +{ + // + // @brief Frontend to Assembly mountpoint. + // + class AssemblyInterface + { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + MPCC_COPY_DEFAULT(AssemblyInterface); + + //@ brief compile to object file. + // Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; + }; + + /// @brief Simple assembly factory + class AssemblyFactory final + { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + MPCC_COPY_DEFAULT(AssemblyFactory); + + public: + enum + { + kArchAMD64, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchUnknown, + }; + + Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; + }; + + union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; + }; + + union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) + : raw(raw) + { + } + ~NumberCast64() + { + raw = 0; + } + + CharType number[8]; + UInt64 raw; + }; + + union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) + : raw(raw) + { + } + ~NumberCast32() + { + raw = 0; + } + + CharType number[4]; + UInt32 raw; + }; + + union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) + : raw(raw) + { + } + ~NumberCast16() + { + raw = 0; + } + + CharType number[2]; + UInt16 raw; + }; + + union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) + : raw(raw) + { + } + ~NumberCast8() + { + raw = 0; + } + + CharType number; + UInt8 raw; + }; + + class EncoderInterface + { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + MPCC_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string& line, const std::string& file) = 0; + virtual bool WriteLine(std::string& line, const std::string& file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; + }; + +#ifdef __ASM_NEED_AMD64__ + + class EncoderAMD64 final : public EncoderInterface + { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; + + MPCC_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + + virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); + }; + +#endif // __ASM_NEED_AMD64__ + +#ifdef __ASM_NEED_64x0__ + + class Encoder64x0 final : public EncoderInterface + { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + MPCC_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_64x0__ + +#ifdef __ASM_NEED_32x0__ + + class Encoder32x0 final : public EncoderInterface + { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; + + MPCC_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ + +#ifdef __ASM_NEED_PPC__ + + class EncoderPowerPC final : public EncoderInterface + { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; + + MPCC_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ +} // namespace CompilerKit diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp new file mode 100644 index 0000000..cfe4a47 --- /dev/null +++ b/Headers/AsmKit/CPU/32x0.hpp @@ -0,0 +1,95 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @brief 32x0 support. +// @file CPU/32x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 + +#define kAsmByte 0 +#define kAsmHWord 1 +#define kAsmWord 2 + +struct CpuCode32x0 +{ + const char fName[32]; + char fOpcode; + char fSize; + char fFunct3; + char fFunct7; +}; + +#define kAsmDWordStr ".dword" /* 64 bit */ +#define kAsmWordStr ".word" /* 32-bit */ +#define kAsmHWordStr ".half" /* 16-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ + +inline std::vector kOpcodes32x0 = { + kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. + kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch + kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers + kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp + kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. + kAsmOpcodeDecl("cls", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR. + kAsmOpcodeDecl("rts", 0b0111011, 0b110, + kAsmImmediate) // pull stack and return form CR. + kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt +}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: TODO: find one +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp new file mode 100644 index 0000000..2da4f24 --- /dev/null +++ b/Headers/AsmKit/CPU/64x0.hpp @@ -0,0 +1,108 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +// @brief 64x0 support. +// @file CPU/64x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 + +typedef char e64k_character_t; +typedef uint8_t e64k_num_t; + +struct CpuOpcode64x0 +{ + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; +}; + +inline std::vector kOpcodes64x0 = { + kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) + kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) + kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) + kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL/JUMP ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp new file mode 100644 index 0000000..bc4b956 --- /dev/null +++ b/Headers/AsmKit/CPU/amd64.hpp @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @brief AMD64 support. +// @file CPU/amd64.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, + +typedef char i64_character_t; +typedef uint8_t i64_byte_t; +typedef uint16_t i64_hword_t; +typedef uint32_t i64_word_t; + +struct CpuOpcodeAMD64 +{ + std::string fName; + i64_byte_t fPrefixBytes[4]; + i64_hword_t fOpcode; + i64_hword_t fModReg; + i64_word_t fDisplacment; + i64_word_t fImmediate; +}; + +/// these two are edge cases +#define kAsmIntOpcode 0xCC +#define kasmIntOpcodeAlt 0xCD + +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 +#define kJumpLimitStandardLimit 0xEB + +inline std::vector kOpcodesAMD64 = { + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF) +}; + +#define kAsmRegisterLimit 15 diff --git a/Headers/AsmKit/CPU/arm64.hpp b/Headers/AsmKit/CPU/arm64.hpp new file mode 100644 index 0000000..e7d4f68 --- /dev/null +++ b/Headers/AsmKit/CPU/arm64.hpp @@ -0,0 +1,26 @@ +/* ------------------------------------------- + +Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +/// @brief ARM64 encoding support. +/// @file CPU/arm64.hpp + +struct CpuOpcodeArm64; + +/// @brief ARM64 opcode header. +struct CpuOpcodeArm64 final +{ + uint8_t fOpcode; // opcode + uint8_t fRegisterLeft; // left register index + uint8_t fRegisterRight; // right register index + bool fRegisterLeftHooked; + bool fRegisterRightHooked; + uint32_t fImmediateValue; // immediate 32-bit value + bool fImmediateValueHooked; +}; diff --git a/Headers/AsmKit/CPU/ppc.hpp b/Headers/AsmKit/CPU/ppc.hpp new file mode 100644 index 0000000..e3ea6c5 --- /dev/null +++ b/Headers/AsmKit/CPU/ppc.hpp @@ -0,0 +1,1929 @@ +/* ------------------------------------------- + + Some modifications are copyrighted under: + ZKA Technologies + + Original author: + Apple Inc + +------------------------------------------- */ + +#pragma once + +#include + +/// @note Based of: +/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html + +/* + * These defines are use in the cpus field of the instructions. If the field + * is zero it can execute on all cpus. The defines are or'ed together. This + * information is used to set the cpusubtype in the resulting object file. + */ +#define CPU601 0x1 +#define IMPL64 0x2 +#define OPTIONAL 0x4 +#define VMX 0x8 +#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ +#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ + +enum optype +{ + NONE, /* no operand */ + JBSR, /* jbsr pseudo op */ + PCREL, /* PC relative (branch offset) */ + BADDR, /* Branch address (sign extended absolute address) */ + D, /* 16 bit displacement */ + DS, /* 14 bit displacement (double word) */ + SI, /* signed 16 bit immediate */ + UI, /* unsigned 16 bit immediate */ + HI, /* high 16 bit immediate (with truncation) */ + GREG, /* general register */ + G0REG, /* general register r1-r31 or 0 */ + FREG, /* float register */ + VREG, /* vector register */ + SGREG, /* segment register */ + SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ + BCND, /* branch condition opcode */ + CRF, /* condition register field */ + CRFONLY, /* condition register field only no expression allowed */ + sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ + mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ + NUM, /* number */ + SNUM, /* signed number */ + NUM0, /* number (where 1< + +#define SizeType size_t + +#define VoidPtr void* +#define voidPtr VoidPtr + +#define UIntPtr uintptr_t + +#define Int64 int64_t +#define UInt64 uint64_t + +#define Int32 int +#define UInt32 unsigned + +#define Bool bool + +#define Int16 int16_t +#define UInt16 uint16_t + +#define Int8 int8_t +#define UInt8 uint8_t + +#define CharType char +#define Boolean bool + +#include +#include +#include + +#define nullPtr std::nullptr_t + +#define MUST_PASS(E) assert(E) + +#ifndef __FORCE_STRLEN +#define __FORCE_STRLEN 1 + +#define string_length(len) strlen(len) +#endif + +#ifndef __FORCE_MEMCPY +#define __FORCE_MEMCPY 1 + +#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) +#endif + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#include +#include +#include +#include + +namespace CompilerKit +{ + inline constexpr int BASE_YEAR = 1900; + + inline std::string current_date() noexcept + { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); + + std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); + + return fmt; + } + + inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept + { + if (limit == 0) + return false; + + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; + + while (limit != 1) + { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; + } +} // namespace CompilerKit + +#define PACKED __attribute__((packed)) + +typedef char char_type; + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts \ + { \ + ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ + } + +#ifdef __NDK_MODULE__ +#define NDK_MODULE(name) int name(int argc, char** argv) +#else +#define NDK_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __NDK_MODULE__ */ + +#pragma scalar_storage_order big-endian + +#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Headers/Macros.hpp b/Headers/Macros.hpp new file mode 100644 index 0000000..c190cda --- /dev/null +++ b/Headers/Macros.hpp @@ -0,0 +1,33 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// @brief provide support for Macros.hpp header. + +#ifndef _CK_CL_HPP +#define _CK_CL_HPP + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +/// @note xxxx is the error placeholder, in hexadecimal. +#define MPCC_ERROR_PREFIX_CXX "CXXxxxx" +#define MPCC_ERROR_PREFIX_CL "CLxxxx" +#define MPCC_ERROR_PREFIX_ASM "ASMxxxx" + +#endif /* ifndef _CK_CL_HPP */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp new file mode 100644 index 0000000..186c9cf --- /dev/null +++ b/Headers/ParserKit.hpp @@ -0,0 +1,173 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +namespace ParserKit +{ + using namespace CompilerKit; + + /// @brief Compiler backend, implements a frontend, such as C, C++... + /// See Toolchain, for some examples. + class CompilerBackend + { + public: + explicit CompilerBackend() = default; + virtual ~CompilerBackend() = default; + + MPCC_COPY_DEFAULT(CompilerBackend); + + // NOTE: cast this to your user defined ast. + typedef void* AstType; + + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + + virtual bool Compile(const std::string& text, const char* file) = 0; + + //! @brief What language are we dealing with? + virtual const char* Language() + { + return "Invalid Language"; + } + }; + + struct SyntaxLeafList; + struct SyntaxLeafList; + struct CompilerKeyword; + + /// we want to do that because to separate keywords. + enum KeywordKind + { + eKeywordKindNamespace, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, + eKeywordKindVariable, + eKeywordKindVariablePtr, + eKeywordKindType, + eKeywordKindTypePtr, + eKeywordKindExpressionBegin, + eKeywordKindExpressionEnd, + eKeywordKindArgSeparator, + eKeywordKindBodyStart, + eKeywordKindBodyEnd, + eKeywordKindClass, + eKeywordKindPtrAccess, + eKeywordKindAccess, + eKeywordKindIf, + eKeywordKindElse, + eKeywordKindElseIf, + eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, + eKeywordKindConstant, + eKeywordKindTypedef, + eKeywordKindEndInstr, + eKeywordKindSpecifier, + eKeywordKindInvalid, + eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, + }; + + /// \brief Compiler keyword information struct. + struct CompilerKeyword + { + std::string keyword_name; + KeywordKind keyword_kind = eKeywordKindInvalid; + }; + struct SyntaxLeafList final + { + struct SyntaxLeaf final + { + Int32 fUserType; +#ifdef __PK_USE_STRUCT_INSTEAD__ + CompilerKeyword fUserData; +#else + std::string fUserData; +#endif + + std::string fUserValue; + struct SyntaxLeaf* fNext; + }; + + std::vector fLeafList; + SizeType fNumLeafs; + + size_t SizeOf() + { + return fNumLeafs; + } + std::vector& Get() + { + return fLeafList; + } + SyntaxLeaf& At(size_t index) + { + return fLeafList[index]; + } + }; + + /// find the perfect matching word in a haystack. + /// \param haystack base string + /// \param needle the string we search for. + /// \return if we found it or not. + inline bool find_word(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) + return true; + + if (index < 0 || index >= haystack.size()) + return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); + } + + /// find a word within strict conditions and returns a range of it. + /// \param haystack + /// \param needle + /// \return position of needle. + inline std::size_t find_word_range(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) + { + return index; + } + + return false; + } +} // namespace ParserKit diff --git a/Headers/Public/SDK/CRT/__mpcc_alloca.hxx b/Headers/Public/SDK/CRT/__mpcc_alloca.hxx new file mode 100644 index 0000000..02b3123 --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_alloca.hxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +typedef void* ptr_type; +typedef __SIZE_TYPE__ size_type; + +inline void* __mpcc_alloca_gcc(size_type sz) +{ + return __builtin_alloca(sz); +} diff --git a/Headers/Public/SDK/CRT/__mpcc_defines.hxx b/Headers/Public/SDK/CRT/__mpcc_defines.hxx new file mode 100644 index 0000000..19ed8a4 --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_defines.hxx @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#ifndef __MPCC_DEF__ +#define __MPCC_DEF__ + +#ifndef __GNUC__ + +typedef __SIZE_TYPE__ size_t; + +#ifdef __LP64__ +typedef long int ssize_t; +#else +typedef int ssize_t; +#endif // __LP64__ + +typedef size_t ptrdiff_t; +typedef size_t uintptr_t; +typedef void* voidptr_t; +typedef void* any_t; +typedef char* caddr_t; + +#ifndef NULL +#define NULL ((voidptr_t)0) +#endif // !null + +#ifdef __GNUC__ +#include +#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#define __packed__ __attribute__((packed)) +#elif defined(__MPCC__) +#define __packed__ __mpcc_packed__ +#define __alloca(sz) __mpcc_alloca(sz) +#endif + +#define __deref(ptr) (*(ptr)) + +#ifdef __cplusplus +#define __init_decl() \ + extern "C" \ + { + + +#define __fini_decl() \ + }; \ + + +#else +#define __init_decl() +#define __fini_decl() +#endif + +typedef long long off_t; +typedef unsigned long long uoff_t; + +typedef union float_cast { + struct + { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int sign : 1; + }; + + float f; +} __packed__ float_cast_t; + +typedef union double_cast { + struct + { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; +} __packed__ double_cast_t; + +#endif // ifndef __GNUC__ + +#endif /* __MPCC_DEF__ */ diff --git a/Headers/Public/SDK/CRT/__mpcc_exception.hxx b/Headers/Public/SDK/CRT/__mpcc_exception.hxx new file mode 100644 index 0000000..4a9f84a --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_exception.hxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +/// This file is an implementation of __throw* family of functions. + +#include +#include +#include + +namespace std +{ + inline void __throw_general(void) + { + throw std::runtime_error("MPCC C++ Runtime error."); + } + + inline void __throw_domain_error(const char* error) + { + std::cout << "MPCC C++: Domain error: " << error << "\r"; + __throw_general(); + } +} // namespace std diff --git a/Headers/Public/SDK/CRT/__mpcc_hint.hxx b/Headers/Public/SDK/CRT/__mpcc_hint.hxx new file mode 100644 index 0000000..02dbc94 --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_hint.hxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#pragma compiler(hint_manifest) + +#define _Input +#define _Output + +#define _Optional + +#define _StrictCheckInput +#define _StrictCheckOutput + +#define _InOut +#define _StrictInOut diff --git a/Headers/Public/SDK/CRT/__mpcc_malloc.hxx b/Headers/Public/SDK/CRT/__mpcc_malloc.hxx new file mode 100644 index 0000000..eeaa67b --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_malloc.hxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +namespace stdx +{ + /// @brief allocate a new class. + /// @tparam KindClass the class type to allocate. + template + inline void* allocate(Args&&... args) + { + return new KindClass(std::forward(args)...); + } + + /// @brief free a class. + /// @tparam KindClass the class type to allocate. + template + inline void release(KindClass ptr) + { + if (!ptr) + return; + delete ptr; + } +} // namespace stdx diff --git a/Headers/Public/SDK/CRT/__mpcc_power.inc b/Headers/Public/SDK/CRT/__mpcc_power.inc new file mode 100644 index 0000000..9e4928c --- /dev/null +++ b/Headers/Public/SDK/CRT/__mpcc_power.inc @@ -0,0 +1,35 @@ +# Path: SDK/__mpcc_power.inc +# Language: MPCC POWER Assembly support for GNU. +# Build Date: 2024-6-4 + +%ifdef __CODETOOLS__ + +%def lda li +%def sta stw +%def ldw li + +%def r0 0 +%def r1 1 +%def r2 2 +%def r3 3 +%def r4 4 +%def r5 5 +%def r6 6 +%def r7 7 +%def r8 8 +%def r9 9 +%def r10 10 +%def r11 11 +%def r12 12 +%def r13 13 +%def r14 14 +%def r15 15 +%def r16 16 +%def r17 17 +%def r18 18 +%def r19 19 +%def r20 20 + +%endif + +%def nop mr 0, 0 diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp new file mode 100644 index 0000000..baa4249 --- /dev/null +++ b/Headers/StdKit/AE.hpp @@ -0,0 +1,143 @@ +/* + * ======================================================== + * + * MPCC + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include + +#define kAEMag0 'A' +#define kAEMag1 'E' + +#define kAESymbolLen 64 +#define kAEPad 8 +#define kAEMagLen 2 +#define kAEInvalidOpcode 0x00 + +// Advanced Executable File Format for MetroLink. +// Reloctable by offset is the default strategy. +// You can also relocate at runtime but that's up to the operating system +// loader. + +namespace CompilerKit +{ + // @brief Advanced Executable Header + // One thing to keep in mind. + // This object format, is reloctable. + typedef struct AEHeader final + { + CharType fMagic[kAEMagLen]; + CharType fArch; + CharType fSubArch; + SizeType fCount; + CharType fSize; + SizeType fStartCode; + SizeType fCodeSize; + CharType fPad[kAEPad]; + } PACKED AEHeader, *AEHeaderPtr; + + // @brief Advanced Executable Record. + // Could be data, code or bss. + // fKind must be filled with PEF fields. + + typedef struct AERecordHeader final + { + CharType fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + CharType fPad[kAEPad]; + } PACKED AERecordHeader, *AERecordHeaderPtr; + + enum + { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, + }; +} // namespace CompilerKit + +// provide operator<< for AE + +std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); + + return fp; +} + +std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); + + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); + return fp; +} + +namespace CompilerKit::Utils +{ + /** + * @brief AE Reader protocol + * + */ + class AEReadableProtocol final + { + public: + std::ifstream FP; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + MPCC_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) + { + if (!raw) + return nullptr; + + return this->_Read(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template + TypeClass* _Read(char* raw, std::size_t sz) + { + FP.read(raw, std::streamsize(sz)); + return reinterpret_cast(raw); + } + }; +} // namespace CompilerKit::Utils diff --git a/Headers/StdKit/ELF.hpp b/Headers/StdKit/ELF.hpp new file mode 100644 index 0000000..4f0d0ae --- /dev/null +++ b/Headers/StdKit/ELF.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include +#include + +struct file; + +#ifndef elf_read_implies_exec +/* Executables for which elf_read_implies_exec() returns TRUE will + have the READ_IMPLIES_EXEC personality flag set automatically. + Override in asm/elf.h as needed. */ +#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 +#endif + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uintptr_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x)&0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* POWER VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; diff --git a/Headers/StdKit/ErrorID.hpp b/Headers/StdKit/ErrorID.hpp new file mode 100644 index 0000000..41d6b2f --- /dev/null +++ b/Headers/StdKit/ErrorID.hpp @@ -0,0 +1,22 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +#define MPCC_EXEC_ERROR -30 +#define MPCC_FILE_NOT_FOUND -31 +#define MPCC_DIR_NOT_FOUND -32 +#define MPCC_FILE_EXISTS -33 +#define MPCC_TOO_LONG -34 +#define MPCC_INVALID_DATA -35 +#define MPCC_UNIMPLEMENTED -36 +#define MPCC_FAT_ERROR -37 diff --git a/Headers/StdKit/ErrorOr.hpp b/Headers/StdKit/ErrorOr.hpp new file mode 100644 index 0000000..6c8e87e --- /dev/null +++ b/Headers/StdKit/ErrorOr.hpp @@ -0,0 +1,61 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + using ErrorT = UInt32; + + template + class ErrorOr final + { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) + : mId(err) + { + } + + explicit ErrorOr(nullPtr Null) + { + } + + explicit ErrorOr(T Class) + : mRef(Class) + { + } + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref Leak() + { + return mRef; + } + + operator bool() + { + return mRef; + } + + private: + Ref mRef; + Int32 mId{0}; + }; + + using ErrorOrAny = ErrorOr; + +} // namespace CompilerKit diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp new file mode 100644 index 0000000..d8709ed --- /dev/null +++ b/Headers/StdKit/PEF.hpp @@ -0,0 +1,134 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @file PEF.hpp +// @brief Preferred Executable Format + +#define kPefMagic "Joy!" +#define kPefMagicFat "yoJ!" + +#define kPefExt ".exec" +#define kPefDylibExt ".lib" +#define kPefLibExt ".slib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" + +#define kPefMagicLen 5 + +#define kPefVersion 2 +#define kPefNameLen 255 + +#define kPefBaseOrigin (0x1000000) + +#define kPefStart "__ImageStart" + +namespace CompilerKit +{ + enum + { + kPefArchStart = 99, + kPefArchIntel86S = 100, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* 64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, + }; + + enum + { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchGeneric, + kPefSubArchIBM, + }; + + enum + { + kPefKindExec = 1, /* .exe */ + kPefKindSharedObject = 2, /* .lib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, + }; + + /* PEF container */ + typedef struct PEFContainer final + { + CharType Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ + } PACKED PEFContainer; + + /* First PEFCommandHeader starts after PEFContainer */ + /* Last container is __exec_end */ + + /* PEF executable section and commands. */ + + typedef struct PEFCommandHeader final + { + CharType Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* file offset */ + SizeType Size; /* file size */ + } PACKED PEFCommandHeader; + + enum + { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, + kPefInvalid = 0xFF, + }; +} // namespace CompilerKit + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} diff --git a/Headers/StdKit/Ref.hpp b/Headers/StdKit/Ref.hpp new file mode 100644 index 0000000..e655ccb --- /dev/null +++ b/Headers/StdKit/Ref.hpp @@ -0,0 +1,91 @@ + +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +namespace CompilerKit +{ + // @author ZKA Technologies + // @brief Reference class, refers to a pointer of data in static memory. + template + class Ref final + { + public: + explicit Ref() = default; + ~Ref() = default; + + public: + explicit Ref(T cls, const bool& strong = false) + : m_Class(cls), m_Strong(strong) + { + } + + Ref& operator=(T ref) + { + m_Class = ref; + return *this; + } + + public: + T operator->() const + { + return m_Class; + } + + T& Leak() + { + return m_Class; + } + + T operator*() + { + return m_Class; + } + + bool IsStrong() const + { + return m_Strong; + } + + operator bool() + { + return m_Class; + } + + private: + T m_Class; + bool m_Strong{false}; + }; + + template + class NonNullRef final + { + public: + NonNullRef() = delete; + NonNullRef(nullPtr) = delete; + + explicit NonNullRef(T* ref) + : m_Ref(ref, true) + { + } + + Ref& operator->() + { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef& ref) = delete; + NonNullRef(const NonNullRef& ref) = default; + + private: + Ref m_Ref{nullptr}; + }; +} // namespace CompilerKit diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp new file mode 100644 index 0000000..59a7997 --- /dev/null +++ b/Headers/StdKit/String.hpp @@ -0,0 +1,90 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + /** + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + + class StringView final + { + public: + explicit StringView() = delete; + + explicit StringView(SizeType Sz) noexcept + : m_Sz(Sz) + { + m_Data = new char[Sz]; + assert(m_Data); + } + + ~StringView() noexcept + { + if (m_Data) + { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + MPCC_COPY_DEFAULT(StringView); + + CharType* Data(); + const CharType* CData() const; + SizeType Length() const; + + bool operator==(const CharType* rhs) const; + bool operator!=(const CharType* rhs) const; + + bool operator==(const StringView& rhs) const; + bool operator!=(const StringView& rhs) const; + + StringView& operator+=(const CharType* rhs); + StringView& operator+=(const StringView& rhs); + + operator bool() + { + return m_Data && m_Data[0] != 0; + } + + bool operator!() + { + return !m_Data || m_Data[0] == 0; + } + + private: + char* m_Data{nullptr}; + SizeType m_Sz{0}; + SizeType m_Cur{0}; + + friend class StringBuilder; + }; + + /** + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ + struct StringBuilder final + { + static StringView Construct(const CharType* data); + static const char* FromInt(const char* fmt, int n); + static const char* FromBool(const char* fmt, bool n); + static const char* Format(const char* fmt, const char* from); + static bool Equals(const char* lhs, const char* rhs); + }; +} // namespace CompilerKit diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx new file mode 100644 index 0000000..dbc258d --- /dev/null +++ b/Headers/StdKit/XCOFF.hxx @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + + File: XCOFF.hpp + Purpose: XCOFF for NewOS. + + Revision History: + + 04/07/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __XCOFF__ +#define __XCOFF__ + +#include + +#define kXCOFF64Magic 0x01F7 + +#define kXCOFFRelFlg 0x0001 +#define kXCOFFExecutable 0x0002 +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace CompilerKit +{ + /// @brief XCoff identification header. + typedef struct XCoffFileHeader + { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header + } XCoffFileHeader; +} // namespace CompilerKit + +#endif // ifndef __XCOFF__ diff --git a/Headers/UUID.hpp b/Headers/UUID.hpp new file mode 100644 index 0000000..00b153b --- /dev/null +++ b/Headers/UUID.hpp @@ -0,0 +1,983 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define LIBUUID_CPP20_OR_GREATER +#endif + +#endif + +#ifdef LIBUUID_CPP20_OR_GREATER +#include +#else +#include +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#ifdef UUID_TIME_GENERATOR +#include +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#endif + +namespace uuids +{ +#ifdef __cpp_lib_span + template + using span = std::span; +#else + template + using span = gsl::span; +#endif + + namespace detail + { + template + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept + { + if (ch >= static_cast('0') && ch <= static_cast('9')) + return static_cast(ch - static_cast('0')); + if (ch >= static_cast('a') && ch <= static_cast('f')) + return static_cast(10 + ch - static_cast('a')); + if (ch >= static_cast('A') && ch <= static_cast('F')) + return static_cast(10 + ch - static_cast('A')); + return 0; + } + + template + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept + { + return (ch >= static_cast('0') && ch <= static_cast('9')) || + (ch >= static_cast('a') && ch <= static_cast('f')) || + (ch >= static_cast('A') && ch <= static_cast('F')); + } + + template + [[nodiscard]] constexpr std::basic_string_view to_string_view( + TChar const* str) noexcept + { + if (str) + return str; + return {}; + } + + template + [[nodiscard]] constexpr std::basic_string_view + to_string_view(StringType const& str) noexcept + { + return str; + } + + class sha1 + { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate( + uint32_t value, size_t const count) noexcept + { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() + { + reset(); + } + + void reset() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) + { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) + { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) + { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) + { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) + { + const uint8_t* block = static_cast(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) + { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) + { + while (m_blockByteIndex != 0) + { + process_byte(0); + } + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + else + { + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast((bitCount >> 24) & 0xFF)); + process_byte(static_cast((bitCount >> 16) & 0xFF)); + process_byte(static_cast((bitCount >> 8) & 0xFF)); + process_byte(static_cast((bitCount)&0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) + { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast(d32[0] >> 24); + digest[di++] = static_cast(d32[0] >> 16); + digest[di++] = static_cast(d32[0] >> 8); + digest[di++] = static_cast(d32[0] >> 0); + + digest[di++] = static_cast(d32[1] >> 24); + digest[di++] = static_cast(d32[1] >> 16); + digest[di++] = static_cast(d32[1] >> 8); + digest[di++] = static_cast(d32[1] >> 0); + + digest[di++] = static_cast(d32[2] >> 24); + digest[di++] = static_cast(d32[2] >> 16); + digest[di++] = static_cast(d32[2] >> 8); + digest[di++] = static_cast(d32[2] >> 0); + + digest[di++] = static_cast(d32[3] >> 24); + digest[di++] = static_cast(d32[3] >> 16); + digest[di++] = static_cast(d32[3] >> 8); + digest[di++] = static_cast(d32[3] >> 0); + + digest[di++] = static_cast(d32[4] >> 24); + digest[di++] = static_cast(d32[4] >> 16); + digest[di++] = static_cast(d32[4] >> 8); + digest[di++] = static_cast(d32[4] >> 0); + + return digest; + } + + private: + void process_block() + { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) + { + w[i] = static_cast(m_block[i * 4 + 0] << 24); + w[i] |= static_cast(m_block[i * 4 + 1] << 16); + w[i] |= static_cast(m_block[i * 4 + 2] << 8); + w[i] |= static_cast(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) + { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) + { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) + { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid[37] = + L"00000000-0000-0000-0000-000000000000"; + + template + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; + } // namespace detail + + // -------------------------------------------------------------------------------------------------------------------------- + // UUID format https://tools.ietf.org/html/rfc4122 + // -------------------------------------------------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------------------------------------------------- + // Field NDR Data Type Octet # Note + // -------------------------------------------------------------------------------------------------------------------------- + // time_low unsigned long 0 - 3 The low field + // of the timestamp. time_mid unsigned short 4 - 5 + // The middle field of the timestamp. time_hi_and_version unsigned + // short 6 - 7 The high field of the timestamp multiplexed + // with the version number. clock_seq_hi_and_reserved unsigned small 8 + // The high field of the clock sequence multiplexed with the variant. + // clock_seq_low unsigned small 9 The low + // field of the clock sequence. node character 10 + // - 15 The spatially unique node identifier. + // -------------------------------------------------------------------------------------------------------------------------- + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // -------------------------------------------------------------------------------------------------------------------------- + // enumerations + // -------------------------------------------------------------------------------------------------------------------------- + + // indicated by a bit pattern in octet 8, marked with N in + // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx + enum class uuid_variant + { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved + }; + + // indicated by a bit pattern in octet 6, marked with M in + // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx + enum class uuid_version + { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = + 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = + 5 // The name-based version specified in RFS 4122 with SHA1 hashing + }; + + // Forward declare uuid & to_string so that we can declare to_string as a friend + // later. + class uuid; + template , class Allocator = std::allocator> + std::basic_string to_string(uuid const& id); + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid class + // -------------------------------------------------------------------------------------------------------------------------- + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept + { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array const& arr) noexcept + : data{arr} + { + } + + explicit uuid(span bytes) + { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template + explicit uuid(ForwardIterator first, ForwardIterator last) + { + if (std::distance(first, last) == 16) + std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept + { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept + { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept + { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) + return false; + return true; + } + + void swap(uuid& other) noexcept + { + data.swap(other.data); + } + + [[nodiscard]] inline span as_bytes() const + { + return span( + reinterpret_cast(data.data()), 16); + } + + template + [[nodiscard]] constexpr static bool is_valid_uuid( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) + return false; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return false; + } + + if (firstDigit) + { + firstDigit = false; + } + else + { + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return false; + } + + return true; + } + + template + [[nodiscard]] constexpr static std::optional from_string( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array data{{0}}; + + if (str.empty()) + return {}; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return {}; + } + + if (firstDigit) + { + data[index] = static_cast(detail::hex2char(str[i]) << 4); + firstDigit = false; + } + else + { + data[index] = + static_cast(data[index] | detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return {}; + } + + return uuid{data}; + } + + private: + std::array data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template + friend std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id); + + template + friend std::basic_string to_string(uuid const& id); + + friend std::hash; + }; + + // -------------------------------------------------------------------------------------------------------------------------- + // operators and non-member functions + // -------------------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] inline bool operator==(uuid const& lhs, + uuid const& rhs) noexcept + { + return lhs.data == rhs.data; + } + + [[nodiscard]] inline bool operator!=(uuid const& lhs, + uuid const& rhs) noexcept + { + return !(lhs == rhs); + } + + [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data < rhs.data; + } + + template + [[nodiscard]] inline std::basic_string to_string( + uuid const& id) + { + std::basic_string uustr{detail::empty_guid}; + + for (size_t i = 0, index = 0; i < 36; ++i) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + continue; + } + uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; + uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; + index++; + } + + return uustr; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id) + { + s << to_string(id); + return s; + } + + inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept + { + lhs.swap(rhs); + } + + // -------------------------------------------------------------------------------------------------------------------------- + // namespace IDs that could be used for generating name-based uuids + // -------------------------------------------------------------------------------------------------------------------------- + + // Name string is a fully-qualified domain name + static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is a URL + static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an ISO OID (See https://oidref.com/, + // https://en.wikipedia.org/wiki/Object_identifier) + static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an X.500 DN, in DER or a text output format (See + // https://en.wikipedia.org/wiki/X.500, + // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) + static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid generators + // -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR + class uuid_system_generator + { + public: + using result_type = uuid; + + uuid operator()() + { +#ifdef _WIN32 + + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) + { + throw std::system_error(hr, std::system_category(), + "CoCreateGuid failed"); + } + + std::array bytes = { + {static_cast((newId.Data1 >> 24) & 0xFF), + static_cast((newId.Data1 >> 16) & 0xFF), + static_cast((newId.Data1 >> 8) & 0xFF), + static_cast((newId.Data1) & 0xFF), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xFF), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], + newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], + id[6], id[7], id[8], id[9], id[10], + id[11], id[12], id[13], id[14], id[15]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array arrbytes = { + {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, + bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, + bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, + bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; +#else + return uuid{}; +#endif + } + }; +#endif + + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) + : generator(&gen, [](auto) {}) + { + } + explicit basic_uuid_random_generator(engine_type* gen) + : generator(gen, [](auto) {}) + { + } + + [[nodiscard]] uuid operator()() + { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution distribution; + std::shared_ptr generator; + }; + + using uuid_random_generator = basic_uuid_random_generator; + + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept + : nsuuid(namespace_uuid) + { + } + + template + [[nodiscard]] uuid operator()(StringType const& name) + { + reset(); + process_characters(detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() + { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template + void process_characters(std::basic_string_view const str) + { + for (uint32_t c : str) + { + hasher.process_byte(static_cast(c & 0xFF)); + if constexpr (!std::is_same_v) + { + hasher.process_byte(static_cast((c >> 8) & 0xFF)); + hasher.process_byte(static_cast((c >> 16) & 0xFF)); + hasher.process_byte(static_cast((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() + { + detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + detail::sha1 hasher; + }; + +#ifdef UUID_TIME_GENERATOR + // !!! DO NOT USE THIS IN PRODUCTION + // this implementation is unreliable for good uuids + class uuid_time_generator + { + using mac_address = std::array; + + std::optional device_address; + + [[nodiscard]] bool get_mac_address() + { + if (device_address.has_value()) + { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) + return false; + std::vector buf(len); + auto pips = reinterpret_cast(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) + return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() + { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = + std::chrono::duration_cast(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() + { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() + { + if (get_mac_address()) + { + std::array data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } + }; +#endif +} // namespace uuids + +namespace std +{ + template <> + struct hash + { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const + { +#ifdef UUID_HASH_STRING_BASED + std::hash hasher; + return static_cast(hasher(uuids::to_string(uuid))); +#else + uint64_t l = static_cast(uuid.data[0]) << 56 | + static_cast(uuid.data[1]) << 48 | + static_cast(uuid.data[2]) << 40 | + static_cast(uuid.data[3]) << 32 | + static_cast(uuid.data[4]) << 24 | + static_cast(uuid.data[5]) << 16 | + static_cast(uuid.data[6]) << 8 | + static_cast(uuid.data[7]); + uint64_t h = static_cast(uuid.data[8]) << 56 | + static_cast(uuid.data[9]) << 48 | + static_cast(uuid.data[10]) << 40 | + static_cast(uuid.data[11]) << 32 | + static_cast(uuid.data[12]) << 24 | + static_cast(uuid.data[13]) << 16 | + static_cast(uuid.data[14]) << 8 | + static_cast(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) + { + return result_type(l ^ h); + } + else + { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } + }; +} // namespace std + +#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Headers/Version.hxx b/Headers/Version.hxx new file mode 100644 index 0000000..639c2c6 --- /dev/null +++ b/Headers/Version.hxx @@ -0,0 +1,3 @@ +#pragma once + +#define kDistVersion "v1.22" diff --git a/Notes/ASM specs.txt b/Notes/ASM specs.txt new file mode 100644 index 0000000..a0c42bf --- /dev/null +++ b/Notes/ASM specs.txt @@ -0,0 +1,11 @@ +==================== +X86 ASSEMBLER SPECS +==================== + +WHAT TO DO: + Provide a complete support of x86-64 with: + + - org directive. + - 64-bit and 32-bit registers. + - basic instructions (load, store, jump to) + - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Notes/HAVP DSP.txt b/Notes/HAVP DSP.txt new file mode 100644 index 0000000..12fcec5 --- /dev/null +++ b/Notes/HAVP DSP.txt @@ -0,0 +1,13 @@ +HAVP - Harvard Audio/Video Processor + +- Encoding: IBAD + +- Data path = 24 + - 16: sound data + - 8: information data + +- Register size: 32 +- Store strategy: shift registers. +- Standard registers: [ r0, r9 ] +- Floating point registers: [ f0, f2 ] +- Builtin SRAM: 512kb diff --git a/Notes/Notice.txt b/Notes/Notice.txt new file mode 100644 index 0000000..23691da --- /dev/null +++ b/Notes/Notice.txt @@ -0,0 +1,4 @@ +The X64000 draft papers +They contain thing that might appear through the next iteration of 64k. + +Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Notes/RISC CPU.txt b/Notes/RISC CPU.txt new file mode 100644 index 0000000..e17b494 --- /dev/null +++ b/Notes/RISC CPU.txt @@ -0,0 +1,17 @@ +VNRP - Von Neumann, RISC Processor + +- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs + +- Data path = 128-bit (register data) +- Addressing = 58-bit physical address size. + +- Registers (128-bit) = r0, r19 +- Float/Vector registers (128-bit) = f0, f9 + +- Out of order (superscalar also added to the equation) = Yes +- Superscalar = Yes + +- L1 cache: 16kb (8 instr, 8 data) +- L2 cache: 1024kb (512 instr, 512 data) + +- Clock speed: 1 Ghz diff --git a/Notes/asm-specs.txt b/Notes/asm-specs.txt deleted file mode 100644 index a0c42bf..0000000 --- a/Notes/asm-specs.txt +++ /dev/null @@ -1,11 +0,0 @@ -==================== -X86 ASSEMBLER SPECS -==================== - -WHAT TO DO: - Provide a complete support of x86-64 with: - - - org directive. - - 64-bit and 32-bit registers. - - basic instructions (load, store, jump to) - - flushable into object-code and flat binary. \ No newline at end of file diff --git a/Notes/havp.txt b/Notes/havp.txt deleted file mode 100644 index 12fcec5..0000000 --- a/Notes/havp.txt +++ /dev/null @@ -1,13 +0,0 @@ -HAVP - Harvard Audio/Video Processor - -- Encoding: IBAD - -- Data path = 24 - - 16: sound data - - 8: information data - -- Register size: 32 -- Store strategy: shift registers. -- Standard registers: [ r0, r9 ] -- Floating point registers: [ f0, f2 ] -- Builtin SRAM: 512kb diff --git a/Notes/notice.txt b/Notes/notice.txt deleted file mode 100644 index 23691da..0000000 --- a/Notes/notice.txt +++ /dev/null @@ -1,4 +0,0 @@ -The X64000 draft papers -They contain thing that might appear through the next iteration of 64k. - -Please look at the document shared for the latest revisions. \ No newline at end of file diff --git a/Notes/vnrp.txt b/Notes/vnrp.txt deleted file mode 100644 index e17b494..0000000 --- a/Notes/vnrp.txt +++ /dev/null @@ -1,17 +0,0 @@ -VNRP - Von Neumann, RISC Processor - -- Encoding = RegToReg, Imm, Syscall, Jump, NoArgs - -- Data path = 128-bit (register data) -- Addressing = 58-bit physical address size. - -- Registers (128-bit) = r0, r19 -- Float/Vector registers (128-bit) = f0, f9 - -- Out of order (superscalar also added to the equation) = Yes -- Superscalar = Yes - -- L1 cache: 16kb (8 instr, 8 data) -- L2 cache: 1024kb (512 instr, 512 data) - -- Clock speed: 1 Ghz diff --git a/Sources/32asm.cc b/Sources/32asm.cc deleted file mode 100644 index d32ab0b..0000000 --- a/Sources/32asm.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 32asm.cxx -// @author ZKA Technologies -// @brief 32x0 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_32x0__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 32x0 Assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/32asm.cxx b/Sources/32asm.cxx new file mode 100644 index 0000000..8577722 --- /dev/null +++ b/Sources/32asm.cxx @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file 32asm.cxx +// @author ZKA Technologies +// @brief 32x0 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_32x0__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 32x0 Assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/64asm.cc b/Sources/64asm.cc deleted file mode 100644 index 0a89e6a..0000000 --- a/Sources/64asm.cc +++ /dev/null @@ -1,954 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 64asm.cxx -// @author Amlal EL Mahrouss -// @brief 64x000 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_64x0__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -static char kOutputArch = CompilerKit::kPefArch64000; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -constexpr auto c64x0IPAlignment = 0x4U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static bool kVerbose = false; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ 64asm ] " << kWhite - << ((file == "64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; -} -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 64x0 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssembler64000) { - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " - "Logic.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; - kStdOut << "-64xxx: Compile for a subset of the X64000.\n"; - - return 0; - } else if (strcmp(argv[i], "-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::Encoder64x0 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "64asm"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "64asm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "64asm: At least one record is needed to write an object " - "file.\n64asm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "64asm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) - kStdOut << "64asm: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "64asm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "64asm: Exit failed.\n"; - - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import")); - - /// sanity check to avoid stupid linker errors. - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by 64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export")); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; - - // these don't. - std::vector filter_inst = {"jlr", "jrl", "int"}; - - for (auto &opcode64x0 : kOpcodes64x0) { - if (line.find(opcode64x0.fName) != std::string::npos) { - if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; - - for (auto &op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), - opcode64x0.fName); - it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + - strlen(opcode64x0.fName)])) { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_hex_number"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "64asm: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "64asm: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "64asm: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "64asm: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::Encoder64x0::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; - - for (auto &opcode64x0 : kOpcodes64x0) { - // strict check here - if (ParserKit::find_word(line, opcode64x0.fName) && - detail::algorithm::is_valid(line)) { - std::string name(opcode64x0.fName); - std::string jump_label, cpy_jump_label; - - kBytes.emplace_back(opcode64x0.fOpcode); - kBytes.emplace_back(opcode64x0.fFunct3); - kBytes.emplace_back(opcode64x0.fFunct7); - - // check funct7 type. - switch (opcode64x0.fFunct7) { - // reg to reg means register to register transfer operation. - case kAsmRegToReg: - case kAsmImmediate: { - // \brief how many registers we found. - std::size_t found_some = 0UL; - - for (size_t line_index = 0UL; line_index < line.size(); - line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && - isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (kOutputArch == CompilerKit::kPefArch64000) { - if (isdigit(line[line_index + 3]) && - isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - detail::print_error( - "invalid register index, r" + reg_str + - "\nnote: The 64x0 accepts registers from r0 to r20.", - file); - throw std::runtime_error("invalid_register_index"); - } - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - detail::print_error("invalid register index, r" + reg_str, - file); - throw std::runtime_error("invalid_register_index"); - } - - kBytes.emplace_back(reg_index); - ++found_some; - - if (kVerbose) { - kStdOut << "64asm: Register found: " << register_syntax << "\n"; - kStdOut << "64asm: Register amount in instruction: " - << found_some << "\n"; - } - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode64x0.fFunct7 != kAsmImmediate) { - // remember! register to register! - if (found_some == 1) { - detail::print_error( - "Too few registers.\ntip: each 64asm register " - "starts with 'r'.\nline: " + - line, - file); - throw std::runtime_error("not_a_register"); - } - } - - if (found_some < 1 && name != "ldw" && name != "lda" && - name != "stw") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "add") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "sub") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - if (found_some > 0 && name == "pop") { - detail::print_error( - "invalid combination for opcode 'pop'.\ntip: it expects " - "nothing.\nline: " + - line, - file); - throw std::runtime_error("invalid_comb_op_pop"); - } - } - default: - break; - } - - // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { - auto where_string = name; - - // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || - name == "sta") - where_string = ","; - - jump_label = line; - - auto found_sym = false; - - while (jump_label.find(where_string) != std::string::npos) { - jump_label = jump_label.substr(jump_label.find(where_string) + - where_string.size()); - - while (jump_label.find(" ") != std::string::npos) { - jump_label.erase(jump_label.find(" "), 1); - } - - if (jump_label[0] != kAsmRegisterPrefix[0] && - !isdigit(jump_label[1])) { - if (found_sym) { - detail::print_error( - "invalid combination of opcode and operands.\nhere -> " + - jump_label, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } else { - // death trap installed. - found_sym = true; - } - } - } - - cpy_jump_label = jump_label; - - // replace any spaces with $ - if (jump_label[0] == ' ') { - while (jump_label.find(' ') != std::string::npos) { - if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; - - jump_label.erase(jump_label.find(' '), 1); - } - } - - if (!this->WriteNumber(0, jump_label)) { - // sta expects this: sta 0x000000, r0 - if (name == "sta") { - detail::print_error( - "invalid combination of opcode and operands.\nHere ->" + line, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } - } else { - if (name == "sta" && - cpy_jump_label.find("import ") != std::string::npos) { - detail::print_error("invalid usage import on 'sta', here: " + line, - file); - throw std::runtime_error("invalid_sta_usage"); - } - } - - goto asm_write_label; - } - - // This is the case where we jump to a label, it is also used as a goto. - if (name == "lda" || name == "sta") { - asm_write_label: - if (cpy_jump_label.find('\n') != std::string::npos) - cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); - - if (cpy_jump_label.find("import") != std::string::npos) { - cpy_jump_label.erase(cpy_jump_label.find("import"), strlen("import")); - - if (name == "sta") { - detail::print_error("import is not allowed on a sta operation.", - file); - throw std::runtime_error("import_sta_op"); - } else { - goto asm_end_label_cpy; - } - } - - if (name == "lda" || name == "sta") { - for (auto &label : kOriginLabel) { - if (cpy_jump_label == label.first) { - if (kVerbose) { - kStdOut << "64asm: Replace label " << cpy_jump_label - << " to address: " << label.second << std::endl; - } - - CompilerKit::NumberCast64 num(label.second); - - for (auto &num : num.number) { - kBytes.push_back(num); - } - - goto asm_end_label_cpy; - } - } - - if (cpy_jump_label[0] == '0') { - switch (cpy_jump_label[1]) { - case 'x': - case 'o': - case 'b': - if (this->WriteNumber(0, cpy_jump_label)) - goto asm_end_label_cpy; - - break; - default: - break; - } - - if (isdigit(cpy_jump_label[0])) { - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - } - } - } - - if (cpy_jump_label.size() < 1) { - detail::print_error("label is empty, can't jump on it.", file); - throw std::runtime_error("label_empty"); - } - - /// don't go any further if: - /// load word (ldw) or store word. (stw) - - if (name == "ldw" || name == "stw") break; - - auto mld_reloc_str = std::to_string(cpy_jump_label.size()); - mld_reloc_str += kUndefinedSymbol; - mld_reloc_str += cpy_jump_label; - - bool ignore_back_slash = false; - - for (auto &reloc_chr : mld_reloc_str) { - if (reloc_chr == '\\') { - ignore_back_slash = true; - continue; - } - - if (ignore_back_slash) { - ignore_back_slash = false; - continue; - } - - kBytes.push_back(reloc_chr); - } - - kBytes.push_back('\0'); - goto asm_end_label_cpy; - } - - asm_end_label_cpy: - kOrigin += c64x0IPAlignment; - - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/64asm.cxx b/Sources/64asm.cxx new file mode 100644 index 0000000..777f448 --- /dev/null +++ b/Sources/64asm.cxx @@ -0,0 +1,954 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file 64asm.cxx +// @author Amlal EL Mahrouss +// @brief 64x000 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_64x0__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +static char kOutputArch = CompilerKit::kPefArch64000; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +constexpr auto c64x0IPAlignment = 0x4U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +static bool kVerbose = false; + +static std::vector kBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string &line); + +namespace detail { +void print_error(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << kRed << "[ 64asm ] " << kWhite + << ((file == "64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +void print_warning(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (!file.empty()) { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; +} +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 64x0 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssembler64000) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { + kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " + "ZKA Technologies.\n"; + return 0; + } else if (strcmp(argv[i], "-h") == 0) { + kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " + "Logic.\n"; + kStdOut << "-version: Print program version.\n"; + kStdOut << "-verbose: Print verbose output.\n"; + kStdOut << "-binary: Output as flat binary.\n"; + kStdOut << "-64xxx: Compile for a subset of the X64000.\n"; + + return 0; + } else if (strcmp(argv[i], "-binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "-verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto &ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::Encoder64x0 asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + detail::print_error(ln, argv[i]); + continue; + } + + try { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } catch (const std::exception &e) { + if (kVerbose) { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "64asm"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "64asm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) { + kStdErr << "64asm: At least one record is needed to write an object " + "file.\n64asm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + std::size_t record_count = 0UL; + + for (auto &rec : kRecords) { + if (kVerbose) + kStdOut << "64asm: Wrote record " << rec.fName << " to file...\n"; + + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; + + file_ptr_out << rec; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto &sym : kUndefinedSymbols) { + CompilerKit::AERecordHeader _record_hdr{0}; + + if (kVerbose) + kStdOut << "64asm: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + + file_ptr_out << _record_hdr; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "64asm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto &byte : kBytes) { + file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); + } + + if (kVerbose) kStdOut << "64asm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "64asm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "64asm: Exit failed.\n"; + + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string &line) { + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (ParserKit::find_word(line, "import")) { + if (kOutputAsBinary) { + detail::print_error("Invalid import directive in flat binary mode.", + "64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import")); + + /// sanity check to avoid stupid linker errors. + if (name.size() == 0) { + detail::print_error("Invalid import", "ppcasm"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char &j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by 64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (ParserKit::find_word(line, "export")) { + if (kOutputAsBinary) { + detail::print_error("Invalid export directive in flat binary mode.", + "64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export")); + + std::string name_copy = name; + + for (char &j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm { +// \brief authorize a brief set of characters. +static inline bool is_not_alnum_space(char c) { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.')); +} + +bool is_valid(const std::string &str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, + const std::string &file) { + std::string err_str; + + if (line.empty() || ParserKit::find_word(line, "import") || + ParserKit::find_word(line, "export") || + line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) { + if (line.find(',') + 1 == line.size()) { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } else { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto &ch : substr) { + if (ch != ' ' && ch != '\t') { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + + // these do take an argument. + std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; + + // these don't. + std::vector filter_inst = {"jlr", "jrl", "int"}; + + for (auto &opcode64x0 : kOpcodes64x0) { + if (line.find(opcode64x0.fName) != std::string::npos) { + if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; + + for (auto &op : operands_inst) { + // if only the instruction was found. + if (line == op) { + err_str += "\nMalformed "; + err_str += op; + err_str += " instruction, here -> "; + err_str += line; + } + } + + // if it is like that -> addr1, 0x0 + if (auto it = std::find(filter_inst.begin(), filter_inst.end(), + opcode64x0.fName); + it == filter_inst.cend()) { + if (ParserKit::find_word(line, opcode64x0.fName)) { + if (!isspace(line[line.find(opcode64x0.fName) + + strlen(opcode64x0.fName)])) { + err_str += "\nMissing space between "; + err_str += opcode64x0.fName; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; +} + +bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, + std::string &jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) { + if (errno != 0) { + detail::print_error("invalid hex number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_hex_number"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "64asm: found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) { + if (errno != 0) { + detail::print_error("invalid binary number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "64asm: found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) { + if (errno != 0) { + detail::print_error("invalid octal number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "64asm: found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "64asm: found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::Encoder64x0::WriteLine(std::string &line, + const std::string &file) { + if (ParserKit::find_word(line, "export ")) return true; + + for (auto &opcode64x0 : kOpcodes64x0) { + // strict check here + if (ParserKit::find_word(line, opcode64x0.fName) && + detail::algorithm::is_valid(line)) { + std::string name(opcode64x0.fName); + std::string jump_label, cpy_jump_label; + + kBytes.emplace_back(opcode64x0.fOpcode); + kBytes.emplace_back(opcode64x0.fFunct3); + kBytes.emplace_back(opcode64x0.fFunct7); + + // check funct7 type. + switch (opcode64x0.fFunct7) { + // reg to reg means register to register transfer operation. + case kAsmRegToReg: + case kAsmImmediate: { + // \brief how many registers we found. + std::size_t found_some = 0UL; + + for (size_t line_index = 0UL; line_index < line.size(); + line_index++) { + if (line[line_index] == kAsmRegisterPrefix[0] && + isdigit(line[line_index + 1])) { + std::string register_syntax = kAsmRegisterPrefix; + register_syntax += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + register_syntax += line[line_index + 2]; + + std::string reg_str; + reg_str += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + reg_str += line[line_index + 2]; + + // it ranges from r0 to r19 + // something like r190 doesn't exist in the instruction set. + if (kOutputArch == CompilerKit::kPefArch64000) { + if (isdigit(line[line_index + 3]) && + isdigit(line[line_index + 2])) { + reg_str += line[line_index + 3]; + detail::print_error( + "invalid register index, r" + reg_str + + "\nnote: The 64x0 accepts registers from r0 to r20.", + file); + throw std::runtime_error("invalid_register_index"); + } + } + + // finally cast to a size_t + std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + + if (reg_index > kAsmRegisterLimit) { + detail::print_error("invalid register index, r" + reg_str, + file); + throw std::runtime_error("invalid_register_index"); + } + + kBytes.emplace_back(reg_index); + ++found_some; + + if (kVerbose) { + kStdOut << "64asm: Register found: " << register_syntax << "\n"; + kStdOut << "64asm: Register amount in instruction: " + << found_some << "\n"; + } + } + } + + // we're not in immediate addressing, reg to reg. + if (opcode64x0.fFunct7 != kAsmImmediate) { + // remember! register to register! + if (found_some == 1) { + detail::print_error( + "Too few registers.\ntip: each 64asm register " + "starts with 'r'.\nline: " + + line, + file); + throw std::runtime_error("not_a_register"); + } + } + + if (found_some < 1 && name != "ldw" && name != "lda" && + name != "stw") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } else if (found_some == 1 && name == "add") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } else if (found_some == 1 && name == "sub") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } + + if (found_some > 0 && name == "pop") { + detail::print_error( + "invalid combination for opcode 'pop'.\ntip: it expects " + "nothing.\nline: " + + line, + file); + throw std::runtime_error("invalid_comb_op_pop"); + } + } + default: + break; + } + + // try to fetch a number from the name + if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { + auto where_string = name; + + // if we load something, we'd need it's symbol/literal + if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || + name == "sta") + where_string = ","; + + jump_label = line; + + auto found_sym = false; + + while (jump_label.find(where_string) != std::string::npos) { + jump_label = jump_label.substr(jump_label.find(where_string) + + where_string.size()); + + while (jump_label.find(" ") != std::string::npos) { + jump_label.erase(jump_label.find(" "), 1); + } + + if (jump_label[0] != kAsmRegisterPrefix[0] && + !isdigit(jump_label[1])) { + if (found_sym) { + detail::print_error( + "invalid combination of opcode and operands.\nhere -> " + + jump_label, + file); + throw std::runtime_error("invalid_comb_op_ops"); + } else { + // death trap installed. + found_sym = true; + } + } + } + + cpy_jump_label = jump_label; + + // replace any spaces with $ + if (jump_label[0] == ' ') { + while (jump_label.find(' ') != std::string::npos) { + if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; + + jump_label.erase(jump_label.find(' '), 1); + } + } + + if (!this->WriteNumber(0, jump_label)) { + // sta expects this: sta 0x000000, r0 + if (name == "sta") { + detail::print_error( + "invalid combination of opcode and operands.\nHere ->" + line, + file); + throw std::runtime_error("invalid_comb_op_ops"); + } + } else { + if (name == "sta" && + cpy_jump_label.find("import ") != std::string::npos) { + detail::print_error("invalid usage import on 'sta', here: " + line, + file); + throw std::runtime_error("invalid_sta_usage"); + } + } + + goto asm_write_label; + } + + // This is the case where we jump to a label, it is also used as a goto. + if (name == "lda" || name == "sta") { + asm_write_label: + if (cpy_jump_label.find('\n') != std::string::npos) + cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); + + if (cpy_jump_label.find("import") != std::string::npos) { + cpy_jump_label.erase(cpy_jump_label.find("import"), strlen("import")); + + if (name == "sta") { + detail::print_error("import is not allowed on a sta operation.", + file); + throw std::runtime_error("import_sta_op"); + } else { + goto asm_end_label_cpy; + } + } + + if (name == "lda" || name == "sta") { + for (auto &label : kOriginLabel) { + if (cpy_jump_label == label.first) { + if (kVerbose) { + kStdOut << "64asm: Replace label " << cpy_jump_label + << " to address: " << label.second << std::endl; + } + + CompilerKit::NumberCast64 num(label.second); + + for (auto &num : num.number) { + kBytes.push_back(num); + } + + goto asm_end_label_cpy; + } + } + + if (cpy_jump_label[0] == '0') { + switch (cpy_jump_label[1]) { + case 'x': + case 'o': + case 'b': + if (this->WriteNumber(0, cpy_jump_label)) + goto asm_end_label_cpy; + + break; + default: + break; + } + + if (isdigit(cpy_jump_label[0])) { + if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; + + break; + } + } + } + + if (cpy_jump_label.size() < 1) { + detail::print_error("label is empty, can't jump on it.", file); + throw std::runtime_error("label_empty"); + } + + /// don't go any further if: + /// load word (ldw) or store word. (stw) + + if (name == "ldw" || name == "stw") break; + + auto mld_reloc_str = std::to_string(cpy_jump_label.size()); + mld_reloc_str += kUndefinedSymbol; + mld_reloc_str += cpy_jump_label; + + bool ignore_back_slash = false; + + for (auto &reloc_chr : mld_reloc_str) { + if (reloc_chr == '\\') { + ignore_back_slash = true; + continue; + } + + if (ignore_back_slash) { + ignore_back_slash = false; + continue; + } + + kBytes.push_back(reloc_chr); + } + + kBytes.push_back('\0'); + goto asm_end_label_cpy; + } + + asm_end_label_cpy: + kOrigin += c64x0IPAlignment; + + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc deleted file mode 100644 index efbf68f..0000000 --- a/Sources/64x0-cc.cc +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: ? -/// TODO: - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* C driver */ -/* This is part of the NDK. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file 64x0-cc.cc -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kOk (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend -{ -public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char* text, const char* file); - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override - { - return "64k C"; - } -}; - -static CompilerBackendCLang* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace detail -{ - union number_cast final { - public: - number_cast(UInt64 _Raw) - : _Raw(_Raw) - { - } - - public: - char _Num[8]; - UInt64 _Raw; - }; - - union double_cast final { - public: - double_cast(float _Raw) - : _Raw(_Raw) - { - } - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string& text, const char* file) -{ - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) - { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) - { - if (substr[y] == ' ') - { - while (match_type.find(' ') != std::string::npos) - { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) - { - if (clType.fName == match_type) - { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) - { - break; - } - - if (textBuffer.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) - { - if (textBuffer[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) - { - if (textBuffer[value_index] == ';') - break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') - { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, import "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword export .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (textBuffer[text_index] == ';' && kInStruct) - continue; - - if (textBuffer.find("typedef ") != std::string::npos) - continue; - - if (textBuffer[text_index] == '=' && kInStruct) - { - detail::print_error("assignement of value in struct " + textBuffer, - file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : textBuffer) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) - { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (textBuffer.find("*") != std::string::npos) - { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } - else - { - substr += "\tldw "; - } - } - else if (textBuffer.find('=') != std::string::npos && !kInBraces) - { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') - { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) - { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (textBuffer[text_index] == '=') - break; - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) - { - if (textBuffer[idx] == ',') - continue; - - if (textBuffer[idx] == ' ') - continue; - - if (textBuffer[idx] == ')') - break; - } - - for (char substr_first_index : textBuffer) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) - args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : textBuffer) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') - break; - - substr += _text_i; - } - - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') - { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) - { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') - { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) - kIfFound = false; - - if (kInStruct) - kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char* text, const char* file) -{ - std::string err_str; - std::string ln = text; - - if (ln.empty()) - { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (isalnum(ln[i])) - { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) - return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) - { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '\'') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } - else if (ln.find('"') != std::string::npos) - { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '"') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - else - { - break; - } - } - } - } - else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) - { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) - { - if (ln.find(forbidden) != std::string::npos) - { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final - { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, - {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, - {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, - {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, - {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, - {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, - {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, - {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, - {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, - {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) - { - if (ln.find(variable.fBegin) != std::string::npos) - { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') - ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == variable.fEnd[0]) - { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) - { - if (ln[index_keyword] == ' ') - { - continue; - } - - if (isdigit(ln[index_keyword])) - { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) - { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") - { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') - { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) - { - if (var.fValue.find(keyword) != std::string::npos) - { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) - { - if (fn.find(keyword[0]) != std::string::npos) - { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) - { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') - break; - - if (fn[where_begin] != keyword[keyword_begin]) - { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) - { - err_str.clear(); - goto cc_next; - } - else - { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) - return err_str; - - if (keyword.find(".") != std::string::npos) - return err_str; - - if (isalnum(keyword[0])) - err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (ParserKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCCInterface); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCCInterface::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerBackend->Compile(line_src, src.data()); - } - else - { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) - return -1; - - std::vector keywords = {"ldw", "stw", "lda", "sta", - "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (ParserKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (ParserKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("import " + needle) != - std::string::npos) - { - std::string range = "import " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("import " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "sub") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "Zeta C Driver, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_MODULE(NewOSCompilerCLang64x0) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '/') - { - if (strcmp(argv[index], "/v") == 0 || - strcmp(argv[index], "/version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "/verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) - { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "/dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "/fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) - { - if (kState.fVerbose) - { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/64x0-cc.cxx b/Sources/64x0-cc.cxx new file mode 100644 index 0000000..47abfb5 --- /dev/null +++ b/Sources/64x0-cc.cxx @@ -0,0 +1,1627 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: ? +/// TODO: + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* C driver */ +/* This is part of the NDK. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file 64x0-cc.cxx +/// @brief 64x0 C Compiler. + +/// TODO: support structures, else if, else, . and -> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kOk (0) + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNAL STUFF OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "64k C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; +static std::vector kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, import "; + syntaxLeaf.fUserValue += + kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword export .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error("assignement of value in struct " + textBuffer, + file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } + else + { + substr += "\tldw "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + if (var_to_find == kCompilerVariables.cend()) + { + ++kRegisterCounter; + + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } + + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + if (textBuffer[text_index] == '=') + break; + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tlda r19, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "sub "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (ParserKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (ParserKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && + !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && + !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCCInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCCInterface); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArch64x0; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCCInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ldw", "stw", "lda", "sta", + "add", "sub", "mv"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (ParserKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (ParserKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (ParserKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import " + needle) != + std::string::npos) + { + std::string range = "import " + needle; + leaf.fUserValue.replace( + leaf.fUserValue.find("import " + needle), range.size(), + needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && + keyword != "sub") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "Zeta C Driver, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLang64x0) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyCCInterface()); + kMachine = CompilerKit::AssemblyFactory::kArch64x0; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '/') + { + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/Sources/AssemblyFactory.cc b/Sources/AssemblyFactory.cc deleted file mode 100644 index 35d8cbd..0000000 --- a/Sources/AssemblyFactory.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include - -/** - * @file AssemblyFactory.cc - * @author amlal (amlal@zeta.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, ZKA Technologies - * - */ - -#include - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit -{ - ///! @brief Compile for specific format (ELF, PEF, ZBIN) - Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept - { - if (sourceFile.length() < 1 || !fMounted) - return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); - } - - ///! @brief mount assembly backend. - void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept - { - if (mountPtr) - { - fMounted = mountPtr; - } - } - - ///! @brief Unmount assembler. - AssemblyInterface* AssemblyFactory::Unmount() noexcept - { - auto mount_prev = fMounted; - - if (mount_prev) - { - fMounted = nullptr; - } - - return mount_prev; - } -} // namespace CompilerKit diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx new file mode 100644 index 0000000..61dbebd --- /dev/null +++ b/Sources/AssemblyFactory.cxx @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cxx + * @author amlal (amlal@zeta.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, ZKA Technologies + * + */ + +#include + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit +{ + ///! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + ///! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + ///! @brief Unmount assembler. + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index 00bfbd7..bf05830 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include using namespace CompilerKit; diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index 4c46727..6f6361c 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include #define kZero64Section ".zero64" #define kCode64Section ".code64" diff --git a/Sources/String.cc b/Sources/String.cc deleted file mode 100644 index accc1af..0000000 --- a/Sources/String.cc +++ /dev/null @@ -1,200 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/** - * @file String.cc - * @author Amlal (amlal@mahrouss-logic.com) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) ZKA Technologies - * - */ - -#include - -namespace CompilerKit { -CharType *StringView::Data() { return m_Data; } - -const CharType *StringView::CData() const { return m_Data; } - -SizeType StringView::Length() const { return strlen(m_Data); } - -bool StringView::operator==(const StringView &rhs) const { - if (rhs.Length() != Length()) return false; - - for (SizeType index = 0; index < Length(); ++index) { - if (rhs.m_Data[index] != m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator==(const CharType *rhs) const { - if (string_length(rhs) != Length()) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] != m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator!=(const StringView &rhs) const { - if (rhs.Length() != Length()) return false; - - for (SizeType index = 0; index < rhs.Length(); ++index) { - if (rhs.m_Data[index] == m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator!=(const CharType *rhs) const { - if (string_length(rhs) != Length()) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] == m_Data[index]) return false; - } - - return true; -} - -StringView StringBuilder::Construct(const CharType *data) { - if (!data || *data == 0) return StringView(0); - - StringView view(strlen(data)); - view += data; - - return view; -} - -const char *StringBuilder::FromInt(const char *fmt, int i) { - if (!fmt) return ("-1"); - - auto ret_len = 8 + string_length(fmt); - char *ret = new char[ret_len]; - - if (!ret) return ("-1"); - - memset(ret, 0, ret_len); - - CharType result[8]; - if (!to_str(result, sizeof(int), i)) { - delete[] ret; - return ("-1"); - } - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(result); - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (auto y_idx = idx; y_idx < res_len; ++y_idx) { - ret[result_cnt] = result[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ -} - -const char *StringBuilder::FromBool(const char *fmt, bool i) { - if (!fmt) return ("?"); - - const char *boolean_expr = i ? "true" : "false"; - char *ret = new char[i ? 4 : 5 + string_length(fmt)]; - - if (!ret) return ("?"); - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(boolean_expr); - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (auto y_idx = idx; y_idx < res_len; ++y_idx) { - ret[result_cnt] = boolean_expr[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; -} - -bool StringBuilder::Equals(const char *lhs, const char *rhs) { - if (string_length(rhs) != string_length(lhs)) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] != lhs[index]) return false; - } - - return true; -} - -const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { - if (!fmt || !fmtRight) return ("?"); - - char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; - if (!ret) return ("?"); - - for (SizeType idx = 0; idx < string_length(fmt); ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { - ret[result_cnt] = fmtRight[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; -} - -StringView &StringView::operator+=(const CharType *rhs) { - if (strlen(rhs) > this->m_Sz) { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); - this->m_Cur += strlen(rhs); - - return *this; -} - -StringView &StringView::operator+=(const StringView &rhs) { - if (rhs.m_Cur > this->m_Sz) { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); - this->m_Cur += strlen(rhs.CData()); - - return *this; -} -} // namespace CompilerKit diff --git a/Sources/String.cxx b/Sources/String.cxx new file mode 100644 index 0000000..8b8cb9c --- /dev/null +++ b/Sources/String.cxx @@ -0,0 +1,200 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/** + * @file String.cxx + * @author Amlal (amlal@mahrouss-logic.com) + * @brief C++ string manipulation API. + * @version 0.2 + * @date 2024-01-23 + * + * @copyright Copyright (c) ZKA Technologies + * + */ + +#include + +namespace CompilerKit { +CharType *StringView::Data() { return m_Data; } + +const CharType *StringView::CData() const { return m_Data; } + +SizeType StringView::Length() const { return strlen(m_Data); } + +bool StringView::operator==(const StringView &rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < Length(); ++index) { + if (rhs.m_Data[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator==(const CharType *rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const StringView &rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < rhs.Length(); ++index) { + if (rhs.m_Data[index] == m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const CharType *rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] == m_Data[index]) return false; + } + + return true; +} + +StringView StringBuilder::Construct(const CharType *data) { + if (!data || *data == 0) return StringView(0); + + StringView view(strlen(data)); + view += data; + + return view; +} + +const char *StringBuilder::FromInt(const char *fmt, int i) { + if (!fmt) return ("-1"); + + auto ret_len = 8 + string_length(fmt); + char *ret = new char[ret_len]; + + if (!ret) return ("-1"); + + memset(ret, 0, ret_len); + + CharType result[8]; + if (!to_str(result, sizeof(int), i)) { + delete[] ret; + return ("-1"); + } + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(result); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) { + ret[result_cnt] = result[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ +} + +const char *StringBuilder::FromBool(const char *fmt, bool i) { + if (!fmt) return ("?"); + + const char *boolean_expr = i ? "true" : "false"; + char *ret = new char[i ? 4 : 5 + string_length(fmt)]; + + if (!ret) return ("?"); + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(boolean_expr); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) { + ret[result_cnt] = boolean_expr[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +bool StringBuilder::Equals(const char *lhs, const char *rhs) { + if (string_length(rhs) != string_length(lhs)) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != lhs[index]) return false; + } + + return true; +} + +const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { + if (!fmt || !fmtRight) return ("?"); + + char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; + if (!ret) return ("?"); + + for (SizeType idx = 0; idx < string_length(fmt); ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { + ret[result_cnt] = fmtRight[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +StringView &StringView::operator+=(const CharType *rhs) { + if (strlen(rhs) > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); + this->m_Cur += strlen(rhs); + + return *this; +} + +StringView &StringView::operator+=(const StringView &rhs) { + if (rhs.m_Cur > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); + this->m_Cur += strlen(rhs.CData()); + + return *this; +} +} // namespace CompilerKit diff --git a/Sources/bpp.cc b/Sources/bpp.cc deleted file mode 100644 index 1aefc33..0000000 --- a/Sources/bpp.cc +++ /dev/null @@ -1,899 +0,0 @@ -/* - * ======================================================== - * - * bpp - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include -#include -#include -#include -#include -#include -#include - -#define kMacroPrefix '%' - -/// @author Amlal El Mahrouss (amlel) -/// @file bpp.cc -/// @brief Preprocessor. - -typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, - std::ofstream &pp_out); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Preprocessor internal types. - -///////////////////////////////////////////////////////////////////////////////////////// - -namespace details { -enum { - kEqual, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, -}; - -struct bpp_macro_condition final { - int32_t fType; - std::string fTypeName; -}; - -struct bpp_macro final { - std::vector fArgs; - std::string fName; - std::string fValue; -}; - -class bpp_pragma final { - public: - explicit bpp_pragma() = default; - ~bpp_pragma() = default; - - MPCC_COPY_DEFAULT(bpp_pragma); - - std::string fMacroName; - bpp_parser_fn_t fParse; -}; -} // namespace details - -static std::vector kFiles; -static std::vector kMacros; -static std::vector kIncludes; - -static std::string kWorkingDir; - -static std::vector kKeywords = { - "include", "if", "pragma", "def", "elif", - "ifdef", "ifndef", "else", "warning", "error"}; - -#define kKeywordCxxCnt kKeywords.size() - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_if_condition -// @brief parse #if condition - -///////////////////////////////////////////////////////////////////////////////////////// - -int32_t bpp_parse_if_condition(details::bpp_macro_condition &cond, - details::bpp_macro ¯o, bool &inactive_code, - bool &defined, std::string ¯o_str) { - if (cond.fType == details::kEqual) { - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fValue) != std::string::npos) { - if (macro.fValue == "0") { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } else if (cond.fType == details::kNotEqual) { - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != std::string::npos) { - if (substr_macro.find(macro.fValue) != std::string::npos) { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - std::string number; - - for (auto ¯o_num : kMacros) { - if (substr_macro.find(macro_num.fName) != std::string::npos) { - for (size_t i = 0; i < macro_num.fName.size(); ++i) { - if (isdigit(macro_num.fValue[i])) { - number += macro_num.fValue[i]; - } else { - number.clear(); - break; - } - } - - break; - } - } - - size_t y = 2; - - /* last try */ - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - size_t rhs = atol(macro.fValue.c_str()); - size_t lhs = atol(number.c_str()); - - if (lhs == 0) { - number.clear(); - ++y; - - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - lhs = atol(number.c_str()); - } - - if (cond.fType == details::kGreaterThan) { - if (lhs < rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kGreaterEqThan) { - if (lhs <= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kLesserEqThan) { - if (lhs >= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kLesserThan) { - if (lhs > rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief stores every included file here. - -///////////////////////////////////////////////////////////////////////////////////////// - -std::vector kAllIncludes; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_file -// @brief parse file to preprocess it. - -///////////////////////////////////////////////////////////////////////////////////////// - -void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { - std::string hdr_line; - std::string line_after_include; - - bool inactive_code = false; - bool defined = false; - - try { - while (std::getline(hdr_file, hdr_line)) { - /// BPP Documentation. - if (hdr_line.find("@bdoc") != std::string::npos) { - hdr_line.erase(hdr_line.find("@bdoc")); - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("endif") != std::string::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = false; - - continue; - } - - continue; - } - - if (!defined && inactive_code) { - continue; - } - - if (defined && inactive_code) { - continue; - } - - for (auto macro : kMacros) { - if (ParserKit::find_word(hdr_line, macro.fName) && - hdr_line.find("%def") == std::string::npos) { - auto value = macro.fValue; - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - value); - } - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("def ") != std::string::npos) { - auto line_after_define = - hdr_line.substr(hdr_line.find("def ") + strlen("def ")); - - std::string macro_value; - std::string macro_key; - - std::size_t pos = 0UL; - - std::vector args; - bool on_args = false; - - for (auto &ch : line_after_define) { - ++pos; - - if (ch == '(') { - on_args = true; - continue; - } - - if (ch == ')') { - on_args = false; - continue; - } - - if (ch == '\\') continue; - - if (on_args) continue; - - if (ch == ' ') { - for (size_t i = pos; i < line_after_define.size(); i++) { - macro_value += line_after_define[i]; - } - - break; - } - - macro_key += ch; - } - - std::vector dupls; - std::string str; - - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto &subc : line_after_define) { - if (subc == ',' || subc == ')') { - if (str.empty()) continue; - - dupls.push_back(str); - args.push_back(str); - - str.clear(); - - continue; - } - - if (isalnum(subc)) str.push_back(subc); - } - - for (auto &dupl : dupls) { - std::size_t cnt = 0; - - for (auto &arg : args) { - if (dupl == arg) ++cnt; - } - - if (cnt > 1) { - auto it = std::find(args.begin(), args.end(), dupl); - - while (it != args.end()) { - args.erase(it); - it = std::find(args.begin(), args.end(), dupl); - } - } - } - - details::bpp_macro macro; - - macro.fArgs = args; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.emplace_back(macro); - - continue; - } - - if (hdr_line[0] != kMacroPrefix) { - if (inactive_code) { - continue; - } - - for (auto ¯o : kMacros) { - if (hdr_line.find(macro.fName) != std::string::npos) { - std::vector arg_values; - - if (macro.fArgs.size() > 0) { - for (size_t i = 0; i < hdr_line.size(); ++i) { - if (hdr_line[i] == '(') { - std::string tmp_arg; - - for (size_t x = i; x < hdr_line.size(); x++) { - if (hdr_line[x] == ')') break; - - if (hdr_line[x] == ' ') continue; - - if (hdr_line[i] == '\\') continue; - - if (hdr_line[x] == ',') { - arg_values.push_back(tmp_arg); - tmp_arg.clear(); - continue; - } - - tmp_arg += hdr_line[x]; - } - - break; - } - } - - std::string symbol; - - for (char i : macro.fValue) { - if (i == '(') break; - - if (i == '\\') continue; - - symbol += i; - } - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - symbol); - - size_t x_arg_indx = 0; - - for (size_t i = hdr_line.find(macro.fValue); i < hdr_line.size(); - ++i) { - if (hdr_line.find(macro.fArgs[x_arg_indx]) == i) { - hdr_line.replace(i, macro.fArgs[x_arg_indx].size(), - arg_values[x_arg_indx]); - ++x_arg_indx; - } - } - } else { - std::string symbol; - - for (size_t i = 0; i < macro.fValue.size(); i++) { - if (macro.fValue[i] == ' ') continue; - - if (macro.fValue[i] == '\\') continue; - - symbol += macro.fValue[i]; - } - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - symbol); - } - - break; - } - } - - pp_out << hdr_line << std::endl; - - continue; - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifndef") != std::string::npos) { - auto line_after_ifndef = - hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - std::string macro; - - for (auto &ch : line_after_ifndef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = true; - inactive_code = false; - continue; - } - - if (macro == "1") { - defined = false; - inactive_code = true; - - continue; - } - - bool found = false; - - defined = true; - inactive_code = false; - - for (auto ¯o_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != std::string::npos) { - found = true; - break; - } - } - - if (found) { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != std::string::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = true; - - continue; - } else { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifdef") != std::string::npos) { - auto line_after_ifdef = - hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - std::string macro; - - for (auto &ch : line_after_ifdef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - defined = false; - inactive_code = true; - - for (auto ¯o_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != std::string::npos) { - defined = true; - inactive_code = false; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("pragma") != std::string::npos) { - line_after_include = hdr_line.substr(hdr_line.find("pragma once")); - - // search for this file - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), - line_after_include); - - if (it == kAllIncludes.cend()) { - goto kIncludeFile; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != std::string::npos) { - inactive_code = true; - - std::vector bpp_macro_condition_list = { - { - .fType = details::kEqual, - .fTypeName = "==", - }, - { - .fType = details::kNotEqual, - .fTypeName = "!=", - }, - { - .fType = details::kLesserThan, - .fTypeName = "<", - }, - { - .fType = details::kGreaterThan, - .fTypeName = ">", - }, - { - .fType = details::kLesserEqThan, - .fTypeName = "<=", - }, - { - .fType = details::kGreaterEqThan, - .fTypeName = ">=", - }, - }; - - int32_t good_to_go = 0; - - for (auto ¯o_condition : bpp_macro_condition_list) { - if (hdr_line.find(macro_condition.fTypeName) != std::string::npos) { - for (auto &found_macro : kMacros) { - if (hdr_line.find(found_macro.fName) != std::string::npos) { - good_to_go = - bpp_parse_if_condition(macro_condition, found_macro, - inactive_code, defined, hdr_line); - - break; - } - } - } - } - - if (good_to_go) continue; - - auto line_after_if = - hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); - std::string macro; - - for (auto &ch : line_after_if) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - // last try, is it defined to be one? - for (auto ¯o_ref : kMacros) { - if (macro_ref.fName.find(macro) != std::string::npos && - macro_ref.fValue == "1") { - inactive_code = false; - defined = true; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != std::string::npos) { - auto line_after_warning = - hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - std::string message; - - for (auto &ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - std::cout << "Warning: " << message << std::endl; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != std::string::npos) { - auto line_after_warning = - hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - std::string message; - - for (auto &ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - throw std::runtime_error("Error: " + message); - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("inc ") != std::string::npos) { - line_after_include = - hdr_line.substr(hdr_line.find("inc ") + strlen("inc ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), - line_after_include); - - if (it != kAllIncludes.cend()) { - continue; - } - - std::string path; - - kAllIncludes.push_back(line_after_include); - - bool enable = false; - bool not_local = false; - - for (auto &ch : line_after_include) { - if (ch == ' ') continue; - - if (ch == '<') { - not_local = true; - enable = true; - - continue; - } - - if (ch == '\'') { - enable = true; - continue; - } - - if (enable) { - if (not_local) { - if (ch == '>') break; - } else { - if (ch == '\'') { - break; - } - } - - path += ch; - } - } - - if (not_local) { - bool open = false; - - for (auto &include : kIncludes) { - std::string header_path = include; - header_path.push_back('/'); - header_path += path; - - std::ifstream header(header_path); - - if (!header.is_open()) continue; - - open = true; - - bpp_parse_file(header, pp_out); - - break; - } - - if (!open) { - throw std::runtime_error("bpp: no such include file: " + path); - } - } else { - std::ifstream header(kWorkingDir + path); - - if (!header.is_open()) - throw std::runtime_error("bpp: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } else { - std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) - << "\n"; - continue; - } - } - } catch (std::out_of_range &oor) { - return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief main entrypoint of app. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSPreprocessor) { - try { - bool skip = false; - bool double_skip = false; - - details::bpp_macro macro_1; - macro_1.fName = "__true"; - macro_1.fValue = "1"; - - kMacros.push_back(macro_1); - - details::bpp_macro macro_0; - macro_0.fName = "__false"; - macro_0.fValue = "0"; - - kMacros.push_back(macro_0); - - details::bpp_macro macro_hcore; - macro_hcore.fName = "__MAHROUSS__"; - macro_hcore.fValue = "1"; - - kMacros.push_back(macro_hcore); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (double_skip) { - ++index; - double_skip = false; - continue; - } - - if (argv[index][0] == '/') { - if (strcmp(argv[index], "/version") == 0) { - printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); - return 0; - } - - if (strcmp(argv[index], "/help") == 0) { - printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) ZKA Technologies"); - printf("%s\n", "/working-dir : set directory to working path."); - printf("%s\n", "/include-dir : add directory to include path."); - printf("%s\n", "/def : def macro."); - printf("%s\n", "/version: print the version."); - printf("%s\n", "/help: show help."); - - return 0; - } - - if (strcmp(argv[index], "/include-dir") == 0) { - std::string inc = argv[index + 1]; - - skip = true; - - kIncludes.push_back(inc); - } - - if (strcmp(argv[index], "/working-dir") == 0) { - std::string inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } - - if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) { - std::string macro_key = argv[index + 1]; - - std::string macro_value; - bool is_string = false; - - for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); - ++argv_find_len) { - if (!isdigit(argv[index][argv_find_len])) { - is_string = true; - macro_value += "\""; - - break; - } - } - - macro_value += argv[index + 2]; - - if (is_string) macro_value += "\""; - - details::bpp_macro macro; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.push_back(macro); - - double_skip = true; - } - - continue; - } - - kFiles.emplace_back(argv[index]); - } - - if (kFiles.empty()) return MPCC_EXEC_ERROR; - - for (auto &file : kFiles) { - if (!std::filesystem::exists(file)) continue; - - std::ifstream file_descriptor(file); - std::ofstream file_descriptor_pp(file + ".pp"); - - bpp_parse_file(file_descriptor, file_descriptor_pp); - } - - return 0; - } catch (const std::runtime_error &e) { - std::cout << e.what() << '\n'; - } - - return 1; -} - -// Last rev 8-1-24 diff --git a/Sources/bpp.cxx b/Sources/bpp.cxx new file mode 100644 index 0000000..e027c47 --- /dev/null +++ b/Sources/bpp.cxx @@ -0,0 +1,899 @@ +/* + * ======================================================== + * + * bpp + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 + +#include +#include +#include +#include +#include +#include +#include + +#define kMacroPrefix '%' + +/// @author Amlal El Mahrouss (amlel) +/// @file bpp.cxx +/// @brief Preprocessor. + +typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, + std::ofstream &pp_out); + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Preprocessor internal types. + +///////////////////////////////////////////////////////////////////////////////////////// + +namespace details { +enum { + kEqual, + kGreaterEqThan, + kLesserEqThan, + kGreaterThan, + kLesserThan, + kNotEqual, +}; + +struct bpp_macro_condition final { + int32_t fType; + std::string fTypeName; +}; + +struct bpp_macro final { + std::vector fArgs; + std::string fName; + std::string fValue; +}; + +class bpp_pragma final { + public: + explicit bpp_pragma() = default; + ~bpp_pragma() = default; + + MPCC_COPY_DEFAULT(bpp_pragma); + + std::string fMacroName; + bpp_parser_fn_t fParse; +}; +} // namespace details + +static std::vector kFiles; +static std::vector kMacros; +static std::vector kIncludes; + +static std::string kWorkingDir; + +static std::vector kKeywords = { + "include", "if", "pragma", "def", "elif", + "ifdef", "ifndef", "else", "warning", "error"}; + +#define kKeywordCxxCnt kKeywords.size() + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_if_condition +// @brief parse #if condition + +///////////////////////////////////////////////////////////////////////////////////////// + +int32_t bpp_parse_if_condition(details::bpp_macro_condition &cond, + details::bpp_macro ¯o, bool &inactive_code, + bool &defined, std::string ¯o_str) { + if (cond.fType == details::kEqual) { + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fValue) != std::string::npos) { + if (macro.fValue == "0") { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + } else if (cond.fType == details::kNotEqual) { + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fName) != std::string::npos) { + if (substr_macro.find(macro.fValue) != std::string::npos) { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + std::string number; + + for (auto ¯o_num : kMacros) { + if (substr_macro.find(macro_num.fName) != std::string::npos) { + for (size_t i = 0; i < macro_num.fName.size(); ++i) { + if (isdigit(macro_num.fValue[i])) { + number += macro_num.fValue[i]; + } else { + number.clear(); + break; + } + } + + break; + } + } + + size_t y = 2; + + /* last try */ + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + size_t rhs = atol(macro.fValue.c_str()); + size_t lhs = atol(number.c_str()); + + if (lhs == 0) { + number.clear(); + ++y; + + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + lhs = atol(number.c_str()); + } + + if (cond.fType == details::kGreaterThan) { + if (lhs < rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kGreaterEqThan) { + if (lhs <= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kLesserEqThan) { + if (lhs >= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kLesserThan) { + if (lhs > rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief stores every included file here. + +///////////////////////////////////////////////////////////////////////////////////////// + +std::vector kAllIncludes; + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_file +// @brief parse file to preprocess it. + +///////////////////////////////////////////////////////////////////////////////////////// + +void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { + std::string hdr_line; + std::string line_after_include; + + bool inactive_code = false; + bool defined = false; + + try { + while (std::getline(hdr_file, hdr_line)) { + /// BPP Documentation. + if (hdr_line.find("@bdoc") != std::string::npos) { + hdr_line.erase(hdr_line.find("@bdoc")); + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("endif") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = false; + + continue; + } + + continue; + } + + if (!defined && inactive_code) { + continue; + } + + if (defined && inactive_code) { + continue; + } + + for (auto macro : kMacros) { + if (ParserKit::find_word(hdr_line, macro.fName) && + hdr_line.find("%def") == std::string::npos) { + auto value = macro.fValue; + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + value); + } + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("def ") != std::string::npos) { + auto line_after_define = + hdr_line.substr(hdr_line.find("def ") + strlen("def ")); + + std::string macro_value; + std::string macro_key; + + std::size_t pos = 0UL; + + std::vector args; + bool on_args = false; + + for (auto &ch : line_after_define) { + ++pos; + + if (ch == '(') { + on_args = true; + continue; + } + + if (ch == ')') { + on_args = false; + continue; + } + + if (ch == '\\') continue; + + if (on_args) continue; + + if (ch == ' ') { + for (size_t i = pos; i < line_after_define.size(); i++) { + macro_value += line_after_define[i]; + } + + break; + } + + macro_key += ch; + } + + std::vector dupls; + std::string str; + + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto &subc : line_after_define) { + if (subc == ',' || subc == ')') { + if (str.empty()) continue; + + dupls.push_back(str); + args.push_back(str); + + str.clear(); + + continue; + } + + if (isalnum(subc)) str.push_back(subc); + } + + for (auto &dupl : dupls) { + std::size_t cnt = 0; + + for (auto &arg : args) { + if (dupl == arg) ++cnt; + } + + if (cnt > 1) { + auto it = std::find(args.begin(), args.end(), dupl); + + while (it != args.end()) { + args.erase(it); + it = std::find(args.begin(), args.end(), dupl); + } + } + } + + details::bpp_macro macro; + + macro.fArgs = args; + macro.fName = macro_key; + macro.fValue = macro_value; + + kMacros.emplace_back(macro); + + continue; + } + + if (hdr_line[0] != kMacroPrefix) { + if (inactive_code) { + continue; + } + + for (auto ¯o : kMacros) { + if (hdr_line.find(macro.fName) != std::string::npos) { + std::vector arg_values; + + if (macro.fArgs.size() > 0) { + for (size_t i = 0; i < hdr_line.size(); ++i) { + if (hdr_line[i] == '(') { + std::string tmp_arg; + + for (size_t x = i; x < hdr_line.size(); x++) { + if (hdr_line[x] == ')') break; + + if (hdr_line[x] == ' ') continue; + + if (hdr_line[i] == '\\') continue; + + if (hdr_line[x] == ',') { + arg_values.push_back(tmp_arg); + tmp_arg.clear(); + continue; + } + + tmp_arg += hdr_line[x]; + } + + break; + } + } + + std::string symbol; + + for (char i : macro.fValue) { + if (i == '(') break; + + if (i == '\\') continue; + + symbol += i; + } + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + symbol); + + size_t x_arg_indx = 0; + + for (size_t i = hdr_line.find(macro.fValue); i < hdr_line.size(); + ++i) { + if (hdr_line.find(macro.fArgs[x_arg_indx]) == i) { + hdr_line.replace(i, macro.fArgs[x_arg_indx].size(), + arg_values[x_arg_indx]); + ++x_arg_indx; + } + } + } else { + std::string symbol; + + for (size_t i = 0; i < macro.fValue.size(); i++) { + if (macro.fValue[i] == ' ') continue; + + if (macro.fValue[i] == '\\') continue; + + symbol += macro.fValue[i]; + } + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + symbol); + } + + break; + } + } + + pp_out << hdr_line << std::endl; + + continue; + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("ifndef") != std::string::npos) { + auto line_after_ifndef = + hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); + std::string macro; + + for (auto &ch : line_after_ifndef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = true; + inactive_code = false; + continue; + } + + if (macro == "1") { + defined = false; + inactive_code = true; + + continue; + } + + bool found = false; + + defined = true; + inactive_code = false; + + for (auto ¯o_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + found = true; + break; + } + } + + if (found) { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("else") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = true; + + continue; + } else { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("ifdef") != std::string::npos) { + auto line_after_ifdef = + hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); + std::string macro; + + for (auto &ch : line_after_ifdef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + defined = false; + inactive_code = true; + + for (auto ¯o_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + defined = true; + inactive_code = false; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("pragma") != std::string::npos) { + line_after_include = hdr_line.substr(hdr_line.find("pragma once")); + + // search for this file + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), + line_after_include); + + if (it == kAllIncludes.cend()) { + goto kIncludeFile; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("if") != std::string::npos) { + inactive_code = true; + + std::vector bpp_macro_condition_list = { + { + .fType = details::kEqual, + .fTypeName = "==", + }, + { + .fType = details::kNotEqual, + .fTypeName = "!=", + }, + { + .fType = details::kLesserThan, + .fTypeName = "<", + }, + { + .fType = details::kGreaterThan, + .fTypeName = ">", + }, + { + .fType = details::kLesserEqThan, + .fTypeName = "<=", + }, + { + .fType = details::kGreaterEqThan, + .fTypeName = ">=", + }, + }; + + int32_t good_to_go = 0; + + for (auto ¯o_condition : bpp_macro_condition_list) { + if (hdr_line.find(macro_condition.fTypeName) != std::string::npos) { + for (auto &found_macro : kMacros) { + if (hdr_line.find(found_macro.fName) != std::string::npos) { + good_to_go = + bpp_parse_if_condition(macro_condition, found_macro, + inactive_code, defined, hdr_line); + + break; + } + } + } + } + + if (good_to_go) continue; + + auto line_after_if = + hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); + std::string macro; + + for (auto &ch : line_after_if) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + // last try, is it defined to be one? + for (auto ¯o_ref : kMacros) { + if (macro_ref.fName.find(macro) != std::string::npos && + macro_ref.fValue == "1") { + inactive_code = false; + defined = true; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("warning") != std::string::npos) { + auto line_after_warning = + hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); + std::string message; + + for (auto &ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + std::cout << "Warning: " << message << std::endl; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("error") != std::string::npos) { + auto line_after_warning = + hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); + std::string message; + + for (auto &ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + throw std::runtime_error("Error: " + message); + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("inc ") != std::string::npos) { + line_after_include = + hdr_line.substr(hdr_line.find("inc ") + strlen("inc ")); + + kIncludeFile: + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), + line_after_include); + + if (it != kAllIncludes.cend()) { + continue; + } + + std::string path; + + kAllIncludes.push_back(line_after_include); + + bool enable = false; + bool not_local = false; + + for (auto &ch : line_after_include) { + if (ch == ' ') continue; + + if (ch == '<') { + not_local = true; + enable = true; + + continue; + } + + if (ch == '\'') { + enable = true; + continue; + } + + if (enable) { + if (not_local) { + if (ch == '>') break; + } else { + if (ch == '\'') { + break; + } + } + + path += ch; + } + } + + if (not_local) { + bool open = false; + + for (auto &include : kIncludes) { + std::string header_path = include; + header_path.push_back('/'); + header_path += path; + + std::ifstream header(header_path); + + if (!header.is_open()) continue; + + open = true; + + bpp_parse_file(header, pp_out); + + break; + } + + if (!open) { + throw std::runtime_error("bpp: no such include file: " + path); + } + } else { + std::ifstream header(kWorkingDir + path); + + if (!header.is_open()) + throw std::runtime_error("bpp: no such include file: " + path); + + bpp_parse_file(header, pp_out); + } + } else { + std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) + << "\n"; + continue; + } + } + } catch (std::out_of_range &oor) { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief main entrypoint of app. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSPreprocessor) { + try { + bool skip = false; + bool double_skip = false; + + details::bpp_macro macro_1; + macro_1.fName = "__true"; + macro_1.fValue = "1"; + + kMacros.push_back(macro_1); + + details::bpp_macro macro_0; + macro_0.fName = "__false"; + macro_0.fValue = "0"; + + kMacros.push_back(macro_0); + + details::bpp_macro macro_hcore; + macro_hcore.fName = "__MAHROUSS__"; + macro_hcore.fValue = "1"; + + kMacros.push_back(macro_hcore); + + for (auto index = 1UL; index < argc; ++index) { + if (skip) { + skip = false; + continue; + } + + if (double_skip) { + ++index; + double_skip = false; + continue; + } + + if (argv[index][0] == '/') { + if (strcmp(argv[index], "/version") == 0) { + printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); + return 0; + } + + if (strcmp(argv[index], "/help") == 0) { + printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) ZKA Technologies"); + printf("%s\n", "/working-dir : set directory to working path."); + printf("%s\n", "/include-dir : add directory to include path."); + printf("%s\n", "/def : def macro."); + printf("%s\n", "/version: print the version."); + printf("%s\n", "/help: show help."); + + return 0; + } + + if (strcmp(argv[index], "/include-dir") == 0) { + std::string inc = argv[index + 1]; + + skip = true; + + kIncludes.push_back(inc); + } + + if (strcmp(argv[index], "/working-dir") == 0) { + std::string inc = argv[index + 1]; + skip = true; + kWorkingDir = inc; + } + + if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && + argv[index + 2] != nullptr) { + std::string macro_key = argv[index + 1]; + + std::string macro_value; + bool is_string = false; + + for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); + ++argv_find_len) { + if (!isdigit(argv[index][argv_find_len])) { + is_string = true; + macro_value += "\""; + + break; + } + } + + macro_value += argv[index + 2]; + + if (is_string) macro_value += "\""; + + details::bpp_macro macro; + macro.fName = macro_key; + macro.fValue = macro_value; + + kMacros.push_back(macro); + + double_skip = true; + } + + continue; + } + + kFiles.emplace_back(argv[index]); + } + + if (kFiles.empty()) return MPCC_EXEC_ERROR; + + for (auto &file : kFiles) { + if (!std::filesystem::exists(file)) continue; + + std::ifstream file_descriptor(file); + std::ofstream file_descriptor_pp(file + ".pp"); + + bpp_parse_file(file_descriptor, file_descriptor_pp); + } + + return 0; + } catch (const std::runtime_error &e) { + std::cout << e.what() << '\n'; + } + + return 1; +} + +// Last rev 8-1-24 diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc deleted file mode 100644 index 71f5bba..0000000 --- a/Sources/coff2ae.cc +++ /dev/null @@ -1,23 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file coff2ae.cc -/// @brief COFF To AE, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/coff2ae.cxx b/Sources/coff2ae.cxx new file mode 100644 index 0000000..2f7e062 --- /dev/null +++ b/Sources/coff2ae.cxx @@ -0,0 +1,23 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file coff2ae.cxx +/// @brief COFF To AE, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/compile_flags.txt b/Sources/compile_flags.txt index f9acaba..6ec6b8a 100644 --- a/Sources/compile_flags.txt +++ b/Sources/compile_flags.txt @@ -1,5 +1,5 @@ -std=c++20 -I../ --I../Comm +-I../Headers -I./ -I./Detail/ diff --git a/Sources/cplusplus.cc b/Sources/cplusplus.cc deleted file mode 100644 index 4059413..0000000 --- a/Sources/cplusplus.cc +++ /dev/null @@ -1,905 +0,0 @@ -/* - * ======================================================== - * - * cplusplus - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// bugs: 0 - -#define __PK_USE_STRUCT_INSTEAD__ 1 - -#define kPrintF printf - -#define kSplashCxx() \ -kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") - -// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kOk 0 - -/* ZKA Technologies C++ driver */ -/* This is part of ZECC C++ compiler. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cc -/// @brief Optimized C++ Compiler. -/// @todo Throw error for scoped inside scoped variables when they get referenced outside. -/// @todo Add class/struct/enum support. - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNALS OF THE C COMPILER - -///////////////////////////////////// - -/// @internal -namespace detail -{ - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Offset based struct/class - struct CompilerStructMap final - { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; - -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cplusplus ] " << kWhite - << ((file == "cplusplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::vector kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for the Zeta C++ driver */ -class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend -{ -public: - explicit CompilerBackendCPlusPlus() = default; - ~CompilerBackendCPlusPlus() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); - - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override; -}; - -/// @internal compiler variables - -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; - -static std::vector kRegisterMap; - -static std::vector cRegisters = { - "rbx", - "rsi", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "xmm12", - "xmm13", - "xmm14", - "xmm15", -}; - -/// @brief The PEF calling convention (caller must save rax, rbp) -/// @note callee must return via **rax**. -static std::vector cRegistersCall = { - "rcx", - "rdx", - "r8", - "r9", - "xmm8", - "xmm9", - "xmm10", - "xmm11", -}; - -static size_t kLevelFunction = 0UL; - -/// detail namespaces - -const char* CompilerBackendCPlusPlus::Language() -{ - return "Zeta C++"; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @name Compile -/// @brief Generate MASM assembly from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCPlusPlus::Compile(const std::string& text, - const char* file) -{ - if (text.empty()) - return false; - - // if (expr) - // int name = expr; - // expr; - - std::size_t index = 0UL; - std::vector> keywords_list; - - bool found = false; - static bool commentBlock = false; - - for (auto& keyword : kKeywords) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - switch (keyword.keyword_kind) - { - case ParserKit::eKeywordKindCommentMultiLineStart: { - commentBlock = true; - return true; - } - case ParserKit::eKeywordKindCommentMultiLineEnd: { - commentBlock = false; - break; - } - case ParserKit::eKeywordKindCommentInline: { - break; - } - default: - break; - } - - if (text[text.find(keyword.keyword_name) - 1] == '+' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) - 1] == '-' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) + 1] == '=' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - - found = true; - } - } - - if (!found && !commentBlock) - { - for (size_t i = 0; i < text.size(); i++) - { - if (isalnum(text[i])) - { - detail::print_error("syntax error: " + text, file); - return false; - } - } - } - - for (auto& keyword : keywords_list) - { - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - switch (keyword.first.keyword_kind) - { - case ParserKit::KeywordKind::eKeywordKindFunctionStart: { - std::string fnName = text; - fnName.erase(fnName.find(keyword.first.keyword_name)); - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; - - ++kLevelFunction; - break; - } - case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { - --kLevelFunction; - - if (kRegisterMap.size() > cRegisters.size()) - { - --kLevelFunction; - } - - if (kLevelFunction < 1) - kRegisterMap.clear(); - break; - } - case ParserKit::KeywordKind::eKeywordKindEndInstr: - case ParserKit::KeywordKind::eKeywordKindVariableInc: - case ParserKit::KeywordKind::eKeywordKindVariableDec: - case ParserKit::KeywordKind::eKeywordKindVariableAssign: { - std::string valueOfVar = ""; - - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) - { - valueOfVar = text.substr(text.find("+=") + 2); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) - { - valueOfVar = text.substr(text.find("-=") + 2); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) - { - valueOfVar = text.substr(text.find("=") + 1); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) - { - valueOfVar = "0\n"; - } - - while (valueOfVar.find(";") != std::string::npos && - keyword.first.keyword_kind != ParserKit::KeywordKind::eKeywordKindEndInstr) - { - valueOfVar.erase(valueOfVar.find(";")); - } - - std::string varName = text; - - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) - { - varName.erase(varName.find("+=")); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) - { - varName.erase(varName.find("-=")); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) - { - varName.erase(varName.find("=")); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) - { - varName.erase(varName.find(";")); - } - - bool typeFound = false; - - for (auto& keyword : kKeywords) - { - if (keyword.keyword_kind == ParserKit::eKeywordKindType) - { - if (varName.find(keyword.keyword_name) != std::string::npos) - { - typeFound = true; - varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); - } - - /// in case we goot boolX or intX - if (text.find(keyword.keyword_name) != std::string::npos) - { - if (varName[text.find(keyword.keyword_name)] == ' ') - continue; - - typeFound = false; - } - } - } - - std::string instr = "mov "; - - if (typeFound) - { - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) - { - detail::print_error("Can't increment variable when it's being created.", file); - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) - { - detail::print_error("Can't decrement variable when it's being created.", file); - } - - if (kRegisterMap.size() > cRegisters.size()) - { - ++kLevelFunction; - } - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - continue; - } - - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1] + "\n"; - break; - } - - if (((int)indexRight - 1) < 0) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - } - - kRegisterMap.push_back(varName); - } - else - { - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) - { - instr = "add "; - } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) - { - instr = "sub "; - } - - std::string varErrCpy = varName; - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != varName) - continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - continue; - } - - syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1] + "\n"; - break; - } - - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + varErrCpy, file); - } - } - - break; - } - case ParserKit::KeywordKind::eKeywordKindReturn: { - auto pos = text.find("return") + strlen("return") + 1; - std::string subText = text.substr(pos); - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (subText[0] != '\"' && - subText[0] != '\'') - { - if (!isdigit(subText[0])) - { - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != subText) - continue; - - syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret\n"; - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + subText, file); - } - } - else - { - syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; - } - } - else - { - syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; - syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; - } - - break; - } - default: - break; - } - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } - -_MpccOkay: - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCPlusPlusInterface() = default; - ~AssemblyCPlusPlusInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); - - [[maybe_unused]] - static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchAMD64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCPlusPlusInterface::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - if (dest.empty()) - { - dest = "CXX-MPCC-"; - - std::random_device rd; - auto seed_data = std::array {}; - - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator(generator); - - auto id = gen(); - dest += uuids::to_string(id); - } - - std::vector exts = kAsmFileExts; - - dest += exts[3]; - - std::cout << dest; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: AMD64 assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; - (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" - << "\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string source; - - while (std::getline(src_fp, source)) - { - // Compile into an object file. - kCompilerBackend->Compile(source.c_str(), src.c_str()); - } - - for (auto& ast : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << ast.fUserValue; - } - - if (kAcceptableErrors > 0) - return -1; - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static void cxx_print_help() -{ - kSplashCxx(); - kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { \ - ".cpp", ".cxx", ".cc", ".c++", ".cp" \ - } - -NDK_MODULE(CompilerCPlusPlus) -{ - bool skip = false; - - kKeywords.push_back({.keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); - kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); - kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "bool", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "char", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "long", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "void", .keyword_kind = ParserKit::eKeywordKindType}); - - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariablePtr}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - - kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); - kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); - kKeywords.push_back({.keyword_name = "+=", .keyword_kind = ParserKit::eKeywordKindVariableInc}); - kKeywords.push_back({.keyword_name = "-=", .keyword_kind = ParserKit::eKeywordKindVariableDec}); - kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); - kKeywords.push_back({.keyword_name = "*", .keyword_kind = ParserKit::eKeywordKindPtr}); - kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); - kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); - kKeywords.push_back({.keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator}); - kKeywords.push_back({.keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr}); - kKeywords.push_back({.keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "return", .keyword_kind = ParserKit::eKeywordKindReturn}); - kKeywords.push_back({.keyword_name = "/*", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "*/", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "//", .keyword_kind = ParserKit::eKeywordKindCommentInline}); - kKeywords.push_back({.keyword_name = "==", .keyword_kind = ParserKit::eKeywordKindEq}); - kKeywords.push_back({.keyword_name = "!=", .keyword_kind = ParserKit::eKeywordKindNotEq}); - kKeywords.push_back({.keyword_name = ">=", .keyword_kind = ParserKit::eKeywordKindGreaterEq}); - kKeywords.push_back({.keyword_name = "<=", .keyword_kind = ParserKit::eKeywordKindLessEq}); - - kFactory.Mount(new AssemblyCPlusPlusInterface()); - kCompilerBackend = new CompilerBackendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) - { - if (argv[index][0] == '/') - { - if (skip) - { - skip = false; - continue; - } - - if (strcmp(argv[index], "/v") == 0 || - strcmp(argv[index], "/version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "/verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) - { - cxx_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "/dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "/max-errors") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - detail::print_error(err, "cplusplus"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - bool found = false; - - for (std::string ext : exts) - { - if (argv_i.find(ext) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - if (kState.fVerbose) - { - detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx new file mode 100644 index 0000000..3eb6e9b --- /dev/null +++ b/Sources/cplusplus.cxx @@ -0,0 +1,905 @@ +/* + * ======================================================== + * + * cplusplus + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// bugs: 0 + +#define __PK_USE_STRUCT_INSTEAD__ 1 + +#define kPrintF printf + +#define kSplashCxx() \ +kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") + +// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kOk 0 + +/* ZKA Technologies C++ driver */ +/* This is part of ZECC C++ compiler. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief Optimized C++ Compiler. +/// @todo Throw error for scoped inside scoped variables when they get referenced outside. +/// @todo Add class/struct/enum support. + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNALS OF THE C COMPILER + +///////////////////////////////////// + +/// @internal +namespace detail +{ + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Offset based struct/class + struct CompilerStructMap final + { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; + +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cplusplus ] " << kWhite + << ((file == "cplusplus") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank + << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; + +///////////////////////////////////////// + +// ARGUMENTS REGISTERS (R8, R15) + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::vector kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static size_t kBracesCount = 0UL; + +/* @brief C++ compiler backend for the Zeta C++ driver */ +class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCPlusPlus() = default; + ~CompilerBackendCPlusPlus() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); + + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override; +}; + +/// @internal compiler variables + +static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; + +static std::vector kRegisterMap; + +static std::vector cRegisters = { + "rbx", + "rsi", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "xmm12", + "xmm13", + "xmm14", + "xmm15", +}; + +/// @brief The PEF calling convention (caller must save rax, rbp) +/// @note callee must return via **rax**. +static std::vector cRegistersCall = { + "rcx", + "rdx", + "r8", + "r9", + "xmm8", + "xmm9", + "xmm10", + "xmm11", +}; + +static size_t kLevelFunction = 0UL; + +/// detail namespaces + +const char* CompilerBackendCPlusPlus::Language() +{ + return "Zeta C++"; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @name Compile +/// @brief Generate MASM assembly from a C++ source. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCPlusPlus::Compile(const std::string& text, + const char* file) +{ + if (text.empty()) + return false; + + // if (expr) + // int name = expr; + // expr; + + std::size_t index = 0UL; + std::vector> keywords_list; + + bool found = false; + static bool commentBlock = false; + + for (auto& keyword : kKeywords) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + switch (keyword.keyword_kind) + { + case ParserKit::eKeywordKindCommentMultiLineStart: { + commentBlock = true; + return true; + } + case ParserKit::eKeywordKindCommentMultiLineEnd: { + commentBlock = false; + break; + } + case ParserKit::eKeywordKindCommentInline: { + break; + } + default: + break; + } + + if (text[text.find(keyword.keyword_name) - 1] == '+' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) + 1] == '=' && + keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + + found = true; + } + } + + if (!found && !commentBlock) + { + for (size_t i = 0; i < text.size(); i++) + { + if (isalnum(text[i])) + { + detail::print_error("syntax error: " + text, file); + return false; + } + } + } + + for (auto& keyword : keywords_list) + { + auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + switch (keyword.first.keyword_kind) + { + case ParserKit::KeywordKind::eKeywordKindFunctionStart: { + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; + + ++kLevelFunction; + break; + } + case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { + --kLevelFunction; + + if (kRegisterMap.size() > cRegisters.size()) + { + --kLevelFunction; + } + + if (kLevelFunction < 1) + kRegisterMap.clear(); + break; + } + case ParserKit::KeywordKind::eKeywordKindEndInstr: + case ParserKit::KeywordKind::eKeywordKindVariableInc: + case ParserKit::KeywordKind::eKeywordKindVariableDec: + case ParserKit::KeywordKind::eKeywordKindVariableAssign: { + std::string valueOfVar = ""; + + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + valueOfVar = text.substr(text.find("+=") + 2); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + valueOfVar = text.substr(text.find("-=") + 2); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + { + valueOfVar = text.substr(text.find("=") + 1); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + valueOfVar = "0\n"; + } + + while (valueOfVar.find(";") != std::string::npos && + keyword.first.keyword_kind != ParserKit::KeywordKind::eKeywordKindEndInstr) + { + valueOfVar.erase(valueOfVar.find(";")); + } + + std::string varName = text; + + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + varName.erase(varName.find("+=")); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + varName.erase(varName.find("-=")); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + { + varName.erase(varName.find("=")); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + varName.erase(varName.find(";")); + } + + bool typeFound = false; + + for (auto& keyword : kKeywords) + { + if (keyword.keyword_kind == ParserKit::eKeywordKindType) + { + if (varName.find(keyword.keyword_name) != std::string::npos) + { + typeFound = true; + varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); + } + + /// in case we goot boolX or intX + if (text.find(keyword.keyword_name) != std::string::npos) + { + if (varName[text.find(keyword.keyword_name)] == ' ') + continue; + + typeFound = false; + } + } + } + + std::string instr = "mov "; + + if (typeFound) + { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + detail::print_error("Can't increment variable when it's being created.", file); + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + detail::print_error("Can't decrement variable when it's being created.", file); + } + + if (kRegisterMap.size() > cRegisters.size()) + { + ++kLevelFunction; + } + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + std::size_t indexRight = 0UL; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1] + "\n"; + break; + } + + if (((int)indexRight - 1) < 0) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + } + + kRegisterMap.push_back(varName); + } + else + { + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + { + instr = "add "; + } + else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + { + instr = "sub "; + } + + std::string varErrCpy = varName; + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + std::size_t indxReg = 0UL; + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + /// interpet boolean values, since we're on C++ + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != varName) + continue; + + std::size_t indexRight = 0ul; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1] + "\n"; + break; + } + + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + varErrCpy, file); + } + } + + break; + } + case ParserKit::KeywordKind::eKeywordKindReturn: { + auto pos = text.find("return") + strlen("return") + 1; + std::string subText = text.substr(pos); + subText = subText.erase(subText.find(";")); + size_t indxReg = 0UL; + + if (subText[0] != '\"' && + subText[0] != '\'') + { + if (!isdigit(subText[0])) + { + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != subText) + continue; + + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret\n"; + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + subText, file); + } + } + else + { + syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; + } + } + else + { + syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; + syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; + } + + break; + } + default: + break; + } + + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); + } + +_MpccOkay: + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCPlusPlusInterface() = default; + ~AssemblyCPlusPlusInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); + + [[maybe_unused]] + static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchAMD64; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCPlusPlusInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + if (dest.empty()) + { + dest = "CXX-MPCC-"; + + std::random_device rd; + auto seed_data = std::array {}; + + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator(generator); + + auto id = gen(); + dest += uuids::to_string(id); + } + + std::vector exts = kAsmFileExts; + + dest += exts[3]; + + std::cout << dest; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "; Language: AMD64 assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; + (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" + << "\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.emplace_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string source; + + while (std::getline(src_fp, source)) + { + // Compile into an object file. + kCompilerBackend->Compile(source.c_str(), src.c_str()); + } + + for (auto& ast : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << ast.fUserValue; + } + + if (kAcceptableErrors > 0) + return -1; + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static void cxx_print_help() +{ + kSplashCxx(); + kPrintF("%s", "No help available, see:\n"); + kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExtListCxx \ + { \ + ".cpp", ".cxx", ".cc", ".c++", ".cp" \ + } + +NDK_MODULE(CompilerCPlusPlus) +{ + bool skip = false; + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); + kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = ParserKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); + + kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); + kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = ParserKit::eKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = ParserKit::eKeywordKindVariableDec}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = ParserKit::eKeywordKindPtr}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = ParserKit::eKeywordKindReturn}); + kKeywords.push_back({.keyword_name = "/*", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "*/", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "//", .keyword_kind = ParserKit::eKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = ParserKit::eKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = ParserKit::eKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = ParserKit::eKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = ParserKit::eKeywordKindLessEq}); + + kFactory.Mount(new AssemblyCPlusPlusInterface()); + kCompilerBackend = new CompilerBackendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) + { + if (argv[index][0] == '/') + { + if (skip) + { + skip = false; + continue; + } + + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cxx_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/max-errors") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + detail::print_error(err, "cplusplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + bool found = false; + + for (std::string ext : exts) + { + if (argv_i.find(ext) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + if (kState.fVerbose) + { + detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); + } + + return 1; + } + + if (kFactory.Compile(argv_i, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc deleted file mode 100644 index 70ab104..0000000 --- a/Sources/elf2ae.cc +++ /dev/null @@ -1,22 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief COFF 2 AE entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/Sources/elf2ae.cxx b/Sources/elf2ae.cxx new file mode 100644 index 0000000..3409f6e --- /dev/null +++ b/Sources/elf2ae.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief COFF 2 AE entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc deleted file mode 100644 index c0dd351..0000000 --- a/Sources/i64asm.cc +++ /dev/null @@ -1,1484 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file i64asm.cxx -/// @author Amlal EL Mahrouss -/// @brief AMD64 Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -/// bugs: 0 - -/// feature request: 1 -/// Encode registers in mov, add, xor... - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_AMD64__ 1 - -#define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -static char kOutputArch = CompilerKit::kPefArchAMD64; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -constexpr auto cAMD64IPAlignment = 0x4U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -/// @brief keep it simple by default. -static std::int32_t kRegisterBitWidth = 16U; - -static bool kVerbose = false; - -static std::vector kAppBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kDefinedSymbols; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string& line); - -namespace detail -{ - void print_error(std::string reason, const std::string& file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - kStdErr << kRed << "[ i64asm ] " << kWhite - << ((file == "i64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - void print_warning(std::string reason, const std::string& file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (!file.empty()) - { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank - << std::endl; - } -} // namespace detail - -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssemblerAMD64) -{ - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) - { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) - { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) - { - if (argv[i][0] == '/') - { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) - { - kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " - "(c) ZKA Technologies.\n"; - return 0; - } - else if (strcmp(argv[i], "/h") == 0) - { - kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version: Print program version.\n"; - kStdOut << "/verbose: Print verbose output.\n"; - kStdOut << "/binary: Output as flat binary.\n"; - - return 0; - } - else if (strcmp(argv[i], "/binary") == 0) - { - kOutputAsBinary = true; - continue; - } - else if (strcmp(argv[i], "/verbose") == 0) - { - kVerbose = true; - continue; - } - - kStdOut << "i64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) - { - kStdOut << "i64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) - { - if (object_output.find(ext) != std::string::npos) - { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) - { - if (kVerbose) - { - kStdOut << "i64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderAMD64 asm64; - - while (std::getline(file_ptr, line)) - { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) - { - detail::print_error(ln, argv[i]); - continue; - } - - try - { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } - catch (const std::exception& e) - { - if (kVerbose) - { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "i64asm"); - } - - try - { - std::filesystem::remove(object_output); - } - catch (...) - { - } - - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "i64asm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) - { - kStdErr << "i64asm: At least one record is needed to write an object " - "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) - { - if (kVerbose) - kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) - { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) - kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "i64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kAppBytes) - { - if (byte == 0) - continue; - - if (byte == 0xFF) - { - byte = 0; - } - - file_ptr_out << reinterpret_cast(&byte)[0]; - } - - if (kVerbose) - kStdOut << "i64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) - kStdOut << "i64asm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) - kStdOut << "i64asm: Exit failed.\n"; - - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string& line) -{ - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (ParserKit::find_word(line, "import")) - { - if (kOutputAsBinary) - { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) - { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) - { - if (j == ' ' || j == ',') - j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by i64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (ParserKit::find_word(line, "export")) - { - if (kOutputAsBinary) - { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export") + 1); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) - { - detail::print_error("Symbol already defined.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm -{ - // \brief authorize a brief set of characters. - static inline bool is_not_alnum_space(char c) - { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); - } - - bool is_valid(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); - } -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - ParserKit::find_word(line, kAssemblerPragmaSymStr) || - ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) - { - if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) - { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) - { - err_str = "Line contains non alphanumeric characters.\nHere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) - { - if (line.find(',') + 1 == line.size()) - { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } - else - { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) - { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) - { - if (ch != ' ' && ch != '\t') - { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) - { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto& opcodeAMD64 : kOpcodesAMD64) - { - if (ParserKit::find_word(line, opcodeAMD64.fName)) - { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, - const std::string& file) -{ - if (ParserKit::find_word(line, "export ")) - return true; - - struct RegMapAMD64 - { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector REGISTER_LIST{ - {.fName = "ax", .fModRM = 0x0}, - {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, - {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, - {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, - {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, - {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, - {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, - {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto& opcodeAMD64 : kOpcodesAMD64) - { - // strict check here - if (ParserKit::find_word(line, opcodeAMD64.fName) && - detail::algorithm::is_valid(line)) - { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (name.find("mov") != std::string::npos) - { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) - { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector currentRegList; - - for (auto& reg : REGISTER_LIST) - { - std::vector regExt = {'e', 'r'}; - - for (auto& ext : regExt) - { - std::string registerName; - - if (bits > 16) - registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) - { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) - { - if (registerName[0] == 'r') - { - detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) - onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) - { - /// very tricky to understand. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') - { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } - else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) - { - if (!hasRBasedRegs && bits >= 32) - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x89); - } - else if (bits == 16) - { - if (hasRBasedRegs) - { - detail::print_error( - "Invalid combination of operands and registers.", "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) - { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - else - { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } - else if (name == "int" || name == "into" || name == "intd") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } - else if (name == "jmp" || name == "call") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) - { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } - else - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) - { - if (foundInstruction) - { - detail::print_error("Syntax error: " + line, "i64asm"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) - { - kRegisterBitWidth = 64U; - } - else if (line.find("bits 32") != std::string::npos) - { - kRegisterBitWidth = 32U; - } - else if (line.find("bits 16") != std::string::npos) - { - kRegisterBitWidth = 16U; - } - else if (line.find("org") != std::string::npos) - { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) - { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) - { - if (errno != 0) - { - continue; - } - else - { - if (kVerbose) - { - kStdOut << "i64asm: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) - { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) - { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) - { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += cAMD64IPAlignment; - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/i64asm.cxx b/Sources/i64asm.cxx new file mode 100644 index 0000000..a1f57b3 --- /dev/null +++ b/Sources/i64asm.cxx @@ -0,0 +1,1484 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file i64asm.cxx +/// @author Amlal EL Mahrouss +/// @brief AMD64 Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +/// bugs: 0 + +/// feature request: 1 +/// Encode registers in mov, add, xor... + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_AMD64__ 1 + +#define kAssemblerPragmaSymStr "#" +#define kAssemblerPragmaSym '#' + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +static char kOutputArch = CompilerKit::kPefArchAMD64; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +constexpr auto cAMD64IPAlignment = 0x4U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +/// @brief keep it simple by default. +static std::int32_t kRegisterBitWidth = 16U; + +static bool kVerbose = false; + +static std::vector kAppBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kDefinedSymbols; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string& line); + +namespace detail +{ + void print_error(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + kStdErr << kRed << "[ i64asm ] " << kWhite + << ((file == "i64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + void print_warning(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (!file.empty()) + { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank + << std::endl; + } +} // namespace detail + +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief AMD64 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerAMD64) +{ + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = { + "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", + "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", + "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) + { + CpuOpcodeAMD64 code{ + .fName = opcodes_jump[i], + .fOpcode = static_cast(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) + { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) + { + if (argv[i][0] == '/') + { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " + "(c) ZKA Technologies.\n"; + return 0; + } + else if (strcmp(argv[i], "/h") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + + return 0; + } + else if (strcmp(argv[i], "/binary") == 0) + { + kOutputAsBinary = true; + continue; + } + else if (strcmp(argv[i], "/verbose") == 0) + { + kVerbose = true; + continue; + } + + kStdOut << "i64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) + { + kStdOut << "i64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) + { + if (object_output.find(ext) != std::string::npos) + { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) + { + if (kVerbose) + { + kStdOut << "i64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + while (std::getline(file_ptr, line)) + { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) + { + detail::print_error(ln, argv[i]); + continue; + } + + try + { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } + catch (const std::exception& e) + { + if (kVerbose) + { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "i64asm"); + } + + try + { + std::filesystem::remove(object_output); + } + catch (...) + { + } + + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) + { + if (kVerbose) + { + kStdOut << "i64asm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) + { + kStdErr << "i64asm: At least one record is needed to write an object " + "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + std::size_t record_count = 0UL; + + for (auto& rec : kRecords) + { + if (kVerbose) + kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; + + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; + + file_ptr_out << rec; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto& sym : kUndefinedSymbols) + { + CompilerKit::AERecordHeader _record_hdr{0}; + + if (kVerbose) + kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + + file_ptr_out << _record_hdr; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kAppBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto& byte : kAppBytes) + { + if (byte == 0) + continue; + + if (byte == 0xFF) + { + byte = 0; + } + + file_ptr_out << reinterpret_cast(&byte)[0]; + } + + if (kVerbose) + kStdOut << "i64asm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) + kStdOut << "i64asm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) + kStdOut << "i64asm: Exit failed.\n"; + + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string& line) +{ + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (ParserKit::find_word(line, "import")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) + { + detail::print_error("Invalid import", "ppcasm"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) + { + if (j == ' ' || j == ',') + j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by i64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (ParserKit::find_word(line, "export")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export") + 1); + + std::string name_copy = name; + + for (char& j : name) + { + if (j == ' ') + j = '$'; + } + + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != + kDefinedSymbols.end()) + { + detail::print_error("Symbol already defined.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + kDefinedSymbols.push_back(name); + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm +{ + // \brief authorize a brief set of characters. + static inline bool is_not_alnum_space(char c) + { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); + } + + bool is_valid(const std::string& str) + { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); + } +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, + const std::string& file) +{ + std::string err_str; + + if (line.empty() || ParserKit::find_word(line, "import") || + ParserKit::find_word(line, "export") || + ParserKit::find_word(line, kAssemblerPragmaSymStr) || + ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + { + if (line.find(';') != std::string::npos) + { + line.erase(line.find(';')); + } + else + { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non valid characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non alphanumeric characters.\nHere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) + { + if (line.find(',') + 1 == line.size()) + { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } + else + { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto& ch : substr) + { + if (ch != ' ' && ch != '\t') + { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + if (ParserKit::find_word(line, opcodeAMD64.fName)) + { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; +} + +bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, + const std::string& file) +{ + if (ParserKit::find_word(line, "export ")) + return true; + + struct RegMapAMD64 + { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector REGISTER_LIST{ + {.fName = "ax", .fModRM = 0x0}, + {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, + {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, + {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, + {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, + {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, + {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, + {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + // strict check here + if (ParserKit::find_word(line, opcodeAMD64.fName) && + detail::algorithm::is_valid(line)) + { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (name.find("mov") != std::string::npos) + { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) + { + detail::print_error("Syntax error.", "i64asm"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector currentRegList; + + for (auto& reg : REGISTER_LIST) + { + std::vector regExt = {'e', 'r'}; + + for (auto& ext : regExt) + { + std::string registerName; + + if (bits > 16) + registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) + { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) + { + if (registerName[0] == 'r') + { + detail::print_error( + "invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back( + {.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) + onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) + { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || + currentRegList[1].fName[0] == 'r') + { + if (isdigit(currentRegList[0].fName[1]) && + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } + else if (isdigit(currentRegList[0].fName[1]) || + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) + { + if (!hasRBasedRegs && bits >= 32) + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x89); + } + else if (bits == 16) + { + if (hasRBasedRegs) + { + detail::print_error( + "Invalid combination of operands and registers.", "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + + if (currentRegList[1].fName[0] == 'r' && + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) + { + if (currentRegList[0].fName[0] == 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + else + { + if (currentRegList[0].fName[0] != 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | + currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } + else if (name == "int" || name == "into" || name == "intd") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } + else if (name == "jmp" || name == "call") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) + { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } + else + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) + { + if (foundInstruction) + { + detail::print_error("Syntax error: " + line, "i64asm"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) + { + kRegisterBitWidth = 64U; + } + else if (line.find("bits 32") != std::string::npos) + { + kRegisterBitWidth = 32U; + } + else if (line.find("bits 16") != std::string::npos) + { + kRegisterBitWidth = 16U; + } + else if (line.find("org") != std::string::npos) + { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) + { + if (kOrigin = strtol( + (line.substr(line.find("org") + strlen("org") + 1)).c_str(), + nullptr, base[i]); + kOrigin) + { + if (errno != 0) + { + continue; + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) + { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) + { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) + { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += cAMD64IPAlignment; + + return true; +} + +// Last rev 13-1-24 diff --git a/Sources/link.cc b/Sources/link.cc deleted file mode 100644 index d94cbf1..0000000 --- a/Sources/link.cc +++ /dev/null @@ -1,738 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// @file link.cc -/// @author Amlal EL Mahrouss (amlel) -/// @brief ZKA Technologies Linker. - -/// Last Rev: Sat Feb 24 CET 2024 - -/// @note Do not look up for anything with .code64/.data64/.zero64! -/// It will be loaded when program will start up! - -#include - -//! Assembler Kit -#include - -//! Preferred Executable Format -#include -#include -#include -#include -#include - -//! Dist version -#include - -//! Advanced Executable Object Format -#include - -//! C++ I/O headers. -#include -#include - -#define kLinkerVersion "Zeta Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" - -#define StringCompare(DST, SRC) strcmp(DST, SRC) - -#define kPefNoCpu 0U -#define kPefNoSubCpu 0U - -#define kWhite "\e[0;97m" -#define kStdOut (std::cout << kWhite) - -#define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId 0x5046FF -#define kLinkerAbiContainer "Container:Abi:" - -enum -{ - kStandardAbi = 0x5046 /* PF */ -}; - -static std::string kOutput; -static Int32 kAbi = kStandardAbi; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArch64000; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; -static Bool kVerbose = false; - -/* link is to be found, mld is to be found at runtime. */ -static const char* kLdDefineSymbol = ":UndefinedSymbol:"; -static const char* kLdDynamicSym = ":RuntimeSymbol:"; - -/* object code and list. */ -static std::vector kObjectList; -static std::vector kObjectBytes; - -#define kPrintF printf -#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) - -NDK_MODULE(NewOSLinker) -{ - bool is_executable = true; - - /** - * @brief parse flags and such. - * - */ - for (size_t i = 1; i < argc; ++i) - { - if (StringCompare(argv[i], "/help") == 0) - { - kLinkerSplash(); - kStdOut << "/version: Show linker version.\n"; - kStdOut << "/help: Show linker help.\n"; - kStdOut << "/verbose: Enable linker trace.\n"; - kStdOut << "/shared: Output as a shared PEF.\n"; - kStdOut << "/fat-bin: Output as a FAT PEF.\n"; - kStdOut << "/32x0: Output as a 32x0 PEF.\n"; - kStdOut << "/64x0: Output as a 64x0 PEF.\n"; - kStdOut << "/amd64: Output as a AMD64 PEF.\n"; - kStdOut << "/rv64: Output as a RISC-V PEF.\n"; - kStdOut << "/power64: Output as a POWER PEF.\n"; - kStdOut << "/arm64: Output as a ARM64 PEF.\n"; - kStdOut << "/output-file: Select the output file name.\n"; - - return 0; - } - else if (StringCompare(argv[i], "/version") == 0) - { - kLinkerSplash(); - return 0; - } - else if (StringCompare(argv[i], "/fat-bin") == 0) - { - kFatBinaryEnable = true; - - continue; - } - else if (StringCompare(argv[i], "/64x0") == 0) - { - kArch = CompilerKit::kPefArch64000; - - continue; - } - else if (StringCompare(argv[i], "/amd64") == 0) - { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } - else if (StringCompare(argv[i], "/32x0") == 0) - { - kArch = CompilerKit::kPefArch32000; - - continue; - } - else if (StringCompare(argv[i], "/power64") == 0) - { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } - else if (StringCompare(argv[i], "/arm64") == 0) - { - kArch = CompilerKit::kPefArchARM64; - - continue; - } - else if (StringCompare(argv[i], "/verbose") == 0) - { - kVerbose = true; - - continue; - } - else if (StringCompare(argv[i], "/shared") == 0) - { - if (kOutput.empty()) - { - continue; - } - - if (kOutput.find(kPefExt) != std::string::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } - else if (StringCompare(argv[i], "/output-file") == 0) - { - kOutput = argv[i + 1]; - ++i; - - continue; - } - else - { - if (argv[i][0] == '/') - { - kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return MPCC_EXEC_ERROR; - } - - kObjectList.emplace_back(argv[i]); - - continue; - } - } - - if (kOutput.empty()) - { - kStdOut << "link: no output filename set." << std::endl; - return MPCC_EXEC_ERROR; - } - - // sanity check. - if (kObjectList.empty()) - { - kStdOut << "link: no input files." << std::endl; - return MPCC_EXEC_ERROR; - } - else - { - namespace fs = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) - { - if (!fs::exists(obj)) - { - // if filesystem doesn't find file - // -> throw error. - kStdOut << "link: no such file: " << obj << std::endl; - return MPCC_EXEC_ERROR; - } - } - } - - // PEF expects a valid architecture when outputing a binary. - if (kArch == 0) - { - kStdOut << "link: no target architecture set, can't continue." << std::endl; - return MPCC_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = CompilerKit::kPefKindExec; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // ZKA Technologies Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - - std::ofstream outputFc(kOutput, std::ofstream::binary); - - if (outputFc.bad()) - { - if (kVerbose) - { - kStdOut << "link: error: " << strerror(errno) << "\n"; - } - - return MPCC_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector commandHdrsList; - CompilerKit::Utils::AEReadableProtocol readProto{}; - - for (const auto& i : kObjectList) - { - if (!std::filesystem::exists(i)) - continue; - - CompilerKit::AEHeader hdr{}; - - readProto.FP = std::ifstream(i, std::ifstream::binary); - readProto.FP >> hdr; - - auto ae_header = hdr; - - if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && - ae_header.fSize == sizeof(CompilerKit::AEHeader)) - { - if (ae_header.fArch != kArch) - { - if (kVerbose) - kStdOut << "link: info: is this a FAT binary? : "; - - if (!kFatBinaryEnable) - { - if (kVerbose) - kStdOut << "No.\n"; - - kStdOut << "link: error: object " << i - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - std::remove(kOutput.c_str()); - return MPCC_FAT_ERROR; - } - else - { - if (kVerbose) - { - kStdOut << "Yes.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= ae_header.fArch; - std::size_t cnt = ae_header.fCount; - - if (kVerbose) - kStdOut << "link: object header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - char_type* raw_ae_records = - new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; - memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto* ae_records = readProto.Read(raw_ae_records, cnt); - for (size_t ae_record_index = 0; ae_record_index < cnt; - ++ae_record_index) - { - CompilerKit::PEFCommandHeader command_header{0}; - size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; - - memcpy(command_header.Name, ae_records[ae_record_index].fName, - kPefNameLen); - - // check this header if it's any valid. - if (std::string(command_header.Name).find(".code64") == - std::string::npos && - std::string(command_header.Name).find(".data64") == - std::string::npos && - std::string(command_header.Name).find(".zero64") == - std::string::npos) - { - if (std::string(command_header.Name).find(kPefStart) == - std::string::npos && - *command_header.Name == 0) - { - if (std::string(command_header.Name).find(kLdDefineSymbol) != - std::string::npos) - { - goto ld_mark_header; - } - else - { - continue; - } - } - } - - if (std::string(command_header.Name).find(kPefStart) != - std::string::npos && - std::string(command_header.Name).find(".code64") != - std::string::npos) - { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offsetOfData; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; - command_header.Cpu = ae_header.fArch; - command_header.SubCpu = ae_header.fSubArch; - - if (kVerbose) - { - kStdOut << "link: object record: " - << ae_records[ae_record_index].fName << " was marked.\n"; - - kStdOut << "link: object record offset: " << command_header.Offset << "\n"; - } - - commandHdrsList.emplace_back(command_header); - } - - delete[] raw_ae_records; - - std::vector bytes; - bytes.resize(ae_header.fCodeSize); - - readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); - readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); - - for (auto& byte : bytes) - { - kObjectBytes.push_back(byte); - } - - readProto.FP.close(); - - continue; - } - - kStdOut << "link: not an object: " << i << std::endl; - std::remove(kOutput.c_str()); - - // don't continue, it is a fatal error. - return MPCC_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - outputFc << pef_container; - - if (kVerbose) - { - kStdOut << "link: wrote container header.\n"; - } - - outputFc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector not_found; - std::vector symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - for (auto& commandHdr : commandHdrsList) - { - // check if this symbol needs to be resolved. - if (std::string(commandHdr.Name).find(kLdDefineSymbol) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) - { - if (kVerbose) - kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; - - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it == not_found.end()) - { - not_found.emplace_back(commandHdr.Name); - } - } - - symbols.emplace_back(commandHdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); - ++not_found_idx) - { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdrsList[not_found_idx].Name)); - it != not_found.end()) - { - std::string symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) - continue; - - // erase the lookup prefix. - symbol_imp.erase( - 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != std::string::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto& commandHdr : commandHdrsList) - { - if (std::string(commandHdr.Name).find(symbol_imp) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDefineSymbol) == - std::string::npos) - { - std::string undefined_symbol = commandHdr.Name; - auto result_of_sym = - undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) - { - if (result_of_sym[i] != symbol_imp[i]) - goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) - kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) - { - if (kVerbose) - kStdOut - << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " - "against your compiler's runtime library.\n"; - - kStdOut << "link: undefined entrypoint " << kPefStart - << " for executable: " << kOutput << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader dateHeader{}; - - time_t timestamp = time(nullptr); - - std::string timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strcpy(dateHeader.Name, timeStampStr.c_str()); - - dateHeader.Flags = 0; - dateHeader.Kind = CompilerKit::kPefZero; - dateHeader.Offset = outputFc.tellp(); - dateHeader.Size = timeStampStr.size(); - - commandHdrsList.push_back(dateHeader); - - CompilerKit::PEFCommandHeader abiHeader{}; - - std::string abi = kLinkerAbiContainer; - - switch (kArch) - { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "MHRA"; - break; - } - default: { - abi += " IDK"; - break; - } - } - - memcpy(abiHeader.Name, abi.c_str(), abi.size()); - - abiHeader.Size = abi.size(); - abiHeader.Offset = outputFc.tellp(); - abiHeader.Flags = 0; - abiHeader.Kind = CompilerKit::kPefLinkerID; - - commandHdrsList.push_back(abiHeader); - - CompilerKit::PEFCommandHeader uuidHeader{}; - - std::random_device rd; - - auto seedData = std::array{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), - uuidStr.size()); - - uuidHeader.Size = 16; - uuidHeader.Offset = outputFc.tellp(); - uuidHeader.Flags = 0; - uuidHeader.Kind = CompilerKit::kPefZero; - - commandHdrsList.push_back(uuidHeader); - - // prepare a symbol vector. - std::vector undefSymbols; - std::vector duplSymbols; - std::vector resolveSymbols; - - constexpr Int32 cPaddingOffset = 16; - - size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; - commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) - { - if (std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) - { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - std::string symbolName = commandHdrsList[commandHeaderIndex].Name; - - if (!symbolName.empty()) - { - undefSymbols.emplace_back(symbolName); - } - - commandHdrsList[commandHeaderIndex].Offset += previousOffset; - previousOffset += commandHdrsList[commandHeaderIndex].Size; - - std::string name = commandHdrsList[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kPefStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != std::string::npos && - name.find(".code64") != std::string::npos) - { - pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; - auto tellCurPos = outputFc.tellp(); - - outputFc.seekp(0); - outputFc << pef_container; - - outputFc.seekp(tellCurPos); - } - - if (kVerbose) - { - kStdOut << "link: command header name: " << name << "\n"; - kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; - } - - outputFc << commandHdrsList[commandHeaderIndex]; - - for (size_t subCommandHeaderIndex = 0UL; - subCommandHeaderIndex < commandHdrsList.size(); - ++subCommandHeaderIndex) - { - if (subCommandHeaderIndex == commandHeaderIndex) - continue; - - if (std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) - { - if (kVerbose) - { - kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; - - if (commandHdr.Name == - std::string(commandHdrsList[commandHeaderIndex].Name)) - { - if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), - commandHdr.Name) == duplSymbols.cend()) - { - duplSymbols.emplace_back(commandHdr.Name); - } - - if (kVerbose) - kStdOut << "link: found duplicate symbol: " << commandHdr.Name - << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!duplSymbols.empty()) - { - for (auto& symbol : duplSymbols) - { - kStdOut << "link: multiple symbols of " << symbol << ".\n"; - } - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto byte : kObjectBytes) - { - outputFc << byte; - } - - if (kVerbose) - kStdOut << "link: wrote contents of: " << kOutput << "\n"; - - // step 3: check if we have those symbols - - std::vector unrefSyms; - - for (auto& commandHdr : commandHdrsList) - { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it != not_found.end()) - { - unrefSyms.emplace_back(commandHdr.Name); - } - } - - if (!unrefSyms.empty()) - { - for (auto& unreferenced_symbol : unrefSyms) - { - kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; - } - } - - if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || - !unrefSyms.empty()) - { - if (kVerbose) - kStdOut << "link: file: " << kOutput - << ", is corrupt, removing file...\n"; - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - return 0; -} - -// Last rev 13-1-24 diff --git a/Sources/link.cxx b/Sources/link.cxx new file mode 100644 index 0000000..e671d84 --- /dev/null +++ b/Sources/link.cxx @@ -0,0 +1,741 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// @file link.cxx +/// @author Amlal EL Mahrouss (amlel) +/// @brief ZKA Technologies Linker. + +/// Last Rev: Sat Feb 24 CET 2024 + +/// @note Do not look up for anything with .code64/.data64/.zero64! +/// It will be loaded when program will start up! + +#include + +//! Assembler Kit +#include + +//! Preferred Executable Format +#include +#include +#include +#include +#include + +//! Dist version +#include + +//! Advanced Executable Object Format +#include + +//! C++ I/O headers. +#include +#include + +#define kLinkerVersion "Zeta Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" + +#define StringCompare(DST, SRC) strcmp(DST, SRC) + +#define kPefNoCpu 0U +#define kPefNoSubCpu 0U + +#define kWhite "\e[0;97m" +#define kStdOut (std::cout << kWhite) + +#define kLinkerDefaultOrigin kPefBaseOrigin +#define kLinkerId 0x5046FF +#define kLinkerAbiContainer "Container:Abi:" + +enum +{ + eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ + eABINewOSKrnl = 0x5046, /* PF (NewOSKrnl) */ + eABIMTL = 0x4650, /* FP (MTL firmware) */ + eABIInvalid = 1, +}; + +static std::string kOutput; +static Int32 kAbi = eABINewOSKrnl; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = CompilerKit::kPefArchInvalid; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; +static Bool kVerbose = false; + +/* link is to be found, mld is to be found at runtime. */ +static const char* kLdDefineSymbol = ":UndefinedSymbol:"; +static const char* kLdDynamicSym = ":RuntimeSymbol:"; + +/* object code and list. */ +static std::vector kObjectList; +static std::vector kObjectBytes; + +#define kPrintF printf +#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) + +NDK_MODULE(NewOSLinker) +{ + bool is_executable = true; + + /** + * @brief parse flags and such. + * + */ + for (size_t i = 1; i < argc; ++i) + { + if (StringCompare(argv[i], "/help") == 0) + { + kLinkerSplash(); + kStdOut << "/version: Show linker version.\n"; + kStdOut << "/help: Show linker help.\n"; + kStdOut << "/verbose: Enable linker trace.\n"; + kStdOut << "/shared: Output as a shared PEF.\n"; + kStdOut << "/fat-bin: Output as a FAT PEF.\n"; + kStdOut << "/32x0: Output as a 32x0 PEF.\n"; + kStdOut << "/64x0: Output as a 64x0 PEF.\n"; + kStdOut << "/amd64: Output as a AMD64 PEF.\n"; + kStdOut << "/rv64: Output as a RISC-V PEF.\n"; + kStdOut << "/power64: Output as a POWER PEF.\n"; + kStdOut << "/arm64: Output as a ARM64 PEF.\n"; + kStdOut << "/output-file: Select the output file name.\n"; + + return 0; + } + else if (StringCompare(argv[i], "/version") == 0) + { + kLinkerSplash(); + return 0; + } + else if (StringCompare(argv[i], "/fat-bin") == 0) + { + kFatBinaryEnable = true; + + continue; + } + else if (StringCompare(argv[i], "/64x0") == 0) + { + kArch = CompilerKit::kPefArch64000; + + continue; + } + else if (StringCompare(argv[i], "/amd64") == 0) + { + kArch = CompilerKit::kPefArchAMD64; + + continue; + } + else if (StringCompare(argv[i], "/32x0") == 0) + { + kArch = CompilerKit::kPefArch32000; + + continue; + } + else if (StringCompare(argv[i], "/power64") == 0) + { + kArch = CompilerKit::kPefArchPowerPC; + + continue; + } + else if (StringCompare(argv[i], "/arm64") == 0) + { + kArch = CompilerKit::kPefArchARM64; + + continue; + } + else if (StringCompare(argv[i], "/verbose") == 0) + { + kVerbose = true; + + continue; + } + else if (StringCompare(argv[i], "/shared") == 0) + { + if (kOutput.empty()) + { + continue; + } + + if (kOutput.find(kPefExt) != std::string::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } + else if (StringCompare(argv[i], "/output-file") == 0) + { + kOutput = argv[i + 1]; + ++i; + + continue; + } + else + { + if (argv[i][0] == '/') + { + kStdOut << "link: unknown flag: " << argv[i] << "\n"; + return MPCC_EXEC_ERROR; + } + + kObjectList.emplace_back(argv[i]); + + continue; + } + } + + if (kOutput.empty()) + { + kStdOut << "link: no output filename set." << std::endl; + return MPCC_EXEC_ERROR; + } + + // sanity check. + if (kObjectList.empty()) + { + kStdOut << "link: no input files." << std::endl; + return MPCC_EXEC_ERROR; + } + else + { + namespace fs = std::filesystem; + + // check for existing files, if they don't throw an error. + for (auto& obj : kObjectList) + { + if (!fs::exists(obj)) + { + // if filesystem doesn't find file + // -> throw error. + kStdOut << "link: no such file: " << obj << std::endl; + return MPCC_EXEC_ERROR; + } + } + } + + // PEF expects a valid architecture when outputing a binary. + if (kArch == 0) + { + kStdOut << "link: no target architecture set, can't continue." << std::endl; + return MPCC_EXEC_ERROR; + } + + CompilerKit::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = CompilerKit::kPefKindExec; + pef_container.SubCpu = kSubArch; + pef_container.Linker = kLinkerId; // ZKA Technologies Linker + pef_container.Abi = kAbi; // Multi-Processor UX ABI + pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; + pef_container.Magic[1] = kPefMagic[1]; + pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; + pef_container.Magic[3] = kPefMagic[3]; + pef_container.Version = kPefVersion; + + // specify the start address, can be 0x10000 + pef_container.Start = kLinkerDefaultOrigin; + pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); + + std::ofstream outputFc(kOutput, std::ofstream::binary); + + if (outputFc.bad()) + { + if (kVerbose) + { + kStdOut << "link: error: " << strerror(errno) << "\n"; + } + + return MPCC_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector commandHdrsList; + CompilerKit::Utils::AEReadableProtocol readProto{}; + + for (const auto& i : kObjectList) + { + if (!std::filesystem::exists(i)) + continue; + + CompilerKit::AEHeader hdr{}; + + readProto.FP = std::ifstream(i, std::ifstream::binary); + readProto.FP >> hdr; + + auto ae_header = hdr; + + if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && + ae_header.fSize == sizeof(CompilerKit::AEHeader)) + { + if (ae_header.fArch != kArch) + { + if (kVerbose) + kStdOut << "link: info: is this a FAT binary? : "; + + if (!kFatBinaryEnable) + { + if (kVerbose) + kStdOut << "No.\n"; + + kStdOut << "link: error: object " << i + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + std::remove(kOutput.c_str()); + return MPCC_FAT_ERROR; + } + else + { + if (kVerbose) + { + kStdOut << "Yes.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= ae_header.fArch; + std::size_t cnt = ae_header.fCount; + + if (kVerbose) + kStdOut << "link: object header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = + new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); + + auto* ae_records = readProto.Read(raw_ae_records, cnt); + for (size_t ae_record_index = 0; ae_record_index < cnt; + ++ae_record_index) + { + CompilerKit::PEFCommandHeader command_header{0}; + size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; + + memcpy(command_header.Name, ae_records[ae_record_index].fName, + kPefNameLen); + + // check this header if it's any valid. + if (std::string(command_header.Name).find(".code64") == + std::string::npos && + std::string(command_header.Name).find(".data64") == + std::string::npos && + std::string(command_header.Name).find(".zero64") == + std::string::npos) + { + if (std::string(command_header.Name).find(kPefStart) == + std::string::npos && + *command_header.Name == 0) + { + if (std::string(command_header.Name).find(kLdDefineSymbol) != + std::string::npos) + { + goto ld_mark_header; + } + else + { + continue; + } + } + } + + if (std::string(command_header.Name).find(kPefStart) != + std::string::npos && + std::string(command_header.Name).find(".code64") != + std::string::npos) + { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offsetOfData; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = ae_header.fArch; + command_header.SubCpu = ae_header.fSubArch; + + if (kVerbose) + { + kStdOut << "link: object record: " + << ae_records[ae_record_index].fName << " was marked.\n"; + + kStdOut << "link: object record offset: " << command_header.Offset << "\n"; + } + + commandHdrsList.emplace_back(command_header); + } + + delete[] raw_ae_records; + + std::vector bytes; + bytes.resize(ae_header.fCodeSize); + + readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); + readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); + + for (auto& byte : bytes) + { + kObjectBytes.push_back(byte); + } + + readProto.FP.close(); + + continue; + } + + kStdOut << "link: not an object: " << i << std::endl; + std::remove(kOutput.c_str()); + + // don't continue, it is a fatal error. + return MPCC_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + outputFc << pef_container; + + if (kVerbose) + { + kStdOut << "link: wrote container header.\n"; + } + + outputFc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector not_found; + std::vector symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& commandHdr : commandHdrsList) + { + // check if this symbol needs to be resolved. + if (std::string(commandHdr.Name).find(kLdDefineSymbol) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; + + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it == not_found.end()) + { + not_found.emplace_back(commandHdr.Name); + } + } + + symbols.emplace_back(commandHdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); + ++not_found_idx) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdrsList[not_found_idx].Name)); + it != not_found.end()) + { + std::string symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) + continue; + + // erase the lookup prefix. + symbol_imp.erase( + 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != std::string::npos) + symbol_imp.erase(symbol_imp.find('$'), 1); + + // the reason we do is because, this may not match the symbol, and we need + // to look for other matching symbols. + for (auto& commandHdr : commandHdrsList) + { + if (std::string(commandHdr.Name).find(symbol_imp) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDefineSymbol) == + std::string::npos) + { + std::string undefined_symbol = commandHdr.Name; + auto result_of_sym = + undefined_symbol.substr(undefined_symbol.find(symbol_imp)); + + for (int i = 0; result_of_sym[i] != 0; ++i) + { + if (result_of_sym[i] != symbol_imp[i]) + goto ld_continue_search; + } + + not_found.erase(it); + + if (kVerbose) + kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) + { + if (kVerbose) + kStdOut + << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " + "against your compiler's runtime library.\n"; + + kStdOut << "link: undefined entrypoint " << kPefStart + << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + CompilerKit::PEFCommandHeader dateHeader{}; + + time_t timestamp = time(nullptr); + + std::string timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strcpy(dateHeader.Name, timeStampStr.c_str()); + + dateHeader.Flags = 0; + dateHeader.Kind = CompilerKit::kPefZero; + dateHeader.Offset = outputFc.tellp(); + dateHeader.Size = timeStampStr.size(); + + commandHdrsList.push_back(dateHeader); + + CompilerKit::PEFCommandHeader abiHeader{}; + + std::string abi = kLinkerAbiContainer; + + switch (kArch) + { + case CompilerKit::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case CompilerKit::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case CompilerKit::kPefArch32000: + case CompilerKit::kPefArch64000: { + abi += "MHRA"; + break; + } + default: { + abi += " IDK"; + break; + } + } + + memcpy(abiHeader.Name, abi.c_str(), abi.size()); + + abiHeader.Size = abi.size(); + abiHeader.Offset = outputFc.tellp(); + abiHeader.Flags = 0; + abiHeader.Kind = CompilerKit::kPefLinkerID; + + commandHdrsList.push_back(abiHeader); + + CompilerKit::PEFCommandHeader uuidHeader{}; + + std::random_device rd; + + auto seedData = std::array{}; + std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); + std::seed_seq seq(std::begin(seedData), std::end(seedData)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid id = gen(); + auto uuidStr = uuids::to_string(id); + + memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), + uuidStr.size()); + + uuidHeader.Size = 16; + uuidHeader.Offset = outputFc.tellp(); + uuidHeader.Flags = 0; + uuidHeader.Kind = CompilerKit::kPefZero; + + commandHdrsList.push_back(uuidHeader); + + // prepare a symbol vector. + std::vector undefSymbols; + std::vector duplSymbols; + std::vector resolveSymbols; + + constexpr Int32 cPaddingOffset = 16; + + size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; + commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) + { + if (std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + std::string symbolName = commandHdrsList[commandHeaderIndex].Name; + + if (!symbolName.empty()) + { + undefSymbols.emplace_back(symbolName); + } + + commandHdrsList[commandHeaderIndex].Offset += previousOffset; + previousOffset += commandHdrsList[commandHeaderIndex].Size; + + std::string name = commandHdrsList[commandHeaderIndex].Name; + + /// so this is valid when we get to the entrypoint. + /// it is always a code64 container. And should equal to kPefStart as well. + /// this chunk of code updates the pef_container.Start with the updated offset. + if (name.find(kPefStart) != std::string::npos && + name.find(".code64") != std::string::npos) + { + pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; + auto tellCurPos = outputFc.tellp(); + + outputFc.seekp(0); + outputFc << pef_container; + + outputFc.seekp(tellCurPos); + } + + if (kVerbose) + { + kStdOut << "link: command header name: " << name << "\n"; + kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; + } + + outputFc << commandHdrsList[commandHeaderIndex]; + + for (size_t subCommandHeaderIndex = 0UL; + subCommandHeaderIndex < commandHdrsList.size(); + ++subCommandHeaderIndex) + { + if (subCommandHeaderIndex == commandHeaderIndex) + continue; + + if (std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + { + kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; + + if (commandHdr.Name == + std::string(commandHdrsList[commandHeaderIndex].Name)) + { + if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), + commandHdr.Name) == duplSymbols.cend()) + { + duplSymbols.emplace_back(commandHdr.Name); + } + + if (kVerbose) + kStdOut << "link: found duplicate symbol: " << commandHdr.Name + << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!duplSymbols.empty()) + { + for (auto& symbol : duplSymbols) + { + kStdOut << "link: multiple symbols of " << symbol << ".\n"; + } + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + // step 2.5: write program bytes. + + for (auto byte : kObjectBytes) + { + outputFc << byte; + } + + if (kVerbose) + kStdOut << "link: wrote contents of: " << kOutput << "\n"; + + // step 3: check if we have those symbols + + std::vector unrefSyms; + + for (auto& commandHdr : commandHdrsList) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it != not_found.end()) + { + unrefSyms.emplace_back(commandHdr.Name); + } + } + + if (!unrefSyms.empty()) + { + for (auto& unreferenced_symbol : unrefSyms) + { + kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; + } + } + + if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || + !unrefSyms.empty()) + { + if (kVerbose) + kStdOut << "link: file: " << kOutput + << ", is corrupt, removing file...\n"; + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + return 0; +} + +// Last rev 13-1-24 diff --git a/Sources/power-cc.cc b/Sources/power-cc.cc deleted file mode 100644 index 332fa53..0000000 --- a/Sources/power-cc.cc +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kOk 0 - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cc -/// @brief POWER C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCT OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - file.erase(file.find(".pp"), 3); - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend -{ -public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char* text, const char* file); - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override - { - return "POWER C"; - } -}; - -static CompilerBackendCLang* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace detail -{ - union number_cast final { - public: - number_cast(UInt64 _Raw) - : _Raw(_Raw) - { - } - - public: - char _Num[8]; - UInt64 _Raw; - }; - - union double_cast final { - public: - double_cast(float _Raw) - : _Raw(_Raw) - { - } - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string& text, const char* file) -{ - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) - { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) - { - if (substr[y] == ' ') - { - while (match_type.find(' ') != std::string::npos) - { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) - { - if (clType.fName == match_type) - { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) - { - break; - } - - if (textBuffer.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) - { - if (textBuffer[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) - { - if (textBuffer[value_index] == ';') - break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("import") != std::string::npos) - value.erase(value.find("import"), strlen("import")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) - { - if (value.find(reg.fName) != std::string::npos) - { - found = true; - syntaxLeaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) - syntaxLeaf.fUserValue += "r0"; - } - - syntaxLeaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') - { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + - " \ndword export .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (textBuffer[text_index] == ';' && kInStruct) - continue; - - if (textBuffer.find("typedef ") != std::string::npos) - continue; - - if (textBuffer[text_index] == '=' && kInStruct) - { - detail::print_error( - "assignement of value inside a struct " + textBuffer, file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : textBuffer) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) - { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (textBuffer.find("*") != std::string::npos) - { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } - else - { - substr += "\tli "; - } - } - else if (textBuffer.find('=') != std::string::npos && !kInBraces) - { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') - { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - kCompilerVariables.push_back({.fName = substr}); - - if (textBuffer[text_index] == ';') - break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) - { - if (newSubstr[start] == ',') - break; - - if (newSubstr[start] == ' ') - continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntaxLeaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) - { - if (textBuffer[idx] == ',') - continue; - - if (textBuffer[idx] == ' ') - continue; - - if (textBuffer[idx] == ')') - break; - } - - for (char substr_first_index : textBuffer) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) - args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : textBuffer) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') - break; - - substr += _text_i; - } - - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - - syntaxLeaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') - { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) - { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') - { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) - kIfFound = false; - - if (kInStruct) - kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char* text, const char* file) -{ - std::string err_str; - std::string ln = text; - - if (ln.empty()) - { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (isalnum(ln[i])) - { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) - return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) - { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '\'') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } - else if (ln.find('"') != std::string::npos) - { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '"') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - else - { - break; - } - } - } - } - else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) - { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) - { - if (ln.find(forbidden) != std::string::npos) - { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final - { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, - {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, - {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, - {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, - {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, - {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, - {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, - {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, - {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, - {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) - { - if (ln.find(variable.fBegin) != std::string::npos) - { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') - ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == variable.fEnd[0]) - { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) - { - if (ln[index_keyword] == ' ') - { - continue; - } - - if (isdigit(ln[index_keyword])) - { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) - { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") - { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') - { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) - { - if (var.fValue.find(keyword) != std::string::npos) - { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) - { - if (fn.find(keyword[0]) != std::string::npos) - { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) - { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') - break; - - if (fn[where_begin] != keyword[keyword_begin]) - { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) - { - err_str.clear(); - goto cc_next; - } - else - { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) - return err_str; - - if (keyword.find(".") != std::string::npos) - return err_str; - - if (isalnum(keyword[0])) - err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (ParserKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyMountpointCLang::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerBackend->Compile(line_src, src.data()); - } - else - { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) - return -1; - - std::vector keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (ParserKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (ParserKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("import ") != std::string::npos) - { - std::string range = "import "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_MODULE(NewOSCompilerCLangPowerPC) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) - { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) - { - if (kState.fVerbose) - { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/power-cc.cxx b/Sources/power-cc.cxx new file mode 100644 index 0000000..41cb334 --- /dev/null +++ b/Sources/power-cc.cxx @@ -0,0 +1,1645 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kOk 0 + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief POWER C Compiler. + +///////////////////// + +/// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +/// INTERNAL STRUCT OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + file.erase(file.find(".pp"), 3); + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "POWER C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; +static std::vector kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) + value.erase(value.find(' '), 1); + + while (value.find("import") != std::string::npos) + value.erase(value.find("import"), strlen("import")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) + { + if (value.find(reg.fName) != std::string::npos) + { + found = true; + syntaxLeaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) + syntaxLeaf.fUserValue += "r0"; + } + + syntaxLeaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + + " \ndword export .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error( + "assignement of value inside a struct " + textBuffer, file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } + else + { + substr += "\tli "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + kCompilerVariables.push_back({.fName = substr}); + + if (textBuffer[text_index] == ';') + break; + + std::string reg = kAsmRegisterPrefix; + + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); + + auto newSubstr = substr.substr(substr.find(" ")); + + std::string symbol; + + for (size_t start = 0; start < newSubstr.size(); ++start) + { + if (newSubstr[start] == ',') + break; + + if (newSubstr[start] == ' ') + continue; + + symbol += (newSubstr[start]); + } + + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + + syntaxLeaf.fUserValue += + "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tli r31, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + + syntaxLeaf.fUserValue += "\n\tblr\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (ParserKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (ParserKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && + !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && + !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ld", "stw", "add", "sub", "or"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (ParserKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (ParserKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (ParserKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import ") != std::string::npos) + { + std::string range = "import "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), + range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLangPowerPC) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc deleted file mode 100644 index 5f015d5..0000000 --- a/Sources/ppcasm.cc +++ /dev/null @@ -1,976 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file ppcasm.cxx -/// @author Amlal EL Mahrouss -/// @brief POWER Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_PPC__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -constexpr auto cPowerIPAlignment = 0x4U; - -static CharType kOutputArch = CompilerKit::kPefArchPowerPC; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static bool kVerbose = false; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ ppcasm ] " << kWhite - << ((file == "ppcasm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ ppcasm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ ppcasm ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail - -/// Do not move it on top! it uses the assembler detail namespace! -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssemblerPowerPC) { - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '/') { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { - kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: " << kDistVersion << "\nppcasm: " - "Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version,/v: print program version.\n"; - kStdOut << "/verbose: print verbose output.\n"; - kStdOut << "/binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "/binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "/verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "ppcasm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "ppcasm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "ppcasm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "ppcasm"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "ppcasm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "ppcasm: At least one record is needed to write an object " - "file.\nppcasm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) - kStdOut << "ppcasm: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) - kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAEInvalidOpcode; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "ppcasm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "ppcasm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "ppcasm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; - - return MPCC_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the li - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "ppcasm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by ppcasm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "ppcasm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export")); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "li"}; - - // these don't. - std::vector filter_inst = {"blr", "bl", "sc"}; - - for (auto &opcodePPC : kOpcodesPowerPC) { - if (ParserKit::find_word(line, opcodePPC.name)) { - for (auto &op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = - std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); - it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcodePPC.name)) { - if (!isspace( - line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { - err_str += "\nMissing space between "; - err_str += opcodePPC.name; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "ppcasm: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "ppcasm: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "ppcasm: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "ppcasm: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export")) return true; - if (!detail::algorithm::is_valid(line)) return true; - - for (auto &opcodePPC : kOpcodesPowerPC) { - // strict check here - if (ParserKit::find_word(line, opcodePPC.name)) { - std::string name(opcodePPC.name); - std::string jump_label, cpy_jump_label; - std::vector found_registers_index; - - // check funct7 type. - switch (opcodePPC.ops->type) { - default: { - NumberCast32 num(opcodePPC.opcode); - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - break; - } - case BADDR: - case PCREL: { - auto num = GetNumber32(line, name); - - kBytes.emplace_back(num.number[0]); - kBytes.emplace_back(num.number[1]); - kBytes.emplace_back(num.number[2]); - kBytes.emplace_back(0x48); - - break; - } - /// General purpose, float, vector operations. Everything that involve - /// registers. - case G0REG: - case FREG: - case VREG: - case GREG: { - // \brief how many registers we found. - std::size_t found_some_count = 0UL; - std::size_t register_count = 0UL; - std::string opcodeName = opcodePPC.name; - std::size_t register_sum = 0; - - NumberCast64 num(opcodePPC.opcode); - - for (size_t line_index = 0UL; line_index < line.size(); - line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && - isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (isdigit(line[line_index + 3]) && - isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - detail::print_error( - "invalid register index, r" + reg_str + - "\nnote: The POWER accepts registers from r0 to r32.", - file); - throw std::runtime_error("invalid_register_index"); - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - detail::print_error("invalid register index, r" + reg_str, - file); - throw std::runtime_error("invalid_register_index"); - } - - if (opcodeName == "li") { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - auto num = GetNumber32(line, reg_str); - - kBytes.push_back(num.number[0]); - kBytes.push_back(num.number[1]); - kBytes.push_back(numIndex); - kBytes.push_back(0x38); - - // check if bigger than two. - for (size_t i = 2; i < 4; i++) { - if (num.number[i] > 0) { - detail::print_warning("number overflow on li operation.", - file); - break; - } - } - - break; - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - if (register_sum == 0) { - for (size_t indexReg = 0UL; indexReg < reg_index; - ++indexReg) { - register_sum += 0x20; - } - } else { - register_sum += reg_index; - } - } - - if (opcodeName == "mr") { - switch (register_count) { - case 0: { - kBytes.push_back(0x78); - - char numIndex = 0x3; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x8; - } - - kBytes.push_back(numIndex); - - break; - } - case 1: { - char numIndex = 0x1; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - for (size_t i = 0; i != reg_index; i++) { - kBytes[kBytes.size() - 1] += 0x8; - } - - kBytes[kBytes.size() - 1] -= 0x8; - - kBytes.push_back(numIndex); - - if (reg_index >= 10 && reg_index < 20) - kBytes.push_back(0x7d); - else if (reg_index >= 20 && reg_index < 30) - kBytes.push_back(0x7e); - else if (reg_index >= 30) - kBytes.push_back(0x7f); - else - kBytes.push_back(0x7c); - - break; - } - default: - break; - } - - ++register_count; - ++found_some_count; - } - - if (opcodeName == "addi") { - if (found_some_count == 2 || found_some_count == 0) - kBytes.emplace_back(reg_index); - else if (found_some_count == 1) - kBytes.emplace_back(0x00); - - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("cmp") != std::string::npos) { - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("mf") != std::string::npos || - opcodeName.find("mt") != std::string::npos) { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - num.number[2] += numIndex; - - ++found_some_count; - - if (found_some_count > 1) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - - if (kVerbose) { - kStdOut << "ppcasm: Found register: " << register_syntax - << "\n"; - kStdOut << "ppcasm: Amount of registers in instruction: " - << found_some_count << "\n"; - } - - if (reg_index >= 10 && reg_index < 20) - num.number[3] = 0x7d; - else if (reg_index >= 20 && reg_index < 30) - num.number[3] = 0x7e; - else if (reg_index >= 30) - num.number[3] = 0x7f; - else - num.number[3] = 0x7c; - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - } - - found_registers_index.push_back(reg_index); - } - } - - if (opcodeName == "addi") { - kBytes.emplace_back(0x38); - } - - if (opcodeName.find("cmp") != std::string::npos) { - char rightReg = 0x0; - - for (size_t i = 0; i != found_registers_index[1]; i++) { - rightReg += 0x08; - } - - kBytes.emplace_back(0x00); - kBytes.emplace_back(rightReg); - kBytes.emplace_back(found_registers_index[0]); - kBytes.emplace_back(0x7c); - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - size_t offset = 0UL; - - if (line.find('+') != std::string::npos) { - auto number = GetNumber32(line.substr(line.find("+")), "+"); - offset = number.raw; - } - - kBytes.push_back(offset); - kBytes.push_back(0x00); - kBytes.push_back(register_sum); - - kBytes.emplace_back(0x90); - } - - if (opcodeName == "mr") { - if (register_count == 1) { - detail::print_error("Too few registers. -> " + line, file); - throw std::runtime_error("too_few_registers"); - } - } - - // we're not in immediate addressing, reg to reg. - if (opcodePPC.ops->type != GREG) { - // remember! register to register! - if (found_some_count == 1) { - detail::print_error( - "Unrecognized register found.\ntip: each ppcasm register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/ppcasm.cxx b/Sources/ppcasm.cxx new file mode 100644 index 0000000..01e8124 --- /dev/null +++ b/Sources/ppcasm.cxx @@ -0,0 +1,976 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file ppcasm.cxx +/// @author Amlal EL Mahrouss +/// @brief POWER Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that li will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_PPC__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +constexpr auto cPowerIPAlignment = 0x4U; + +static CharType kOutputArch = CompilerKit::kPefArchPowerPC; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +static bool kVerbose = false; + +static std::vector kBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string &line); + +namespace detail { +void print_error(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << kRed << "[ ppcasm ] " << kWhite + << ((file == "ppcasm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ ppcasm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +void print_warning(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (!file.empty()) { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ ppcasm ] " << kWhite << reason << kBlank + << std::endl; +} +} // namespace detail + +/// Do not move it on top! it uses the assembler detail namespace! +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief POWER assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerPowerPC) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: " << kDistVersion << "\nppcasm: " + "Copyright (c) " + "ZKA Technologies.\n"; + return 0; + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version,/v: print program version.\n"; + kStdOut << "/verbose: print verbose output.\n"; + kStdOut << "/binary: output as flat binary.\n"; + + return 0; + } else if (strcmp(argv[i], "/binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "/verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "ppcasm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "ppcasm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto &ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "ppcasm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderPowerPC asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + detail::print_error(ln, argv[i]); + continue; + } + + try { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } catch (const std::exception &e) { + if (kVerbose) { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "ppcasm"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "ppcasm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) { + kStdErr << "ppcasm: At least one record is needed to write an object " + "file.\nppcasm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + std::size_t record_count = 0UL; + + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; + ++record_count; + + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "ppcasm: Wrote record " << record_hdr.fName << "...\n"; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto &sym : kUndefinedSymbols) { + CompilerKit::AERecordHeader undefined_sym{0}; + + if (kVerbose) + kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; + + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; + + ++record_count; + + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); + + file_ptr_out << undefined_sym; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "ppcasm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto &byte : kBytes) { + file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); + } + + if (kVerbose) kStdOut << "ppcasm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "ppcasm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; + + return MPCC_EXEC_ERROR; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string &line) { + // import is the opposite of export, it signals to the li + // that we need this symbol. + if (ParserKit::find_word(line, "import")) { + if (kOutputAsBinary) { + detail::print_error("Invalid import directive in flat binary mode.", + "ppcasm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) { + detail::print_error("Invalid import", "ppcasm"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char &j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by ppcasm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (ParserKit::find_word(line, "export")) { + if (kOutputAsBinary) { + detail::print_error("Invalid export directive in flat binary mode.", + "ppcasm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export")); + + std::string name_copy = name; + + for (char &j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm { +// \brief authorize a brief set of characters. +static inline bool is_not_alnum_space(char c) { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.')); +} + +bool is_valid(const std::string &str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, + const std::string &file) { + std::string err_str; + + if (line.empty() || ParserKit::find_word(line, "import") || + ParserKit::find_word(line, "export") || + line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + /// does the line contains valid input? + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) { + if (line.find(',') + 1 == line.size()) { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } else { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto &ch : substr) { + if (ch != ' ' && ch != '\t') { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + + // these do take an argument. + std::vector operands_inst = {"stw", "li"}; + + // these don't. + std::vector filter_inst = {"blr", "bl", "sc"}; + + for (auto &opcodePPC : kOpcodesPowerPC) { + if (ParserKit::find_word(line, opcodePPC.name)) { + for (auto &op : operands_inst) { + // if only the instruction was found. + if (line == op) { + err_str += "\nMalformed "; + err_str += op; + err_str += " instruction, here -> "; + err_str += line; + } + } + + // if it is like that -> addr1, 0x0 + if (auto it = + std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); + it == filter_inst.cend()) { + if (ParserKit::find_word(line, opcodePPC.name)) { + if (!isspace( + line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { + err_str += "\nMissing space between "; + err_str += opcodePPC.name; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; +} + +bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, + std::string &jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) { + if (errno != 0) { + detail::print_error("invalid hex number: " + jump_label, "ppcasm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "ppcasm: found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) { + if (errno != 0) { + detail::print_error("invalid binary number: " + jump_label, "ppcasm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "ppcasm: found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) { + if (errno != 0) { + detail::print_error("invalid octal number: " + jump_label, "ppcasm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "ppcasm: found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "ppcasm: found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, + const std::string &file) { + if (ParserKit::find_word(line, "export")) return true; + if (!detail::algorithm::is_valid(line)) return true; + + for (auto &opcodePPC : kOpcodesPowerPC) { + // strict check here + if (ParserKit::find_word(line, opcodePPC.name)) { + std::string name(opcodePPC.name); + std::string jump_label, cpy_jump_label; + std::vector found_registers_index; + + // check funct7 type. + switch (opcodePPC.ops->type) { + default: { + NumberCast32 num(opcodePPC.opcode); + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + break; + } + case BADDR: + case PCREL: { + auto num = GetNumber32(line, name); + + kBytes.emplace_back(num.number[0]); + kBytes.emplace_back(num.number[1]); + kBytes.emplace_back(num.number[2]); + kBytes.emplace_back(0x48); + + break; + } + /// General purpose, float, vector operations. Everything that involve + /// registers. + case G0REG: + case FREG: + case VREG: + case GREG: { + // \brief how many registers we found. + std::size_t found_some_count = 0UL; + std::size_t register_count = 0UL; + std::string opcodeName = opcodePPC.name; + std::size_t register_sum = 0; + + NumberCast64 num(opcodePPC.opcode); + + for (size_t line_index = 0UL; line_index < line.size(); + line_index++) { + if (line[line_index] == kAsmRegisterPrefix[0] && + isdigit(line[line_index + 1])) { + std::string register_syntax = kAsmRegisterPrefix; + register_syntax += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + register_syntax += line[line_index + 2]; + + std::string reg_str; + reg_str += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + reg_str += line[line_index + 2]; + + // it ranges from r0 to r19 + // something like r190 doesn't exist in the instruction set. + if (isdigit(line[line_index + 3]) && + isdigit(line[line_index + 2])) { + reg_str += line[line_index + 3]; + detail::print_error( + "invalid register index, r" + reg_str + + "\nnote: The POWER accepts registers from r0 to r32.", + file); + throw std::runtime_error("invalid_register_index"); + } + + // finally cast to a size_t + std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + + if (reg_index > kAsmRegisterLimit) { + detail::print_error("invalid register index, r" + reg_str, + file); + throw std::runtime_error("invalid_register_index"); + } + + if (opcodeName == "li") { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + auto num = GetNumber32(line, reg_str); + + kBytes.push_back(num.number[0]); + kBytes.push_back(num.number[1]); + kBytes.push_back(numIndex); + kBytes.push_back(0x38); + + // check if bigger than two. + for (size_t i = 2; i < 4; i++) { + if (num.number[i] > 0) { + detail::print_warning("number overflow on li operation.", + file); + break; + } + } + + break; + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + if (register_sum == 0) { + for (size_t indexReg = 0UL; indexReg < reg_index; + ++indexReg) { + register_sum += 0x20; + } + } else { + register_sum += reg_index; + } + } + + if (opcodeName == "mr") { + switch (register_count) { + case 0: { + kBytes.push_back(0x78); + + char numIndex = 0x3; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x8; + } + + kBytes.push_back(numIndex); + + break; + } + case 1: { + char numIndex = 0x1; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + for (size_t i = 0; i != reg_index; i++) { + kBytes[kBytes.size() - 1] += 0x8; + } + + kBytes[kBytes.size() - 1] -= 0x8; + + kBytes.push_back(numIndex); + + if (reg_index >= 10 && reg_index < 20) + kBytes.push_back(0x7d); + else if (reg_index >= 20 && reg_index < 30) + kBytes.push_back(0x7e); + else if (reg_index >= 30) + kBytes.push_back(0x7f); + else + kBytes.push_back(0x7c); + + break; + } + default: + break; + } + + ++register_count; + ++found_some_count; + } + + if (opcodeName == "addi") { + if (found_some_count == 2 || found_some_count == 0) + kBytes.emplace_back(reg_index); + else if (found_some_count == 1) + kBytes.emplace_back(0x00); + + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("cmp") != std::string::npos) { + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("mf") != std::string::npos || + opcodeName.find("mt") != std::string::npos) { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + num.number[2] += numIndex; + + ++found_some_count; + + if (found_some_count > 1) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + + if (kVerbose) { + kStdOut << "ppcasm: Found register: " << register_syntax + << "\n"; + kStdOut << "ppcasm: Amount of registers in instruction: " + << found_some_count << "\n"; + } + + if (reg_index >= 10 && reg_index < 20) + num.number[3] = 0x7d; + else if (reg_index >= 20 && reg_index < 30) + num.number[3] = 0x7e; + else if (reg_index >= 30) + num.number[3] = 0x7f; + else + num.number[3] = 0x7c; + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + } + + found_registers_index.push_back(reg_index); + } + } + + if (opcodeName == "addi") { + kBytes.emplace_back(0x38); + } + + if (opcodeName.find("cmp") != std::string::npos) { + char rightReg = 0x0; + + for (size_t i = 0; i != found_registers_index[1]; i++) { + rightReg += 0x08; + } + + kBytes.emplace_back(0x00); + kBytes.emplace_back(rightReg); + kBytes.emplace_back(found_registers_index[0]); + kBytes.emplace_back(0x7c); + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + size_t offset = 0UL; + + if (line.find('+') != std::string::npos) { + auto number = GetNumber32(line.substr(line.find("+")), "+"); + offset = number.raw; + } + + kBytes.push_back(offset); + kBytes.push_back(0x00); + kBytes.push_back(register_sum); + + kBytes.emplace_back(0x90); + } + + if (opcodeName == "mr") { + if (register_count == 1) { + detail::print_error("Too few registers. -> " + line, file); + throw std::runtime_error("too_few_registers"); + } + } + + // we're not in immediate addressing, reg to reg. + if (opcodePPC.ops->type != GREG) { + // remember! register to register! + if (found_some_count == 1) { + detail::print_error( + "Unrecognized register found.\ntip: each ppcasm register " + "starts with 'r'.\nline: " + + line, + file); + + throw std::runtime_error("not_a_register"); + } + } + + if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } + + break; + } + } + + kOrigin += cPowerIPAlignment; + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/codetools.files b/codetools.files index 211a290..d895485 100644 --- a/codetools.files +++ b/codetools.files @@ -1,29 +1,29 @@ .clang-format -Comm/AsmKit/AsmKit.hpp -Comm/AsmKit/CPU/32x0.hpp -Comm/AsmKit/CPU/64x0.hpp -Comm/AsmKit/CPU/amd64.hpp -Comm/AsmKit/CPU/arm64.hpp -Comm/AsmKit/CPU/ppc.hpp -Comm/CompilerKit.hpp -Comm/Defines.hpp -Comm/ParserKit.hpp -Comm/Public/SDK/CRT/__mpcc_alloca.hxx -Comm/Public/SDK/CRT/__mpcc_defines.hxx -Comm/Public/SDK/CRT/__mpcc_exception.hxx -Comm/Public/SDK/CRT/__mpcc_hint.hxx -Comm/Public/SDK/CRT/__mpcc_malloc.hxx -Comm/Public/SDK/CRT/__mpcc_power.inc -Comm/StdKit/AE.hpp -Comm/StdKit/ELF.hpp -Comm/StdKit/ErrorID.hpp -Comm/StdKit/ErrorOr.hpp -Comm/StdKit/PEF.hpp -Comm/StdKit/Ref.hpp -Comm/StdKit/String.hpp -Comm/StdKit/XCOFF.hxx -Comm/UUID.hpp -Comm/Version.hxx +Headers/AsmKit/AsmKit.hpp +Headers/AsmKit/CPU/32x0.hpp +Headers/AsmKit/CPU/64x0.hpp +Headers/AsmKit/CPU/amd64.hpp +Headers/AsmKit/CPU/arm64.hpp +Headers/AsmKit/CPU/ppc.hpp +Headers/Macros.hpp +Headers/Defines.hpp +Headers/ParserKit.hpp +Headers/Public/SDK/CRT/__mpcc_alloca.hxx +Headers/Public/SDK/CRT/__mpcc_defines.hxx +Headers/Public/SDK/CRT/__mpcc_exception.hxx +Headers/Public/SDK/CRT/__mpcc_hint.hxx +Headers/Public/SDK/CRT/__mpcc_malloc.hxx +Headers/Public/SDK/CRT/__mpcc_power.inc +Headers/StdKit/AE.hpp +Headers/StdKit/ELF.hpp +Headers/StdKit/ErrorID.hpp +Headers/StdKit/ErrorOr.hpp +Headers/StdKit/PEF.hpp +Headers/StdKit/Ref.hpp +Headers/StdKit/String.hpp +Headers/StdKit/XCOFF.hxx +Headers/UUID.hpp +Headers/Version.hxx Doc/asm-specs.txt Doc/havp.txt Doc/notice.txt @@ -33,29 +33,29 @@ Examples/Example64k.s Examples/ExampleAMD64.asm Examples/ExampleAMD64_Return.asm Examples/ExampleCDialect.S -Examples/ExampleCDialect.cc +Examples/ExampleCDialect.cxx Examples/ExampleCPlusPlus.cxx Examples/ExampleCPlusPlus.s Examples/ExamplePowerPC.S MailMap ReadMe.md -Sources/32asm.cc -Sources/64asm.cc -Sources/64x0-cc.cc -Sources/AssemblyFactory.cc +Sources/32asm.cxx +Sources/64asm.cxx +Sources/64x0-cc.cxx +Sources/AssemblyFactory.cxx Sources/Detail/ReadMe.md Sources/Detail/asmutils.hxx Sources/Detail/compilerutils.hxx -Sources/String.cc -Sources/bpp.cc -Sources/coff2ae.cc +Sources/String.cxx +Sources/bpp.cxx +Sources/coff2ae.cxx Sources/compile_flags.txt -Sources/cplusplus.cc -Sources/elf2ae.cc -Sources/i64asm.cc -Sources/link.cc -Sources/power-cc.cc -Sources/ppcasm.cc +Sources/cplusplus.cxx +Sources/elf2ae.cxx +Sources/i64asm.cxx +Sources/link.cxx +Sources/power-cc.cxx +Sources/ppcasm.cxx posix.make run_format.sh win64.make diff --git a/codetools.includes b/codetools.includes index a9a0fb5..cb0237d 100644 --- a/codetools.includes +++ b/codetools.includes @@ -1,2 +1,2 @@ -./Comm +./Headers ./ diff --git a/posix.make b/posix.make index 8a17a58..9a11054 100644 --- a/posix.make +++ b/posix.make @@ -7,42 +7,42 @@ # ======================================================== # -COMMON_INC=-I./Comm -I./ -I./Sources/Detail +COMMON_INC=-I./Headers -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 -LINK_SRC=Sources/link.cc +LINK_SRC=Sources/link.cxx LINK_OUTPUT=Output/link LINK_ALT_OUTPUT=Output/64link LINK_ALT_3_OUTPUT=Output/i64link LINK_ALT_2_OUTPUT=Output/32link LINK_ALT_4_OUTPUT=Output/ppclink -PP_SRC=Sources/bpp.cc +PP_SRC=Sources/bpp.cxx PP_OUTPUT=Output/bpp -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc +SRC_COMMON=Sources/String.cxx Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) +AMD64_CXX_SRC=Sources/cplusplus.cxx $(SRC_COMMON) AMD64_CXX_OUTPUT=Output/cplusplus # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cc $(SRC_COMMON) +64X0_CC_SRC=Sources/64x0-cc.cxx $(SRC_COMMON) 64X0_CC_OUTPUT=Output/64x0-cc # C Compiler (Our own RISC) -PPC_CC_SRC=Sources/power-cc.cc $(SRC_COMMON) +PPC_CC_SRC=Sources/power-cc.cxx $(SRC_COMMON) PPC_CC_OUTPUT=Output/power-cc # 64x0 Assembler (Our Own RISC) -ASM_SRC=Sources/64asm.cc $(SRC_COMMON) +ASM_SRC=Sources/64asm.cxx $(SRC_COMMON) ASM_OUTPUT=Output/64asm # AMD64 Assembler (Intel CISC) -IASM_SRC=Sources/i64asm.cc $(SRC_COMMON) +IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm # Power4 Assembler (IBM RISC) -PPCASM_SRC=Sources/ppcasm.cc $(SRC_COMMON) +PPCASM_SRC=Sources/ppcasm.cxx $(SRC_COMMON) PPCASM_OUTPUT=Output/ppcasm .PHONY: all diff --git a/win64.make b/win64.make index 37d762a..70d9381 100644 --- a/win64.make +++ b/win64.make @@ -7,41 +7,41 @@ # ======================================================== # -COMMON_INC=-I./Comm -I./ -I./Sources/Detail +COMMON_INC=-I./Headers -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 -Xlinker -s -LINK_SRC=Sources/link.cc +LINK_SRC=Sources/link.cxx LINK_OUTPUT=Output/link.exe LINK_ALT_OUTPUT=Output/64link.exe LINK_ALT_3_OUTPUT=Output/i64link.exe LINK_ALT_2_OUTPUT=Output/32link.exe -PP_SRC=Sources/bpp.cc +PP_SRC=Sources/bpp.cxx PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cc Sources/AssemblyFactory.cc +SRC_COMMON=Sources/String.cxx Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/cplusplus.cc $(SRC_COMMON) +AMD64_CXX_SRC=Sources/cplusplus.cxx $(SRC_COMMON) AMD64_CXX_OUTPUT=Output/cplusplus.exe # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cc $(SRC_COMMON) +64X0_CC_SRC=Sources/64x0-cc.cxx $(SRC_COMMON) 64X0_CC_OUTPUT=Output/64x0-cc.exe # C Compiler -PPC_CC_SRC=Sources/power-cc.cc $(SRC_COMMON) +PPC_CC_SRC=Sources/power-cc.cxx $(SRC_COMMON) PPC_CC_OUTPUT=Output/power-cc.exe # 64x0 Assembler -ASM_SRC=Sources/64asm.cc $(SRC_COMMON) +ASM_SRC=Sources/64asm.cxx $(SRC_COMMON) ASM_OUTPUT=Output/64asm.exe # AMD64 Assembler -IASM_SRC=Sources/i64asm.cc $(SRC_COMMON) +IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm.exe # POWER Assembler -PPCASM_SRC=Sources/ppcasm.cc $(SRC_COMMON) +PPCASM_SRC=Sources/ppcasm.cxx $(SRC_COMMON) PPCASM_OUTPUT=Output/ppcasm.exe .PHONY: all -- cgit v1.2.3 From 13b84ff69d821029da3c2318a35a294d8045d7f9 Mon Sep 17 00:00:00 2001 From: Amlal Date: Wed, 17 Jul 2024 18:39:40 +0200 Subject: [IMP] NDK instead of MPCC. Signed-off-by: Amlal --- Examples/ExampleCDialect.S | 2 +- Examples/ExampleCPlusPlus.s | 4 ++-- Headers/Public/SDK/CRT/__mpcc_exception.hxx | 4 ++-- Headers/Public/SDK/CRT/__mpcc_power.inc | 2 +- Headers/StdKit/AE.hpp | 2 +- Sources/cplusplus.cxx | 2 +- posix.make | 2 +- win64.make | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) (limited to 'Sources') diff --git a/Examples/ExampleCDialect.S b/Examples/ExampleCDialect.S index 1eb2f82..c657cbb 100644 --- a/Examples/ExampleCDialect.S +++ b/Examples/ExampleCDialect.S @@ -1,5 +1,5 @@ ; Path: Examples/ExampleCDialect.cxx -; Language: MPCC assembly. (Generated from C++) +; Language: NDK assembly. (Generated from C++) ; Date: 2024-5-14 #bits 64 diff --git a/Examples/ExampleCPlusPlus.s b/Examples/ExampleCPlusPlus.s index 0414858..7522eca 100644 --- a/Examples/ExampleCPlusPlus.s +++ b/Examples/ExampleCPlusPlus.s @@ -1,5 +1,5 @@ ; Path: Examples/ExampleCPlusPlus.cxx -; Language: MPCC assembly. (Generated from C++) +; Language: NDK assembly. (Generated from C++) ; Date: 2024-5-14 #bits 64 @@ -15,5 +15,5 @@ mov r10, r8 mov r11, 0 mov r12, 0 -mov rax, 0 +mov rax, 0 ret diff --git a/Headers/Public/SDK/CRT/__mpcc_exception.hxx b/Headers/Public/SDK/CRT/__mpcc_exception.hxx index 4a9f84a..dac42ad 100644 --- a/Headers/Public/SDK/CRT/__mpcc_exception.hxx +++ b/Headers/Public/SDK/CRT/__mpcc_exception.hxx @@ -16,12 +16,12 @@ namespace std { inline void __throw_general(void) { - throw std::runtime_error("MPCC C++ Runtime error."); + throw std::runtime_error("NDK C++ Runtime error."); } inline void __throw_domain_error(const char* error) { - std::cout << "MPCC C++: Domain error: " << error << "\r"; + std::cout << "NDK C++: Domain error: " << error << "\r"; __throw_general(); } } // namespace std diff --git a/Headers/Public/SDK/CRT/__mpcc_power.inc b/Headers/Public/SDK/CRT/__mpcc_power.inc index 9e4928c..90b1364 100644 --- a/Headers/Public/SDK/CRT/__mpcc_power.inc +++ b/Headers/Public/SDK/CRT/__mpcc_power.inc @@ -1,5 +1,5 @@ # Path: SDK/__mpcc_power.inc -# Language: MPCC POWER Assembly support for GNU. +# Language: NDK POWER Assembly support for GNU. # Build Date: 2024-6-4 %ifdef __CODETOOLS__ diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp index baa4249..cf64516 100644 --- a/Headers/StdKit/AE.hpp +++ b/Headers/StdKit/AE.hpp @@ -1,7 +1,7 @@ /* * ======================================================== * - * MPCC + * NDK * Copyright ZKA Technologies, all rights reserved. * * ======================================================== diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index 3eb6e9b..e1044b9 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -669,7 +669,7 @@ public: if (dest.empty()) { - dest = "CXX-MPCC-"; + dest = "CXX-NDK-"; std::random_device rd; auto seed_data = std::array {}; diff --git a/posix.make b/posix.make index 9a11054..0b44aed 100644 --- a/posix.make +++ b/posix.make @@ -1,7 +1,7 @@ # # ======================================================== # - # MPCC + # NDK # Copyright ZKA Technologies, all rights reserved. # # ======================================================== diff --git a/win64.make b/win64.make index 70d9381..ff73f42 100644 --- a/win64.make +++ b/win64.make @@ -1,7 +1,7 @@ # # ======================================================== # - # MPCC + # NDK # Copyright ZKA Technologies, all rights reserved. # # ======================================================== -- cgit v1.2.3 From af93068ec107e8d8f5873399e86e4001cb1c6b40 Mon Sep 17 00:00:00 2001 From: Amlal Date: Sun, 21 Jul 2024 09:47:44 +0200 Subject: [RM] Examples/ added to gitignore, improved Ref class. Signed-off-by: Amlal --- .gitignore | 2 ++ Examples/Example64k.s | 3 -- Examples/ExampleAMD64.asm | 6 ---- Examples/ExampleAMD64_Return.asm | 6 ---- Examples/ExampleCDialect.S | 14 --------- Examples/ExampleCDialect.cc | 7 ----- Examples/ExampleCPlusPlus.cxx | 12 -------- Examples/ExampleCPlusPlus.s | 19 ------------- Examples/ExamplePowerPC.S | 8 ------ Examples/ExamplePowerPC.S.pp | 11 -------- Examples/ExamplePowerPC.dmp | 5 ---- Headers/StdKit/Ref.hpp | 26 ++++++++++------- Sources/cplusplus.cxx | 9 +++--- codetools.10x | 48 ------------------------------- codetools.cflags | 1 - codetools.config | 2 -- codetools.creator | 1 - codetools.cxxflags | 1 - codetools.files | 61 ---------------------------------------- codetools.includes | 2 -- 20 files changed, 23 insertions(+), 221 deletions(-) delete mode 100644 Examples/Example64k.s delete mode 100644 Examples/ExampleAMD64.asm delete mode 100644 Examples/ExampleAMD64_Return.asm delete mode 100644 Examples/ExampleCDialect.S delete mode 100644 Examples/ExampleCDialect.cc delete mode 100644 Examples/ExampleCPlusPlus.cxx delete mode 100644 Examples/ExampleCPlusPlus.s delete mode 100644 Examples/ExamplePowerPC.S delete mode 100644 Examples/ExamplePowerPC.S.pp delete mode 100644 Examples/ExamplePowerPC.dmp delete mode 100644 codetools.10x delete mode 100644 codetools.cflags delete mode 100644 codetools.config delete mode 100644 codetools.creator delete mode 100644 codetools.cxxflags delete mode 100644 codetools.files delete mode 100644 codetools.includes (limited to 'Sources') diff --git a/.gitignore b/.gitignore index a181dc3..22939a1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ local.properties *.creator.user +Examples/ + # NewOS/MP-UX executable *.exec *.bin diff --git a/Examples/Example64k.s b/Examples/Example64k.s deleted file mode 100644 index b56003a..0000000 --- a/Examples/Example64k.s +++ /dev/null @@ -1,3 +0,0 @@ -mv r0, r3 -lda r19, 0x10000 -jlr diff --git a/Examples/ExampleAMD64.asm b/Examples/ExampleAMD64.asm deleted file mode 100644 index 781934c..0000000 --- a/Examples/ExampleAMD64.asm +++ /dev/null @@ -1,6 +0,0 @@ -#bits 64 - -export .code64 __ImageStart - -mov rax, 17 -ret diff --git a/Examples/ExampleAMD64_Return.asm b/Examples/ExampleAMD64_Return.asm deleted file mode 100644 index 0ecbaf7..0000000 --- a/Examples/ExampleAMD64_Return.asm +++ /dev/null @@ -1,6 +0,0 @@ -#bits 64 - -export .code64 __RaiseInterrupt - -int 13 -ret diff --git a/Examples/ExampleCDialect.S b/Examples/ExampleCDialect.S deleted file mode 100644 index c657cbb..0000000 --- a/Examples/ExampleCDialect.S +++ /dev/null @@ -1,14 +0,0 @@ -; Path: Examples/ExampleCDialect.cxx -; Language: NDK assembly. (Generated from C++) -; Date: 2024-5-14 - -#bits 64 - -#org 0x1000000 - -export .code64 __MPCC_int___ImageStart -mov r8, 0 - -mov r9, 36 -mov rax, r8 -ret diff --git a/Examples/ExampleCDialect.cc b/Examples/ExampleCDialect.cc deleted file mode 100644 index b55dd5f..0000000 --- a/Examples/ExampleCDialect.cc +++ /dev/null @@ -1,7 +0,0 @@ -int __ImageStart(int argc, char const* argv[]) -{ - int *foo; - *foo = 36; - - return *foo; -} diff --git a/Examples/ExampleCPlusPlus.cxx b/Examples/ExampleCPlusPlus.cxx deleted file mode 100644 index 3335e1e..0000000 --- a/Examples/ExampleCPlusPlus.cxx +++ /dev/null @@ -1,12 +0,0 @@ -int main(int argc, char const* argv[]) -{ - { - bool bar = false; - bar = 1; - - bool bar2 = bar; - bar2 = false; - } - - return 0; -} diff --git a/Examples/ExampleCPlusPlus.s b/Examples/ExampleCPlusPlus.s deleted file mode 100644 index 7522eca..0000000 --- a/Examples/ExampleCPlusPlus.s +++ /dev/null @@ -1,19 +0,0 @@ -; Path: Examples/ExampleCPlusPlus.cxx -; Language: NDK assembly. (Generated from C++) -; Date: 2024-5-14 - -#bits 64 - -#org 0x1000000 - -export .code64 __MPCC_int_main -mov r8, 0 -mov r9, 0 - -mov r10, 1 -mov r10, r8 -mov r11, 0 - -mov r12, 0 -mov rax, 0 -ret diff --git a/Examples/ExamplePowerPC.S b/Examples/ExamplePowerPC.S deleted file mode 100644 index b9de796..0000000 --- a/Examples/ExamplePowerPC.S +++ /dev/null @@ -1,8 +0,0 @@ -; you you can never say! - -b 0x1000 -mflr r21 -mtlr r21 -li r3, 0 -cmpw r10, r11 -stw r7, r5+36 diff --git a/Examples/ExamplePowerPC.S.pp b/Examples/ExamplePowerPC.S.pp deleted file mode 100644 index 5eeb07f..0000000 --- a/Examples/ExamplePowerPC.S.pp +++ /dev/null @@ -1,11 +0,0 @@ -# Path: Examples/ExamplePowerPC.S.pp -# Language: POWER Assembly -# Build Date: 2024-6-4 - -bl 0x1000 - - -li r1, 0x500 -mr r2, r1 -sc -blr diff --git a/Examples/ExamplePowerPC.dmp b/Examples/ExamplePowerPC.dmp deleted file mode 100644 index 5986d03..0000000 --- a/Examples/ExamplePowerPC.dmp +++ /dev/null @@ -1,5 +0,0 @@ -0x0000000000000000: 00 10 00 48 b 0x1000 -0x0000000000000004: 00 05 20 38 li r1, 0x500 -0x0000000000000008: 78 13 21 7C or r1, r1, r2 -0x000000000000000c: 02 00 00 44 sc -0x0000000000000010: 20 00 80 4E blr \ No newline at end of file diff --git a/Headers/StdKit/Ref.hpp b/Headers/StdKit/Ref.hpp index e655ccb..0f9c0e3 100644 --- a/Headers/StdKit/Ref.hpp +++ b/Headers/StdKit/Ref.hpp @@ -12,18 +12,25 @@ namespace CompilerKit { - // @author ZKA Technologies - // @brief Reference class, refers to a pointer of data in static memory. + // @author Amlal + // @brief Reference holder class, refers to a pointer of data in static memory. template class Ref final { public: explicit Ref() = default; - ~Ref() = default; + + ~Ref() + { + if (m_Strong) + { + (*m_Class).~T(); + } + } public: explicit Ref(T cls, const bool& strong = false) - : m_Class(cls), m_Strong(strong) + : m_Class(&cls), m_Strong(strong) { } @@ -41,12 +48,12 @@ namespace CompilerKit T& Leak() { - return m_Class; + return *m_Class; } T operator*() { - return m_Class; + return *m_Class; } bool IsStrong() const @@ -56,11 +63,11 @@ namespace CompilerKit operator bool() { - return m_Class; + return *m_Class; } private: - T m_Class; + T* m_Class; bool m_Strong{false}; }; @@ -68,8 +75,7 @@ namespace CompilerKit class NonNullRef final { public: - NonNullRef() = delete; - NonNullRef(nullPtr) = delete; + explicit NonNullRef() = delete; explicit NonNullRef(T* ref) : m_Ref(ref, true) diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index e1044b9..5b5b8bc 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -9,10 +9,13 @@ /// bugs: 0 +#include "StdKit/Ref.hpp" #define __PK_USE_STRUCT_INSTEAD__ 1 #define kPrintF printf +#define kOk (0) + #define kSplashCxx() \ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") @@ -20,8 +23,8 @@ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all #include #include -#include #include +#include #include #include #include @@ -30,10 +33,8 @@ kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all #include #include -#define kOk 0 - /* ZKA Technologies C++ driver */ -/* This is part of ZECC C++ compiler. */ +/* This is part of NDK. */ /* (c) ZKA Technologies */ /// @author Amlal El Mahrouss (amlel) diff --git a/codetools.10x b/codetools.10x deleted file mode 100644 index 2961860..0000000 --- a/codetools.10x +++ /dev/null @@ -1,48 +0,0 @@ - - - - *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, - - true - true - true - false - false - false - - - - - - - - - - - - - false - - Debug - Release - - - x64 - Win32 - - - C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\include - C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.40.33807\ATLMFC\include - C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include - C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt - C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt - C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um - - - - - - diff --git a/codetools.cflags b/codetools.cflags deleted file mode 100644 index 68d5165..0000000 --- a/codetools.cflags +++ /dev/null @@ -1 +0,0 @@ --std=c17 \ No newline at end of file diff --git a/codetools.config b/codetools.config deleted file mode 100644 index e0284f4..0000000 --- a/codetools.config +++ /dev/null @@ -1,2 +0,0 @@ -// Add predefined macros for your project here. For example: -// #define THE_ANSWER 42 diff --git a/codetools.creator b/codetools.creator deleted file mode 100644 index e94cbbd..0000000 --- a/codetools.creator +++ /dev/null @@ -1 +0,0 @@ -[General] diff --git a/codetools.cxxflags b/codetools.cxxflags deleted file mode 100644 index e23b2ae..0000000 --- a/codetools.cxxflags +++ /dev/null @@ -1 +0,0 @@ --std=c++20 diff --git a/codetools.files b/codetools.files deleted file mode 100644 index d895485..0000000 --- a/codetools.files +++ /dev/null @@ -1,61 +0,0 @@ -.clang-format -Headers/AsmKit/AsmKit.hpp -Headers/AsmKit/CPU/32x0.hpp -Headers/AsmKit/CPU/64x0.hpp -Headers/AsmKit/CPU/amd64.hpp -Headers/AsmKit/CPU/arm64.hpp -Headers/AsmKit/CPU/ppc.hpp -Headers/Macros.hpp -Headers/Defines.hpp -Headers/ParserKit.hpp -Headers/Public/SDK/CRT/__mpcc_alloca.hxx -Headers/Public/SDK/CRT/__mpcc_defines.hxx -Headers/Public/SDK/CRT/__mpcc_exception.hxx -Headers/Public/SDK/CRT/__mpcc_hint.hxx -Headers/Public/SDK/CRT/__mpcc_malloc.hxx -Headers/Public/SDK/CRT/__mpcc_power.inc -Headers/StdKit/AE.hpp -Headers/StdKit/ELF.hpp -Headers/StdKit/ErrorID.hpp -Headers/StdKit/ErrorOr.hpp -Headers/StdKit/PEF.hpp -Headers/StdKit/Ref.hpp -Headers/StdKit/String.hpp -Headers/StdKit/XCOFF.hxx -Headers/UUID.hpp -Headers/Version.hxx -Doc/asm-specs.txt -Doc/havp.txt -Doc/notice.txt -Doc/vnrp.txt -Doxyfile -Examples/Example64k.s -Examples/ExampleAMD64.asm -Examples/ExampleAMD64_Return.asm -Examples/ExampleCDialect.S -Examples/ExampleCDialect.cxx -Examples/ExampleCPlusPlus.cxx -Examples/ExampleCPlusPlus.s -Examples/ExamplePowerPC.S -MailMap -ReadMe.md -Sources/32asm.cxx -Sources/64asm.cxx -Sources/64x0-cc.cxx -Sources/AssemblyFactory.cxx -Sources/Detail/ReadMe.md -Sources/Detail/asmutils.hxx -Sources/Detail/compilerutils.hxx -Sources/String.cxx -Sources/bpp.cxx -Sources/coff2ae.cxx -Sources/compile_flags.txt -Sources/cplusplus.cxx -Sources/elf2ae.cxx -Sources/i64asm.cxx -Sources/link.cxx -Sources/power-cc.cxx -Sources/ppcasm.cxx -posix.make -run_format.sh -win64.make diff --git a/codetools.includes b/codetools.includes deleted file mode 100644 index cb0237d..0000000 --- a/codetools.includes +++ /dev/null @@ -1,2 +0,0 @@ -./Headers -./ -- cgit v1.2.3 From 5b8e70727d085baeb099979762a336eb30ff41ab Mon Sep 17 00:00:00 2001 From: Amlal Date: Sun, 21 Jul 2024 16:26:05 +0200 Subject: [IMP] Focusing on hand-written parser for C/C++ Signed-off-by: Amlal --- Sources/64x0-cc.cxx | 2 +- Sources/bpp.cxx | 2 +- Sources/cplusplus.cxx | 117 ++++++++++++++++++++++++++++++++++++++++---------- Sources/link.cxx | 18 ++++---- 4 files changed, 106 insertions(+), 33 deletions(-) (limited to 'Sources') diff --git a/Sources/64x0-cc.cxx b/Sources/64x0-cc.cxx index 47abfb5..28667d8 100644 --- a/Sources/64x0-cc.cxx +++ b/Sources/64x0-cc.cxx @@ -1513,7 +1513,7 @@ public: #define kPrintF printf #define kSplashCxx() \ - kPrintF(kWhite "Zeta C Driver, %s, (c) ZKA Technologies\n", kDistVersion) + kPrintF(kWhite "ZKA C Driver, %s, (c) ZKA Technologies\n", kDistVersion) static void cc_print_help() { diff --git a/Sources/bpp.cxx b/Sources/bpp.cxx index e027c47..5dc70a1 100644 --- a/Sources/bpp.cxx +++ b/Sources/bpp.cxx @@ -817,7 +817,7 @@ NDK_MODULE(NewOSPreprocessor) { } if (strcmp(argv[index], "/help") == 0) { - printf("%s\n", "Zeta Preprocessor Driver v1.11, (c) ZKA Technologies"); + printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) ZKA Technologies"); printf("%s\n", "/working-dir : set directory to working path."); printf("%s\n", "/include-dir : add directory to include path."); printf("%s\n", "/def : def macro."); diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index 5b5b8bc..e651cee 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -9,7 +9,6 @@ /// bugs: 0 -#include "StdKit/Ref.hpp" #define __PK_USE_STRUCT_INSTEAD__ 1 #define kPrintF printf @@ -17,7 +16,7 @@ #define kOk (0) #define kSplashCxx() \ -kPrintF(kWhite "%s\n", "Zeta C++ Compiler Driver, (c) 2024 Zeta Electronics, all rights reserved.") + kPrintF(kWhite "%s\n", "ZKA C++ Compiler Driver, (c) 2024 ZKA Electronics, all rights reserved.") // import, @MLAutoRelease { ... }, fn foo() -> auto { ... } @@ -175,7 +174,7 @@ static bool kOnForLoop = false; static bool kInBraces = false; static size_t kBracesCount = 0UL; -/* @brief C++ compiler backend for the Zeta C++ driver */ +/* @brief C++ compiler backend for the ZKA C++ driver */ class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { public: @@ -231,7 +230,7 @@ static size_t kLevelFunction = 0UL; const char* CompilerBackendCPlusPlus::Language() { - return "Zeta C++"; + return "ZKA C++"; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -316,6 +315,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, switch (keyword.first.keyword_kind) { case ParserKit::KeywordKind::eKeywordKindFunctionStart: { + if (text.ends_with(";")) + { + break; + } + std::string fnName = text; fnName.erase(fnName.find(keyword.first.keyword_name)); @@ -331,6 +335,9 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, break; } case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { + if (text.ends_with(";")) + break; + --kLevelFunction; if (kRegisterMap.size() > cRegisters.size()) @@ -342,6 +349,80 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, kRegisterMap.clear(); break; } + case ParserKit::KeywordKind::eKeywordKindIf: + case ParserKit::KeywordKind::eKeywordKindElseIf: { + std::string valueOfVar = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size()); + + if (valueOfVar.find("(") == std::string::npos) + { + detail::print_error("Missing '('", file); + } + else if (valueOfVar.find(")") == std::string::npos) + { + detail::print_error("Missing ')'", file); + } + + valueOfVar = valueOfVar.erase(valueOfVar.find("("), 1); + valueOfVar = valueOfVar.erase(valueOfVar.find(")"), 1); + + size_t index = 0UL; + std::string result = ""; + bool fill_value = false; + + for (auto& chr : valueOfVar) + { + if (chr == '!') + { + result += "cmpnz "; + fill_value = true; + } + + if (chr == '>') + { + + if (valueOfVar[index + 1] == '=') + result += "cmpge "; + else + result += "cmpg "; + + fill_value = true; + } + else if (chr == '<') + { + if (valueOfVar[index + 1] == '=') + result += "cmple "; + else + result += "cmpl "; + + fill_value = true; + } + else if (chr == '=') + { + if (valueOfVar[index + 1] == '=') + result += "cmpge "; + else + result += "mov "; + + fill_value = true; + } + + if (fill_value) + { + for (auto i = index; i < valueOfVar.size(); ++i) + { + result += valueOfVar[i]; + + if (valueOfVar[i] == ' ') + { + result += "\n"; + break; + } + } + } + + ++index; + } + } case ParserKit::KeywordKind::eKeywordKindEndInstr: case ParserKit::KeywordKind::eKeywordKindVariableInc: case ParserKit::KeywordKind::eKeywordKindVariableDec: @@ -634,7 +715,7 @@ _MpccOkay: class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface { public: - explicit AssemblyCPlusPlusInterface() = default; + explicit AssemblyCPlusPlusInterface() = default; ~AssemblyCPlusPlusInterface() override = default; MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); @@ -656,29 +737,23 @@ public: /* @brief copy contents wihtout extension */ std::string src_file = src.data(); std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } + const char* cExts[] = kAsmFileExts; - dest += ch; - } + std::string dest = src_file; + dest += cExts[4]; if (dest.empty()) { dest = "CXX-NDK-"; std::random_device rd; - auto seed_data = std::array {}; + auto seed_data = std::array{}; std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); + std::mt19937 generator(seq); auto gen = uuids::uuid_random_generator(generator); @@ -686,12 +761,6 @@ public: dest += uuids::to_string(id); } - std::vector exts = kAsmFileExts; - - dest += exts[3]; - - std::cout << dest; - kState.fOutputAssembly = std::make_unique(dest); auto fmt = CompilerKit::current_date(); @@ -749,6 +818,10 @@ NDK_MODULE(CompilerCPlusPlus) { bool skip = false; + kKeywords.push_back({.keyword_name = "if", .keyword_kind = ParserKit::eKeywordKindIf}); + kKeywords.push_back({.keyword_name = "else", .keyword_kind = ParserKit::eKeywordKindElse}); + kKeywords.push_back({.keyword_name = "else if", .keyword_kind = ParserKit::eKeywordKindElseIf}); + kKeywords.push_back({.keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass}); kKeywords.push_back({.keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass}); kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); diff --git a/Sources/link.cxx b/Sources/link.cxx index e671d84..d0d2628 100644 --- a/Sources/link.cxx +++ b/Sources/link.cxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright ZKA Technologies + Copyright ZKA Technologies ------------------------------------------- */ @@ -35,7 +35,7 @@ #include #include -#define kLinkerVersion "Zeta Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" +#define kLinkerVersion "ZKA Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" #define StringCompare(DST, SRC) strcmp(DST, SRC) @@ -51,13 +51,13 @@ enum { - eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ + eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ eABINewOSKrnl = 0x5046, /* PF (NewOSKrnl) */ - eABIMTL = 0x4650, /* FP (MTL firmware) */ - eABIInvalid = 1, + eABIMTL = 0x4650, /* FP (MTL firmware) */ + eABIInvalid = 1, }; -static std::string kOutput; +static std::string kOutput = ""; static Int32 kAbi = eABINewOSKrnl; static Int32 kSubArch = kPefNoSubCpu; static Int32 kArch = CompilerKit::kPefArchInvalid; @@ -82,9 +82,9 @@ NDK_MODULE(NewOSLinker) bool is_executable = true; /** - * @brief parse flags and such. - * - */ + * @brief parse flags and such. + * + */ for (size_t i = 1; i < argc; ++i) { if (StringCompare(argv[i], "/help") == 0) -- cgit v1.2.3 From 1817fbd2664f528d29d7fe02eb361585321b858f Mon Sep 17 00:00:00 2001 From: Amlal Date: Mon, 22 Jul 2024 11:17:51 +0200 Subject: [FIX] variable being set to zero after being filled. Signed-off-by: Amlal --- Sources/cplusplus.cxx | 131 ++++++++++++++------------------------------------ 1 file changed, 36 insertions(+), 95 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index e651cee..944004b 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -22,7 +22,8 @@ #include #include -#include +#include + #include #include #include @@ -30,9 +31,8 @@ #include #include #include -#include -/* ZKA Technologies C++ driver */ +/* ZKA C++ driver */ /* This is part of NDK. */ /* (c) ZKA Technologies */ @@ -349,80 +349,6 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, kRegisterMap.clear(); break; } - case ParserKit::KeywordKind::eKeywordKindIf: - case ParserKit::KeywordKind::eKeywordKindElseIf: { - std::string valueOfVar = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size()); - - if (valueOfVar.find("(") == std::string::npos) - { - detail::print_error("Missing '('", file); - } - else if (valueOfVar.find(")") == std::string::npos) - { - detail::print_error("Missing ')'", file); - } - - valueOfVar = valueOfVar.erase(valueOfVar.find("("), 1); - valueOfVar = valueOfVar.erase(valueOfVar.find(")"), 1); - - size_t index = 0UL; - std::string result = ""; - bool fill_value = false; - - for (auto& chr : valueOfVar) - { - if (chr == '!') - { - result += "cmpnz "; - fill_value = true; - } - - if (chr == '>') - { - - if (valueOfVar[index + 1] == '=') - result += "cmpge "; - else - result += "cmpg "; - - fill_value = true; - } - else if (chr == '<') - { - if (valueOfVar[index + 1] == '=') - result += "cmple "; - else - result += "cmpl "; - - fill_value = true; - } - else if (chr == '=') - { - if (valueOfVar[index + 1] == '=') - result += "cmpge "; - else - result += "mov "; - - fill_value = true; - } - - if (fill_value) - { - for (auto i = index; i < valueOfVar.size(); ++i) - { - result += valueOfVar[i]; - - if (valueOfVar[i] == ' ') - { - result += "\n"; - break; - } - } - } - - ++index; - } - } case ParserKit::KeywordKind::eKeywordKindEndInstr: case ParserKit::KeywordKind::eKeywordKindVariableInc: case ParserKit::KeywordKind::eKeywordKindVariableDec: @@ -443,7 +369,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) { - valueOfVar = "0\n"; + break; } while (valueOfVar.find(";") != std::string::npos && @@ -471,25 +397,21 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, varName.erase(varName.find(";")); } - bool typeFound = false; + static bool typeFound = false; for (auto& keyword : kKeywords) { if (keyword.keyword_kind == ParserKit::eKeywordKindType) { - if (varName.find(keyword.keyword_name) != std::string::npos) - { - typeFound = true; - varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); - } - - /// in case we goot boolX or intX if (text.find(keyword.keyword_name) != std::string::npos) { - if (varName[text.find(keyword.keyword_name)] == ' ') + if (text[text.find(keyword.keyword_name)] == ' ') + { + typeFound = false; continue; + } - typeFound = false; + typeFound = true; } } } @@ -550,11 +472,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (pairRight != valueOfVar) { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - continue; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + goto done; } - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + cRegisters[indexRight - 1] + "\n"; + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; break; } @@ -563,10 +485,18 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; } + done: kRegisterMap.push_back(varName); } else { + if (kKeywords[keyword.second - 1].keyword_kind == ParserKit::eKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == ParserKit::eKeywordKindTypePtr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) { syntax_tree.fUserValue = "\n"; @@ -604,6 +534,16 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, valueOfVar.erase(i, 1); } + while (valueOfVar.find(" ") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find(" "), 1); + } + + while (valueOfVar.find("\t") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find("\t"), 1); + } + constexpr auto cTrueVal = "true"; constexpr auto cFalseVal = "false"; @@ -631,13 +571,13 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, { ++indexRight; - if (pairRight != valueOfVar) + if (pairRight != varName) { syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; continue; } - syntax_tree.fUserValue = instr + cRegisters[indxReg - 1] + ", " + cRegisters[indexRight - 1] + "\n"; + syntax_tree.fUserValue = instr + cRegisters[indexRight - 1] + ", " + valueOfVar + "\n"; break; } @@ -670,7 +610,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (pair != subText) continue; - syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg - 1] + "\r\nret\n"; + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg] + "\r\nret\n"; break; } @@ -740,7 +680,7 @@ public: const char* cExts[] = kAsmFileExts; - std::string dest = src_file; + std::string dest = src_file; dest += cExts[4]; if (dest.empty()) @@ -977,3 +917,4 @@ NDK_MODULE(CompilerCPlusPlus) } // Last rev 8-1-24 +// -- cgit v1.2.3 From c0d76598d14d329b0cca8ad61fad55d75446b071 Mon Sep 17 00:00:00 2001 From: Amlal Date: Tue, 23 Jul 2024 20:56:47 +0200 Subject: [IMP] if condition statement on 'cplusplus' compiler. Signed-off-by: Amlal --- Sources/cplusplus.cxx | 111 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) (limited to 'Sources') diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index 944004b..61be2a6 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -314,14 +315,119 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, switch (keyword.first.keyword_kind) { + case ParserKit::KeywordKind::eKeywordKindIf: { + auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); + + if (expr.find(">=") != std::string::npos) + { + auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); + auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); + + size_t i = right.size() - 1; + + try + { + while (!std::isalnum(right[i])) + { + right.erase(i, 1); + --i; + } + + right.erase(0, i); + } + catch (...) + { + right.erase(0, i); + } + + i = left.size() - 1; + try + { + + while (!std::isalnum(left[i])) + { + left.erase(i, 1); + --i; + } + + left.erase(0, i); + } + catch (...) + { + left.erase(0, i); + } + + if (!isdigit(left[0]) || + !isdigit(right[0])) + { + auto indexRight = 0UL; + + auto& valueOfVar = !isdigit(left[0]) ? left : right; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + "," + cRegisters[indexRight + 1] + "\n"; + + goto done_iterarting_on_if; + } + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + ", " + cRegisters[indexRight + 1] + "\n"; + + break; + } + } + + done_iterarting_on_if: + + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue += "jge offset [rsp + 4]\n"; + } + + break; + } case ParserKit::KeywordKind::eKeywordKindFunctionStart: { if (text.ends_with(";")) { break; } + for (auto& ch : text) + { + if (isdigit(ch)) + { + goto dont_accept; + } + } + + goto accept; + + dont_accept: + return true; + + accept: std::string fnName = text; - fnName.erase(fnName.find(keyword.first.keyword_name)); for (auto& ch : fnName) { @@ -332,7 +438,6 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; ++kLevelFunction; - break; } case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { if (text.ends_with(";")) @@ -369,7 +474,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) { - break; + break; } while (valueOfVar.find(";") != std::string::npos && -- cgit v1.2.3 From 698a44192b1b3ffb188af931d66e2570b1fb39a9 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Fri, 26 Jul 2024 19:43:24 +0200 Subject: [IMP] NDKKit, Compiler agnostic kit. Signed-off-by: Amlal EL Mahrouss --- .gitignore | 2 +- .vscode/c_cpp_properties.json | 4 +- Headers/AsmKit/AsmKit.hpp | 217 --- Headers/AsmKit/CPU/32x0.hpp | 95 -- Headers/AsmKit/CPU/64x0.hpp | 108 -- Headers/AsmKit/CPU/amd64.hpp | 57 - Headers/AsmKit/CPU/arm64.hpp | 26 - Headers/AsmKit/CPU/ppc.hpp | 1929 --------------------------- Headers/Defines.hpp | 147 -- Headers/Macros.hpp | 33 - Headers/ParserKit.hpp | 173 --- Headers/Public/SDK/CRT/__mpcc_alloca.hxx | 15 - Headers/Public/SDK/CRT/__mpcc_defines.hxx | 83 -- Headers/Public/SDK/CRT/__mpcc_exception.hxx | 27 - Headers/Public/SDK/CRT/__mpcc_hint.hxx | 20 - Headers/Public/SDK/CRT/__mpcc_malloc.hxx | 30 - Headers/Public/SDK/CRT/__mpcc_power.inc | 35 - Headers/StdKit/AE.hpp | 143 -- Headers/StdKit/ELF.hpp | 389 ------ Headers/StdKit/ErrorID.hpp | 22 - Headers/StdKit/ErrorOr.hpp | 61 - Headers/StdKit/PEF.hpp | 134 -- Headers/StdKit/Ref.hpp | 97 -- Headers/StdKit/String.hpp | 90 -- Headers/StdKit/XCOFF.hxx | 41 - Headers/UUID.hpp | 983 -------------- Headers/Version.hxx | 3 - NDKKit/AsmKit/AsmKit.hpp | 217 +++ NDKKit/AsmKit/CPU/32x0.hpp | 95 ++ NDKKit/AsmKit/CPU/64x0.hpp | 108 ++ NDKKit/AsmKit/CPU/amd64.hpp | 57 + NDKKit/AsmKit/CPU/arm64.hpp | 26 + NDKKit/AsmKit/CPU/ppc.hpp | 1929 +++++++++++++++++++++++++++ NDKKit/Defines.hpp | 147 ++ NDKKit/Macros.hpp | 33 + NDKKit/NFC/AE.hpp | 143 ++ NDKKit/NFC/ELF.hpp | 389 ++++++ NDKKit/NFC/ErrorID.hpp | 22 + NDKKit/NFC/ErrorOr.hpp | 61 + NDKKit/NFC/PEF.hpp | 134 ++ NDKKit/NFC/Ref.hpp | 97 ++ NDKKit/NFC/String.hpp | 90 ++ NDKKit/NFC/XCOFF.hxx | 41 + NDKKit/Parser.hpp | 178 +++ NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx | 15 + NDKKit/Public/SDK/CRT/__mpcc_defines.hxx | 83 ++ NDKKit/Public/SDK/CRT/__mpcc_exception.hxx | 27 + NDKKit/Public/SDK/CRT/__mpcc_hint.hxx | 20 + NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx | 30 + NDKKit/Public/SDK/CRT/__mpcc_power.inc | 35 + NDKKit/UUID.hpp | 983 ++++++++++++++ NDKKit/Version.hpp | 4 + ReadMe.md | 8 +- Sources/32asm.cxx | 8 +- Sources/64asm.cxx | 44 +- Sources/64x0-cc.cxx | 36 +- Sources/AssemblyFactory.cxx | 4 +- Sources/Detail/asmutils.hxx | 4 +- Sources/Detail/compilerutils.hxx | 4 +- Sources/String.cxx | 2 +- Sources/bpp.cxx | 6 +- Sources/coff2ae.cxx | 6 +- Sources/cplusplus.cxx | 194 +-- Sources/elf2ae.cxx | 6 +- Sources/i64asm.cxx | 28 +- Sources/link.cxx | 12 +- Sources/power-as.cxx | 976 ++++++++++++++ Sources/power-cc.cxx | 36 +- Sources/ppcasm.cxx | 976 -------------- posix.make | 6 +- win64.make | 6 +- 71 files changed, 6149 insertions(+), 6141 deletions(-) delete mode 100644 Headers/AsmKit/AsmKit.hpp delete mode 100644 Headers/AsmKit/CPU/32x0.hpp delete mode 100644 Headers/AsmKit/CPU/64x0.hpp delete mode 100644 Headers/AsmKit/CPU/amd64.hpp delete mode 100644 Headers/AsmKit/CPU/arm64.hpp delete mode 100644 Headers/AsmKit/CPU/ppc.hpp delete mode 100644 Headers/Defines.hpp delete mode 100644 Headers/Macros.hpp delete mode 100644 Headers/ParserKit.hpp delete mode 100644 Headers/Public/SDK/CRT/__mpcc_alloca.hxx delete mode 100644 Headers/Public/SDK/CRT/__mpcc_defines.hxx delete mode 100644 Headers/Public/SDK/CRT/__mpcc_exception.hxx delete mode 100644 Headers/Public/SDK/CRT/__mpcc_hint.hxx delete mode 100644 Headers/Public/SDK/CRT/__mpcc_malloc.hxx delete mode 100644 Headers/Public/SDK/CRT/__mpcc_power.inc delete mode 100644 Headers/StdKit/AE.hpp delete mode 100644 Headers/StdKit/ELF.hpp delete mode 100644 Headers/StdKit/ErrorID.hpp delete mode 100644 Headers/StdKit/ErrorOr.hpp delete mode 100644 Headers/StdKit/PEF.hpp delete mode 100644 Headers/StdKit/Ref.hpp delete mode 100644 Headers/StdKit/String.hpp delete mode 100644 Headers/StdKit/XCOFF.hxx delete mode 100644 Headers/UUID.hpp delete mode 100644 Headers/Version.hxx create mode 100644 NDKKit/AsmKit/AsmKit.hpp create mode 100644 NDKKit/AsmKit/CPU/32x0.hpp create mode 100644 NDKKit/AsmKit/CPU/64x0.hpp create mode 100644 NDKKit/AsmKit/CPU/amd64.hpp create mode 100644 NDKKit/AsmKit/CPU/arm64.hpp create mode 100644 NDKKit/AsmKit/CPU/ppc.hpp create mode 100644 NDKKit/Defines.hpp create mode 100644 NDKKit/Macros.hpp create mode 100644 NDKKit/NFC/AE.hpp create mode 100644 NDKKit/NFC/ELF.hpp create mode 100644 NDKKit/NFC/ErrorID.hpp create mode 100644 NDKKit/NFC/ErrorOr.hpp create mode 100644 NDKKit/NFC/PEF.hpp create mode 100644 NDKKit/NFC/Ref.hpp create mode 100644 NDKKit/NFC/String.hpp create mode 100644 NDKKit/NFC/XCOFF.hxx create mode 100644 NDKKit/Parser.hpp create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_defines.hxx create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_exception.hxx create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_hint.hxx create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx create mode 100644 NDKKit/Public/SDK/CRT/__mpcc_power.inc create mode 100644 NDKKit/UUID.hpp create mode 100644 NDKKit/Version.hpp create mode 100644 Sources/power-as.cxx delete mode 100644 Sources/ppcasm.cxx (limited to 'Sources') diff --git a/.gitignore b/.gitignore index 22939a1..8ae6805 100644 --- a/.gitignore +++ b/.gitignore @@ -77,7 +77,7 @@ Output/i64link Output/link Output/power-cc Output/ppc-cc -Output/ppcasm +Output/power-as Output/ppclink .vs diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index c520968..cd1cb3d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,7 @@ { "name": "Macintosh (CLang)", "includePath": [ - "${workspaceFolder}/Headers/**", + "${workspaceFolder}/NDKKit/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], @@ -16,7 +16,7 @@ { "name": "Windows (Cygwin)", "includePath": [ - "${workspaceFolder}/Headers/**", + "${workspaceFolder}/NDKKit/**", "${workspaceFolder}/Sources/Detail/**", "${workspaceFolder}/**" ], diff --git a/Headers/AsmKit/AsmKit.hpp b/Headers/AsmKit/AsmKit.hpp deleted file mode 100644 index b492ce8..0000000 --- a/Headers/AsmKit/AsmKit.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include -#include - -namespace CompilerKit -{ - // - // @brief Frontend to Assembly mountpoint. - // - class AssemblyInterface - { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - MPCC_COPY_DEFAULT(AssemblyInterface); - - //@ brief compile to object file. - // Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; - }; - - /// @brief Simple assembly factory - class AssemblyFactory final - { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - MPCC_COPY_DEFAULT(AssemblyFactory); - - public: - enum - { - kArchAMD64, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchUnknown, - }; - - Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; - }; - - union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; - }; - - union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) - : raw(raw) - { - } - ~NumberCast64() - { - raw = 0; - } - - CharType number[8]; - UInt64 raw; - }; - - union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) - : raw(raw) - { - } - ~NumberCast32() - { - raw = 0; - } - - CharType number[4]; - UInt32 raw; - }; - - union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) - : raw(raw) - { - } - ~NumberCast16() - { - raw = 0; - } - - CharType number[2]; - UInt16 raw; - }; - - union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) - : raw(raw) - { - } - ~NumberCast8() - { - raw = 0; - } - - CharType number; - UInt8 raw; - }; - - class EncoderInterface - { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - MPCC_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string& line, const std::string& file) = 0; - virtual bool WriteLine(std::string& line, const std::string& file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; - }; - -#ifdef __ASM_NEED_AMD64__ - - class EncoderAMD64 final : public EncoderInterface - { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - MPCC_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); - }; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_64x0__ - - class Encoder64x0 final : public EncoderInterface - { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - MPCC_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - - class Encoder32x0 final : public EncoderInterface - { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - MPCC_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - - class EncoderPowerPC final : public EncoderInterface - { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - MPCC_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/Headers/AsmKit/CPU/32x0.hpp b/Headers/AsmKit/CPU/32x0.hpp deleted file mode 100644 index cfe4a47..0000000 --- a/Headers/AsmKit/CPU/32x0.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @brief 32x0 support. -// @file CPU/32x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 - -#define kAsmByte 0 -#define kAsmHWord 1 -#define kAsmWord 2 - -struct CpuCode32x0 -{ - const char fName[32]; - char fOpcode; - char fSize; - char fFunct3; - char fFunct7; -}; - -#define kAsmDWordStr ".dword" /* 64 bit */ -#define kAsmWordStr ".word" /* 32-bit */ -#define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ - -inline std::vector kOpcodes32x0 = { - kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. - kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch - kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers - kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp - kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. - kAsmOpcodeDecl("cls", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR. - kAsmOpcodeDecl("rts", 0b0111011, 0b110, - kAsmImmediate) // pull stack and return form CR. - kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt -}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: TODO: find one -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Headers/AsmKit/CPU/64x0.hpp b/Headers/AsmKit/CPU/64x0.hpp deleted file mode 100644 index 2da4f24..0000000 --- a/Headers/AsmKit/CPU/64x0.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -// @brief 64x0 support. -// @file CPU/64x0.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 - -typedef char e64k_character_t; -typedef uint8_t e64k_num_t; - -struct CpuOpcode64x0 -{ - const e64k_character_t fName[32]; - e64k_num_t fOpcode; - e64k_num_t fFunct3; - e64k_num_t fFunct7; -}; - -inline std::vector kOpcodes64x0 = { - kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) - kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) - kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL/JUMP ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/Headers/AsmKit/CPU/amd64.hpp b/Headers/AsmKit/CPU/amd64.hpp deleted file mode 100644 index bc4b956..0000000 --- a/Headers/AsmKit/CPU/amd64.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @brief AMD64 support. -// @file CPU/amd64.hpp - -#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, - -typedef char i64_character_t; -typedef uint8_t i64_byte_t; -typedef uint16_t i64_hword_t; -typedef uint32_t i64_word_t; - -struct CpuOpcodeAMD64 -{ - std::string fName; - i64_byte_t fPrefixBytes[4]; - i64_hword_t fOpcode; - i64_hword_t fModReg; - i64_word_t fDisplacment; - i64_word_t fImmediate; -}; - -/// these two are edge cases -#define kAsmIntOpcode 0xCC -#define kasmIntOpcodeAlt 0xCD - -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 -#define kJumpLimitStandardLimit 0xEB - -inline std::vector kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF) -}; - -#define kAsmRegisterLimit 15 diff --git a/Headers/AsmKit/CPU/arm64.hpp b/Headers/AsmKit/CPU/arm64.hpp deleted file mode 100644 index e7d4f68..0000000 --- a/Headers/AsmKit/CPU/arm64.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* ------------------------------------------- - -Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -/// @brief ARM64 encoding support. -/// @file CPU/arm64.hpp - -struct CpuOpcodeArm64; - -/// @brief ARM64 opcode header. -struct CpuOpcodeArm64 final -{ - uint8_t fOpcode; // opcode - uint8_t fRegisterLeft; // left register index - uint8_t fRegisterRight; // right register index - bool fRegisterLeftHooked; - bool fRegisterRightHooked; - uint32_t fImmediateValue; // immediate 32-bit value - bool fImmediateValueHooked; -}; diff --git a/Headers/AsmKit/CPU/ppc.hpp b/Headers/AsmKit/CPU/ppc.hpp deleted file mode 100644 index e3ea6c5..0000000 --- a/Headers/AsmKit/CPU/ppc.hpp +++ /dev/null @@ -1,1929 +0,0 @@ -/* ------------------------------------------- - - Some modifications are copyrighted under: - ZKA Technologies - - Original author: - Apple Inc - -------------------------------------------- */ - -#pragma once - -#include - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -/* - * These defines are use in the cpus field of the instructions. If the field - * is zero it can execute on all cpus. The defines are or'ed together. This - * information is used to set the cpusubtype in the resulting object file. - */ -#define CPU601 0x1 -#define IMPL64 0x2 -#define OPTIONAL 0x4 -#define VMX 0x8 -#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ -#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ - -enum optype -{ - NONE, /* no operand */ - JBSR, /* jbsr pseudo op */ - PCREL, /* PC relative (branch offset) */ - BADDR, /* Branch address (sign extended absolute address) */ - D, /* 16 bit displacement */ - DS, /* 14 bit displacement (double word) */ - SI, /* signed 16 bit immediate */ - UI, /* unsigned 16 bit immediate */ - HI, /* high 16 bit immediate (with truncation) */ - GREG, /* general register */ - G0REG, /* general register r1-r31 or 0 */ - FREG, /* float register */ - VREG, /* vector register */ - SGREG, /* segment register */ - SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ - BCND, /* branch condition opcode */ - CRF, /* condition register field */ - CRFONLY, /* condition register field only no expression allowed */ - sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ - mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ - NUM, /* number */ - SNUM, /* signed number */ - NUM0, /* number (where 1< - -#define SizeType size_t - -#define VoidPtr void* -#define voidPtr VoidPtr - -#define UIntPtr uintptr_t - -#define Int64 int64_t -#define UInt64 uint64_t - -#define Int32 int -#define UInt32 unsigned - -#define Bool bool - -#define Int16 int16_t -#define UInt16 uint16_t - -#define Int8 int8_t -#define UInt8 uint8_t - -#define CharType char -#define Boolean bool - -#include -#include -#include - -#define nullPtr std::nullptr_t - -#define MUST_PASS(E) assert(E) - -#ifndef __FORCE_STRLEN -#define __FORCE_STRLEN 1 - -#define string_length(len) strlen(len) -#endif - -#ifndef __FORCE_MEMCPY -#define __FORCE_MEMCPY 1 - -#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) -#endif - -#define MPCC_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define MPCC_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define MPCC_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define MPCC_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#include -#include -#include -#include - -namespace CompilerKit -{ - inline constexpr int BASE_YEAR = 1900; - - inline std::string current_date() noexcept - { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); - - return fmt; - } - - inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept - { - if (limit == 0) - return false; - - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; - - while (limit != 1) - { - ret = ret % 10; - str[cnt] = ret; - - ++cnt; - --limit; - --ret; - } - - str[copy_limit] = '\0'; - return true; - } -} // namespace CompilerKit - -#define PACKED __attribute__((packed)) - -typedef char char_type; - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { \ - ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ - } - -#ifdef __NDK_MODULE__ -#define NDK_MODULE(name) int name(int argc, char** argv) -#else -#define NDK_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __NDK_MODULE__ */ - -#pragma scalar_storage_order big-endian - -#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Headers/Macros.hpp b/Headers/Macros.hpp deleted file mode 100644 index c190cda..0000000 --- a/Headers/Macros.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// @brief provide support for Macros.hpp header. - -#ifndef _CK_CL_HPP -#define _CK_CL_HPP - -#define MPCC_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define MPCC_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define MPCC_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define MPCC_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -/// @note xxxx is the error placeholder, in hexadecimal. -#define MPCC_ERROR_PREFIX_CXX "CXXxxxx" -#define MPCC_ERROR_PREFIX_CL "CLxxxx" -#define MPCC_ERROR_PREFIX_ASM "ASMxxxx" - -#endif /* ifndef _CK_CL_HPP */ diff --git a/Headers/ParserKit.hpp b/Headers/ParserKit.hpp deleted file mode 100644 index 186c9cf..0000000 --- a/Headers/ParserKit.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -namespace ParserKit -{ - using namespace CompilerKit; - - /// @brief Compiler backend, implements a frontend, such as C, C++... - /// See Toolchain, for some examples. - class CompilerBackend - { - public: - explicit CompilerBackend() = default; - virtual ~CompilerBackend() = default; - - MPCC_COPY_DEFAULT(CompilerBackend); - - // NOTE: cast this to your user defined ast. - typedef void* AstType; - - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - - virtual bool Compile(const std::string& text, const char* file) = 0; - - //! @brief What language are we dealing with? - virtual const char* Language() - { - return "Invalid Language"; - } - }; - - struct SyntaxLeafList; - struct SyntaxLeafList; - struct CompilerKeyword; - - /// we want to do that because to separate keywords. - enum KeywordKind - { - eKeywordKindNamespace, - eKeywordKindFunctionStart, - eKeywordKindFunctionEnd, - eKeywordKindVariable, - eKeywordKindVariablePtr, - eKeywordKindType, - eKeywordKindTypePtr, - eKeywordKindExpressionBegin, - eKeywordKindExpressionEnd, - eKeywordKindArgSeparator, - eKeywordKindBodyStart, - eKeywordKindBodyEnd, - eKeywordKindClass, - eKeywordKindPtrAccess, - eKeywordKindAccess, - eKeywordKindIf, - eKeywordKindElse, - eKeywordKindElseIf, - eKeywordKindVariableAssign, - eKeywordKindVariableDec, - eKeywordKindVariableInc, - eKeywordKindConstant, - eKeywordKindTypedef, - eKeywordKindEndInstr, - eKeywordKindSpecifier, - eKeywordKindInvalid, - eKeywordKindReturn, - eKeywordKindCommentInline, - eKeywordKindCommentMultiLineStart, - eKeywordKindCommentMultiLineEnd, - eKeywordKindEq, - eKeywordKindNotEq, - eKeywordKindGreaterEq, - eKeywordKindLessEq, - eKeywordKindPtr, - }; - - /// \brief Compiler keyword information struct. - struct CompilerKeyword - { - std::string keyword_name; - KeywordKind keyword_kind = eKeywordKindInvalid; - }; - struct SyntaxLeafList final - { - struct SyntaxLeaf final - { - Int32 fUserType; -#ifdef __PK_USE_STRUCT_INSTEAD__ - CompilerKeyword fUserData; -#else - std::string fUserData; -#endif - - std::string fUserValue; - struct SyntaxLeaf* fNext; - }; - - std::vector fLeafList; - SizeType fNumLeafs; - - size_t SizeOf() - { - return fNumLeafs; - } - std::vector& Get() - { - return fLeafList; - } - SyntaxLeaf& At(size_t index) - { - return fLeafList[index]; - } - }; - - /// find the perfect matching word in a haystack. - /// \param haystack base string - /// \param needle the string we search for. - /// \return if we found it or not. - inline bool find_word(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) - return true; - - if (index < 0 || index >= haystack.size()) - return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); - } - - /// find a word within strict conditions and returns a range of it. - /// \param haystack - /// \param needle - /// \return position of needle. - inline std::size_t find_word_range(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) - { - return index; - } - - return false; - } -} // namespace ParserKit diff --git a/Headers/Public/SDK/CRT/__mpcc_alloca.hxx b/Headers/Public/SDK/CRT/__mpcc_alloca.hxx deleted file mode 100644 index 02b3123..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_alloca.hxx +++ /dev/null @@ -1,15 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -typedef void* ptr_type; -typedef __SIZE_TYPE__ size_type; - -inline void* __mpcc_alloca_gcc(size_type sz) -{ - return __builtin_alloca(sz); -} diff --git a/Headers/Public/SDK/CRT/__mpcc_defines.hxx b/Headers/Public/SDK/CRT/__mpcc_defines.hxx deleted file mode 100644 index 19ed8a4..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_defines.hxx +++ /dev/null @@ -1,83 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#ifndef __MPCC_DEF__ -#define __MPCC_DEF__ - -#ifndef __GNUC__ - -typedef __SIZE_TYPE__ size_t; - -#ifdef __LP64__ -typedef long int ssize_t; -#else -typedef int ssize_t; -#endif // __LP64__ - -typedef size_t ptrdiff_t; -typedef size_t uintptr_t; -typedef void* voidptr_t; -typedef void* any_t; -typedef char* caddr_t; - -#ifndef NULL -#define NULL ((voidptr_t)0) -#endif // !null - -#ifdef __GNUC__ -#include -#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) -#define __packed__ __attribute__((packed)) -#elif defined(__MPCC__) -#define __packed__ __mpcc_packed__ -#define __alloca(sz) __mpcc_alloca(sz) -#endif - -#define __deref(ptr) (*(ptr)) - -#ifdef __cplusplus -#define __init_decl() \ - extern "C" \ - { - - -#define __fini_decl() \ - }; \ - - -#else -#define __init_decl() -#define __fini_decl() -#endif - -typedef long long off_t; -typedef unsigned long long uoff_t; - -typedef union float_cast { - struct - { - unsigned int mantissa : 23; - unsigned int exponent : 8; - unsigned int sign : 1; - }; - - float f; -} __packed__ float_cast_t; - -typedef union double_cast { - struct - { - unsigned long long int mantissa : 52; - unsigned int exponent : 11; - unsigned int sign : 1; - }; - - double f; -} __packed__ double_cast_t; - -#endif // ifndef __GNUC__ - -#endif /* __MPCC_DEF__ */ diff --git a/Headers/Public/SDK/CRT/__mpcc_exception.hxx b/Headers/Public/SDK/CRT/__mpcc_exception.hxx deleted file mode 100644 index dac42ad..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_exception.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -/// This file is an implementation of __throw* family of functions. - -#include -#include -#include - -namespace std -{ - inline void __throw_general(void) - { - throw std::runtime_error("NDK C++ Runtime error."); - } - - inline void __throw_domain_error(const char* error) - { - std::cout << "NDK C++: Domain error: " << error << "\r"; - __throw_general(); - } -} // namespace std diff --git a/Headers/Public/SDK/CRT/__mpcc_hint.hxx b/Headers/Public/SDK/CRT/__mpcc_hint.hxx deleted file mode 100644 index 02dbc94..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_hint.hxx +++ /dev/null @@ -1,20 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#pragma compiler(hint_manifest) - -#define _Input -#define _Output - -#define _Optional - -#define _StrictCheckInput -#define _StrictCheckOutput - -#define _InOut -#define _StrictInOut diff --git a/Headers/Public/SDK/CRT/__mpcc_malloc.hxx b/Headers/Public/SDK/CRT/__mpcc_malloc.hxx deleted file mode 100644 index eeaa67b..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_malloc.hxx +++ /dev/null @@ -1,30 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -namespace stdx -{ - /// @brief allocate a new class. - /// @tparam KindClass the class type to allocate. - template - inline void* allocate(Args&&... args) - { - return new KindClass(std::forward(args)...); - } - - /// @brief free a class. - /// @tparam KindClass the class type to allocate. - template - inline void release(KindClass ptr) - { - if (!ptr) - return; - delete ptr; - } -} // namespace stdx diff --git a/Headers/Public/SDK/CRT/__mpcc_power.inc b/Headers/Public/SDK/CRT/__mpcc_power.inc deleted file mode 100644 index 90b1364..0000000 --- a/Headers/Public/SDK/CRT/__mpcc_power.inc +++ /dev/null @@ -1,35 +0,0 @@ -# Path: SDK/__mpcc_power.inc -# Language: NDK POWER Assembly support for GNU. -# Build Date: 2024-6-4 - -%ifdef __CODETOOLS__ - -%def lda li -%def sta stw -%def ldw li - -%def r0 0 -%def r1 1 -%def r2 2 -%def r3 3 -%def r4 4 -%def r5 5 -%def r6 6 -%def r7 7 -%def r8 8 -%def r9 9 -%def r10 10 -%def r11 11 -%def r12 12 -%def r13 13 -%def r14 14 -%def r15 15 -%def r16 16 -%def r17 17 -%def r18 18 -%def r19 19 -%def r20 20 - -%endif - -%def nop mr 0, 0 diff --git a/Headers/StdKit/AE.hpp b/Headers/StdKit/AE.hpp deleted file mode 100644 index cf64516..0000000 --- a/Headers/StdKit/AE.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ======================================================== - * - * NDK - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen 64 -#define kAEPad 8 -#define kAEMagLen 2 -#define kAEInvalidOpcode 0x00 - -// Advanced Executable File Format for MetroLink. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system -// loader. - -namespace CompilerKit -{ - // @brief Advanced Executable Header - // One thing to keep in mind. - // This object format, is reloctable. - typedef struct AEHeader final - { - CharType fMagic[kAEMagLen]; - CharType fArch; - CharType fSubArch; - SizeType fCount; - CharType fSize; - SizeType fStartCode; - SizeType fCodeSize; - CharType fPad[kAEPad]; - } PACKED AEHeader, *AEHeaderPtr; - - // @brief Advanced Executable Record. - // Could be data, code or bss. - // fKind must be filled with PEF fields. - - typedef struct AERecordHeader final - { - CharType fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - CharType fPad[kAEPad]; - } PACKED AERecordHeader, *AERecordHeaderPtr; - - enum - { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, - }; -} // namespace CompilerKit - -// provide operator<< for AE - -std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::AERecordHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils -{ - /** - * @brief AE Reader protocol - * - */ - class AEReadableProtocol final - { - public: - std::ifstream FP; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - MPCC_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) - { - if (!raw) - return nullptr; - - return this->_Read(raw, sz * sizeof(AERecordHeader)); - } - - private: - /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ - template - TypeClass* _Read(char* raw, std::size_t sz) - { - FP.read(raw, std::streamsize(sz)); - return reinterpret_cast(raw); - } - }; -} // namespace CompilerKit::Utils diff --git a/Headers/StdKit/ELF.hpp b/Headers/StdKit/ELF.hpp deleted file mode 100644 index 4f0d0ae..0000000 --- a/Headers/StdKit/ELF.hpp +++ /dev/null @@ -1,389 +0,0 @@ -#pragma once - -#include -#include - -struct file; - -#ifndef elf_read_implies_exec -/* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif - -/* 32-bit ELF base types. */ -typedef uint32_t Elf32_Addr; -typedef uint16_t Elf32_Half; -typedef uint32_t Elf32_Off; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Word; - -/* 64-bit ELF base types. */ -typedef uintptr_t Elf64_Addr; -typedef uint16_t Elf64_Half; -typedef int16_t Elf64_SHalf; -typedef uint64_t Elf64_Off; -typedef int32_t Elf64_Sword; -typedef uint32_t Elf64_Word; -typedef uint64_t Elf64_Xword; -typedef int64_t Elf64_Sxword; - -/* These constants are for the segment types stored in the image headers */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff -#define PT_GNU_EH_FRAME 0x6474e550 - -#define PT_GNU_STACK (PT_LOOS + 0x474e551) - -/* These constants define the different elf file types */ -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 -#define ET_LOPROC 0xff00 -#define ET_HIPROC 0xffff - -/* This is the info that is needed to parse the dynamic section of the file */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_ENCODING 32 -#define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 -#define DT_VALRNGLO 0x6ffffd00 -#define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff - -/* This info is needed when parsing the symbol table */ -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 - -#define ELF_ST_BIND(x) ((x) >> 4) -#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) -#define ELF32_ST_BIND(x) ELF_ST_BIND(x) -#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) -#define ELF64_ST_BIND(x) ELF_ST_BIND(x) -#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) - -typedef struct dynamic -{ - Elf32_Sword d_tag; - union { - Elf32_Sword d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct -{ - Elf64_Sxword d_tag; /* entry tag value */ - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - -/* The following are used with relocations */ -#define ELF32_R_SYM(x) ((x) >> 8) -#define ELF32_R_TYPE(x) ((x)&0xff) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i)&0xffffffff) - -typedef struct elf32_rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct elf64_rel -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ -} Elf64_Rel; - -typedef struct elf32_rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct elf64_rela -{ - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ - Elf64_Sxword r_addend; /* Constant addend used to compute value */ -} Elf64_Rela; - -typedef struct elf32_sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct elf64_sym -{ - Elf64_Word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - Elf64_Half st_shndx; /* Associated section index */ - Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Xword st_size; /* Associated symbol size */ -} Elf64_Sym; - -#define EI_NIDENT 16 - -typedef struct elf32_hdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; /* Entry point */ - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Ehdr; - -typedef struct elf64_hdr -{ - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* These constants define the permissions on sections in the program - header, p_flags. */ -#define PF_R 0x4 -#define PF_W 0x2 -#define PF_X 0x1 - -typedef struct elf32_phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -typedef struct elf64_phdr -{ - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment, file & memory */ -} Elf64_Phdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_NUM 12 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xffffffff - -/* sh_flags */ -#define SHF_WRITE 0x1 -#define SHF_ALLOC 0x2 -#define SHF_EXECINSTR 0x4 -#define SHF_MASKPROC 0xf0000000 - -/* special section indexes */ -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_LOPROC 0xff00 -#define SHN_HIPROC 0xff1f -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_HIRESERVE 0xffff - -typedef struct -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; - -typedef struct elf64_shdr -{ - Elf64_Word sh_name; /* Section name, index in string tbl */ - Elf64_Word sh_type; /* Type of section */ - Elf64_Xword sh_flags; /* Miscellaneous section attributes */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Size of section in bytes */ - Elf64_Word sh_link; /* Index of another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -#define EI_MAG0 0 /* e_ident[] indexes */ -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_PAD 8 - -#define ELFMAG0 0x7f /* EI_MAG */ -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define ELFCLASSNONE 0 /* EI_CLASS */ -#define ELFCLASS32 1 -#define ELFCLASS64 2 -#define ELFCLASSNUM 3 - -#define ELFDATANONE 0 /* e_ident[EI_DATA] */ -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_NONE 0 /* e_version, EI_VERSION */ -#define EV_CURRENT 1 -#define EV_NUM 2 - -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 - -#ifndef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE -#endif - -/* Notes used in ET_CORE */ -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ -#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* POWER VSX registers */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ - -/* Note header in a PT_NOTE section */ -typedef struct elf32_note -{ - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ -} Elf32_Nhdr; - -/* Note header in a PT_NOTE section */ -typedef struct elf64_note -{ - Elf64_Word n_namesz; /* Name size */ - Elf64_Word n_descsz; /* Content size */ - Elf64_Word n_type; /* Content type */ -} Elf64_Nhdr; diff --git a/Headers/StdKit/ErrorID.hpp b/Headers/StdKit/ErrorID.hpp deleted file mode 100644 index 41d6b2f..0000000 --- a/Headers/StdKit/ErrorID.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -#define MPCC_EXEC_ERROR -30 -#define MPCC_FILE_NOT_FOUND -31 -#define MPCC_DIR_NOT_FOUND -32 -#define MPCC_FILE_EXISTS -33 -#define MPCC_TOO_LONG -34 -#define MPCC_INVALID_DATA -35 -#define MPCC_UNIMPLEMENTED -36 -#define MPCC_FAT_ERROR -37 diff --git a/Headers/StdKit/ErrorOr.hpp b/Headers/StdKit/ErrorOr.hpp deleted file mode 100644 index 6c8e87e..0000000 --- a/Headers/StdKit/ErrorOr.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - using ErrorT = UInt32; - - template - class ErrorOr final - { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(Int32 err) - : mId(err) - { - } - - explicit ErrorOr(nullPtr Null) - { - } - - explicit ErrorOr(T Class) - : mRef(Class) - { - } - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref Leak() - { - return mRef; - } - - operator bool() - { - return mRef; - } - - private: - Ref mRef; - Int32 mId{0}; - }; - - using ErrorOrAny = ErrorOr; - -} // namespace CompilerKit diff --git a/Headers/StdKit/PEF.hpp b/Headers/StdKit/PEF.hpp deleted file mode 100644 index d8709ed..0000000 --- a/Headers/StdKit/PEF.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include - -// @file PEF.hpp -// @brief Preferred Executable Format - -#define kPefMagic "Joy!" -#define kPefMagicFat "yoJ!" - -#define kPefExt ".exec" -#define kPefDylibExt ".lib" -#define kPefLibExt ".slib" -#define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" - -#define kPefMagicLen 5 - -#define kPefVersion 2 -#define kPefNameLen 255 - -#define kPefBaseOrigin (0x1000000) - -#define kPefStart "__ImageStart" - -namespace CompilerKit -{ - enum - { - kPefArchStart = 99, - kPefArchIntel86S = 100, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* 64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchARM64, - kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, - }; - - enum - { - kPefSubArchAMD, - kPefSubArchIntel, - kPefSubArchGeneric, - kPefSubArchIBM, - }; - - enum - { - kPefKindExec = 1, /* .exe */ - kPefKindSharedObject = 2, /* .lib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, - }; - - /* PEF container */ - typedef struct PEFContainer final - { - CharType Magic[kPefMagicLen]; - UInt32 Linker; - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - } PACKED PEFContainer; - - /* First PEFCommandHeader starts after PEFContainer */ - /* Last container is __exec_end */ - - /* PEF executable section and commands. */ - - typedef struct PEFCommandHeader final - { - CharType Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* file offset */ - SizeType Size; /* file size */ - } PACKED PEFCommandHeader; - - enum - { - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, - kPefInvalid = 0xFF, - }; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFContainer& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -std::ifstream& operator>>(std::ifstream& fp, - CompilerKit::PEFCommandHeader& container) -{ - fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/Headers/StdKit/Ref.hpp b/Headers/StdKit/Ref.hpp deleted file mode 100644 index 0f9c0e3..0000000 --- a/Headers/StdKit/Ref.hpp +++ /dev/null @@ -1,97 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -namespace CompilerKit -{ - // @author Amlal - // @brief Reference holder class, refers to a pointer of data in static memory. - template - class Ref final - { - public: - explicit Ref() = default; - - ~Ref() - { - if (m_Strong) - { - (*m_Class).~T(); - } - } - - public: - explicit Ref(T cls, const bool& strong = false) - : m_Class(&cls), m_Strong(strong) - { - } - - Ref& operator=(T ref) - { - m_Class = ref; - return *this; - } - - public: - T operator->() const - { - return m_Class; - } - - T& Leak() - { - return *m_Class; - } - - T operator*() - { - return *m_Class; - } - - bool IsStrong() const - { - return m_Strong; - } - - operator bool() - { - return *m_Class; - } - - private: - T* m_Class; - bool m_Strong{false}; - }; - - template - class NonNullRef final - { - public: - explicit NonNullRef() = delete; - - explicit NonNullRef(T* ref) - : m_Ref(ref, true) - { - } - - Ref& operator->() - { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef& ref) = delete; - NonNullRef(const NonNullRef& ref) = default; - - private: - Ref m_Ref{nullptr}; - }; -} // namespace CompilerKit diff --git a/Headers/StdKit/String.hpp b/Headers/StdKit/String.hpp deleted file mode 100644 index 59a7997..0000000 --- a/Headers/StdKit/String.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit -{ - /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - - class StringView final - { - public: - explicit StringView() = delete; - - explicit StringView(SizeType Sz) noexcept - : m_Sz(Sz) - { - m_Data = new char[Sz]; - assert(m_Data); - } - - ~StringView() noexcept - { - if (m_Data) - { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - MPCC_COPY_DEFAULT(StringView); - - CharType* Data(); - const CharType* CData() const; - SizeType Length() const; - - bool operator==(const CharType* rhs) const; - bool operator!=(const CharType* rhs) const; - - bool operator==(const StringView& rhs) const; - bool operator!=(const StringView& rhs) const; - - StringView& operator+=(const CharType* rhs); - StringView& operator+=(const StringView& rhs); - - operator bool() - { - return m_Data && m_Data[0] != 0; - } - - bool operator!() - { - return !m_Data || m_Data[0] == 0; - } - - private: - char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; - }; - - /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ - struct StringBuilder final - { - static StringView Construct(const CharType* data); - static const char* FromInt(const char* fmt, int n); - static const char* FromBool(const char* fmt, bool n); - static const char* Format(const char* fmt, const char* from); - static bool Equals(const char* lhs, const char* rhs); - }; -} // namespace CompilerKit diff --git a/Headers/StdKit/XCOFF.hxx b/Headers/StdKit/XCOFF.hxx deleted file mode 100644 index dbc258d..0000000 --- a/Headers/StdKit/XCOFF.hxx +++ /dev/null @@ -1,41 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - - File: XCOFF.hpp - Purpose: XCOFF for NewOS. - - Revision History: - - 04/07/24: Added file (amlel) - -------------------------------------------- */ - -#ifndef __XCOFF__ -#define __XCOFF__ - -#include - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit -{ - /// @brief XCoff identification header. - typedef struct XCoffFileHeader - { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header - } XCoffFileHeader; -} // namespace CompilerKit - -#endif // ifndef __XCOFF__ diff --git a/Headers/UUID.hpp b/Headers/UUID.hpp deleted file mode 100644 index 00b153b..0000000 --- a/Headers/UUID.hpp +++ /dev/null @@ -1,983 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus - -#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define LIBUUID_CPP20_OR_GREATER -#endif - -#endif - -#ifdef LIBUUID_CPP20_OR_GREATER -#include -#else -#include -#endif - -#ifdef _WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#ifdef UUID_TIME_GENERATOR -#include -#pragma comment(lib, "IPHLPAPI.lib") -#endif - -#elif defined(__linux__) || defined(__unix__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#elif defined(__APPLE__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#endif - -namespace uuids -{ -#ifdef __cpp_lib_span - template - using span = std::span; -#else - template - using span = gsl::span; -#endif - - namespace detail - { - template - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept - { - if (ch >= static_cast('0') && ch <= static_cast('9')) - return static_cast(ch - static_cast('0')); - if (ch >= static_cast('a') && ch <= static_cast('f')) - return static_cast(10 + ch - static_cast('a')); - if (ch >= static_cast('A') && ch <= static_cast('F')) - return static_cast(10 + ch - static_cast('A')); - return 0; - } - - template - [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast('0') && ch <= static_cast('9')) || - (ch >= static_cast('a') && ch <= static_cast('f')) || - (ch >= static_cast('A') && ch <= static_cast('F')); - } - - template - [[nodiscard]] constexpr std::basic_string_view to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template - [[nodiscard]] constexpr std::basic_string_view - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast(start); - const uint8_t* finish = static_cast(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast((bitCount >> 24) & 0xFF)); - process_byte(static_cast((bitCount >> 16) & 0xFF)); - process_byte(static_cast((bitCount >> 8) & 0xFF)); - process_byte(static_cast((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast(d32[0] >> 24); - digest[di++] = static_cast(d32[0] >> 16); - digest[di++] = static_cast(d32[0] >> 8); - digest[di++] = static_cast(d32[0] >> 0); - - digest[di++] = static_cast(d32[1] >> 24); - digest[di++] = static_cast(d32[1] >> 16); - digest[di++] = static_cast(d32[1] >> 8); - digest[di++] = static_cast(d32[1] >> 0); - - digest[di++] = static_cast(d32[2] >> 24); - digest[di++] = static_cast(d32[2] >> 16); - digest[di++] = static_cast(d32[2] >> 8); - digest[di++] = static_cast(d32[2] >> 0); - - digest[di++] = static_cast(d32[3] >> 24); - digest[di++] = static_cast(d32[3] >> 16); - digest[di++] = static_cast(d32[3] >> 8); - digest[di++] = static_cast(d32[3] >> 0); - - digest[di++] = static_cast(d32[4] >> 24); - digest[di++] = static_cast(d32[4] >> 16); - digest[di++] = static_cast(d32[4] >> 8); - digest[di++] = static_cast(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast(m_block[i * 4 + 0] << 24); - w[i] |= static_cast(m_block[i * 4 + 1] << 16); - w[i] |= static_cast(m_block[i * 4 + 2] << 8); - w[i] |= static_cast(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid[37] = - L"00000000-0000-0000-0000-000000000000"; - - template - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; - } // namespace detail - - // -------------------------------------------------------------------------------------------------------------------------- - // UUID format https://tools.ietf.org/html/rfc4122 - // -------------------------------------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------------------------------------- - // Field NDR Data Type Octet # Note - // -------------------------------------------------------------------------------------------------------------------------- - // time_low unsigned long 0 - 3 The low field - // of the timestamp. time_mid unsigned short 4 - 5 - // The middle field of the timestamp. time_hi_and_version unsigned - // short 6 - 7 The high field of the timestamp multiplexed - // with the version number. clock_seq_hi_and_reserved unsigned small 8 - // The high field of the clock sequence multiplexed with the variant. - // clock_seq_low unsigned small 9 The low - // field of the clock sequence. node character 10 - // - 15 The spatially unique node identifier. - // -------------------------------------------------------------------------------------------------------------------------- - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_low | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_mid | time_hi_and_version | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |clk_seq_hi_res | clk_seq_low | node (0-1) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | node (2-5) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // -------------------------------------------------------------------------------------------------------------------------- - // enumerations - // -------------------------------------------------------------------------------------------------------------------------- - - // indicated by a bit pattern in octet 8, marked with N in - // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx - enum class uuid_variant - { - // NCS backward compatibility (with the obsolete Apollo Network Computing - // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the - // UUID are a 48-bit timestamp (the number of 4 microsecond units of time - // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet - // is the "address family"; > the final 7 octets are a 56-bit host ID in the - // form specified by the address family - ncs, - - // RFC 4122/DCE 1.1 - // N bit pattern: 10xx - // > big-endian byte order - rfc, - - // Microsoft Corporation backward compatibility - // N bit pattern: 110x - // > little endian byte order - // > formely used in the Component Object Model (COM) library - microsoft, - - // reserved for possible future definition - // N bit pattern: 111x - reserved - }; - - // indicated by a bit pattern in octet 6, marked with M in - // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx - enum class uuid_version - { - none = 0, // only possible for nil or invalid uuids - time_based = 1, // The time-based version specified in RFC 4122 - dce_security = 2, // DCE Security version, with embedded POSIX UIDs. - name_based_md5 = - 3, // The name-based version specified in RFS 4122 with MD5 hashing - random_number_based = 4, // The randomly or pseudo-randomly generated version - // specified in RFS 4122 - name_based_sha1 = - 5 // The name-based version specified in RFS 4122 with SHA1 hashing - }; - - // Forward declare uuid & to_string so that we can declare to_string as a friend - // later. - class uuid; - template , class Allocator = std::allocator> - std::basic_string to_string(uuid const& id); - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid class - // -------------------------------------------------------------------------------------------------------------------------- - class uuid - { - public: - using value_type = uint8_t; - - constexpr uuid() noexcept = default; - - uuid(value_type (&arr)[16]) noexcept - { - std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); - } - - constexpr uuid(std::array const& arr) noexcept - : data{arr} - { - } - - explicit uuid(span bytes) - { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template - explicit uuid(ForwardIterator first, ForwardIterator last) - { - if (std::distance(first, last) == 16) - std::copy(first, last, std::begin(data)); - } - - [[nodiscard]] constexpr uuid_variant variant() const noexcept - { - if ((data[8] & 0x80) == 0x00) - return uuid_variant::ncs; - else if ((data[8] & 0xC0) == 0x80) - return uuid_variant::rfc; - else if ((data[8] & 0xE0) == 0xC0) - return uuid_variant::microsoft; - else - return uuid_variant::reserved; - } - - [[nodiscard]] constexpr uuid_version version() const noexcept - { - if ((data[6] & 0xF0) == 0x10) - return uuid_version::time_based; - else if ((data[6] & 0xF0) == 0x20) - return uuid_version::dce_security; - else if ((data[6] & 0xF0) == 0x30) - return uuid_version::name_based_md5; - else if ((data[6] & 0xF0) == 0x40) - return uuid_version::random_number_based; - else if ((data[6] & 0xF0) == 0x50) - return uuid_version::name_based_sha1; - else - return uuid_version::none; - } - - [[nodiscard]] constexpr bool is_nil() const noexcept - { - for (size_t i = 0; i < data.size(); ++i) - if (data[i] != 0) - return false; - return true; - } - - void swap(uuid& other) noexcept - { - data.swap(other.data); - } - - [[nodiscard]] inline span as_bytes() const - { - return span( - reinterpret_cast(data.data()), 16); - } - - template - [[nodiscard]] constexpr static bool is_valid_uuid( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) - return false; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template - [[nodiscard]] constexpr static std::optional from_string( - StringType const& in_str) noexcept - { - auto str = detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - std::array data{{0}}; - - if (str.empty()) - return {}; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !detail::is_hex(str[i])) - { - return {}; - } - - if (firstDigit) - { - data[index] = static_cast(detail::hex2char(str[i]) << 4); - firstDigit = false; - } - else - { - data[index] = - static_cast(data[index] | detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return {}; - } - - return uuid{data}; - } - - private: - std::array data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template - friend std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id); - - template - friend std::basic_string to_string(uuid const& id); - - friend std::hash; - }; - - // -------------------------------------------------------------------------------------------------------------------------- - // operators and non-member functions - // -------------------------------------------------------------------------------------------------------------------------- - - [[nodiscard]] inline bool operator==(uuid const& lhs, - uuid const& rhs) noexcept - { - return lhs.data == rhs.data; - } - - [[nodiscard]] inline bool operator!=(uuid const& lhs, - uuid const& rhs) noexcept - { - return !(lhs == rhs); - } - - [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept - { - return lhs.data < rhs.data; - } - - template - [[nodiscard]] inline std::basic_string to_string( - uuid const& id) - { - std::basic_string uustr{detail::empty_guid}; - - for (size_t i = 0, index = 0; i < 36; ++i) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - continue; - } - uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; - uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; - index++; - } - - return uustr; - } - - template - std::basic_ostream& operator<<( - std::basic_ostream& s, uuid const& id) - { - s << to_string(id); - return s; - } - - inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept - { - lhs.swap(rhs); - } - - // -------------------------------------------------------------------------------------------------------------------------- - // namespace IDs that could be used for generating name-based uuids - // -------------------------------------------------------------------------------------------------------------------------- - - // Name string is a fully-qualified domain name - static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is a URL - static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an ISO OID (See https://oidref.com/, - // https://en.wikipedia.org/wiki/Object_identifier) - static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an X.500 DN, in DER or a text output format (See - // https://en.wikipedia.org/wiki/X.500, - // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) - static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid generators - // -------------------------------------------------------------------------------------------------------------------------- - -#ifdef UUID_SYSTEM_GENERATOR - class uuid_system_generator - { - public: - using result_type = uuid; - - uuid operator()() - { -#ifdef _WIN32 - - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); - - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } - - std::array bytes = { - {static_cast((newId.Data1 >> 24) & 0xFF), - static_cast((newId.Data1 >> 16) & 0xFF), - static_cast((newId.Data1 >> 8) & 0xFF), - static_cast((newId.Data1) & 0xFF), - - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), - - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), - - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__linux__) || defined(__unix__) - - uuid_t id; - uuid_generate(id); - - std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], - id[6], id[7], id[8], id[9], id[10], - id[11], id[12], id[13], id[14], id[15]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array arrbytes = { - {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, - bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, - bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, - bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; -#else - return uuid{}; -#endif - } - }; -#endif - - template - class basic_uuid_random_generator - { - public: - using engine_type = UniformRandomNumberGenerator; - - explicit basic_uuid_random_generator(engine_type& gen) - : generator(&gen, [](auto) {}) - { - } - explicit basic_uuid_random_generator(engine_type* gen) - : generator(gen, [](auto) {}) - { - } - - [[nodiscard]] uuid operator()() - { - alignas(uint32_t) uint8_t bytes[16]; - for (int i = 0; i < 16; i += 4) - *reinterpret_cast(bytes + i) = distribution(*generator); - - // variant must be 10xxxxxx - bytes[8] &= 0xBF; - bytes[8] |= 0x80; - - // version must be 0100xxxx - bytes[6] &= 0x4F; - bytes[6] |= 0x40; - - return uuid{std::begin(bytes), std::end(bytes)}; - } - - private: - std::uniform_int_distribution distribution; - std::shared_ptr generator; - }; - - using uuid_random_generator = basic_uuid_random_generator; - - class uuid_name_generator - { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept - : nsuuid(namespace_uuid) - { - } - - template - [[nodiscard]] uuid operator()(StringType const& name) - { - reset(); - process_characters(detail::to_string_view(name)); - return make_uuid(); - } - - private: - void reset() - { - hasher.reset(); - std::byte bytes[16]; - auto nsbytes = nsuuid.as_bytes(); - std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); - hasher.process_bytes(bytes, 16); - } - - template - void process_characters(std::basic_string_view const str) - { - for (uint32_t c : str) - { - hasher.process_byte(static_cast(c & 0xFF)); - if constexpr (!std::is_same_v) - { - hasher.process_byte(static_cast((c >> 8) & 0xFF)); - hasher.process_byte(static_cast((c >> 16) & 0xFF)); - hasher.process_byte(static_cast((c >> 24) & 0xFF)); - } - } - } - - [[nodiscard]] uuid make_uuid() - { - detail::sha1::digest8_t digest; - hasher.get_digest_bytes(digest); - - // variant must be 0b10xxxxxx - digest[8] &= 0xBF; - digest[8] |= 0x80; - - // version must be 0b0101xxxx - digest[6] &= 0x5F; - digest[6] |= 0x50; - - return uuid{digest, digest + 16}; - } - - private: - uuid nsuuid; - detail::sha1 hasher; - }; - -#ifdef UUID_TIME_GENERATOR - // !!! DO NOT USE THIS IN PRODUCTION - // this implementation is unreliable for good uuids - class uuid_time_generator - { - using mac_address = std::array; - - std::optional device_address; - - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } - -#ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) - return false; - std::vector buf(len); - auto pips = reinterpret_cast(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) - return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; -#endif - - return device_address.has_value(); - } - - [[nodiscard]] long long get_time_intervals() - { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = - std::chrono::duration_cast(diff).count(); - return ns / 100; - } - - [[nodiscard]] static unsigned short get_clock_sequence() - { - static std::mt19937 clock_gen(std::random_device{}()); - static std::uniform_int_distribution clock_dis; - static std::atomic_ushort clock_sequence = clock_dis(clock_gen); - return clock_sequence++; - } - - public: - [[nodiscard]] uuid operator()() - { - if (get_mac_address()) - { - std::array data; - - auto tm = get_time_intervals(); - - auto clock_seq = get_clock_sequence(); - - auto ptm = reinterpret_cast(&tm); - - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); - - memcpy(&data[8], &clock_seq, 2); - - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; - - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; - - memcpy(&data[10], &device_address.value()[0], 6); - - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } - - return {}; - } - }; -#endif -} // namespace uuids - -namespace std -{ - template <> - struct hash - { - using argument_type = uuids::uuid; - using result_type = std::size_t; - - [[nodiscard]] result_type operator()(argument_type const& uuid) const - { -#ifdef UUID_HASH_STRING_BASED - std::hash hasher; - return static_cast(hasher(uuids::to_string(uuid))); -#else - uint64_t l = static_cast(uuid.data[0]) << 56 | - static_cast(uuid.data[1]) << 48 | - static_cast(uuid.data[2]) << 40 | - static_cast(uuid.data[3]) << 32 | - static_cast(uuid.data[4]) << 24 | - static_cast(uuid.data[5]) << 16 | - static_cast(uuid.data[6]) << 8 | - static_cast(uuid.data[7]); - uint64_t h = static_cast(uuid.data[8]) << 56 | - static_cast(uuid.data[9]) << 48 | - static_cast(uuid.data[10]) << 40 | - static_cast(uuid.data[11]) << 32 | - static_cast(uuid.data[12]) << 24 | - static_cast(uuid.data[13]) << 16 | - static_cast(uuid.data[14]) << 8 | - static_cast(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) - { - return result_type(l ^ h); - } - else - { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } -#endif - } - }; -} // namespace std - -#endif /* STDUUID_H */ \ No newline at end of file diff --git a/Headers/Version.hxx b/Headers/Version.hxx deleted file mode 100644 index 639c2c6..0000000 --- a/Headers/Version.hxx +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define kDistVersion "v1.22" diff --git a/NDKKit/AsmKit/AsmKit.hpp b/NDKKit/AsmKit/AsmKit.hpp new file mode 100644 index 0000000..6074efc --- /dev/null +++ b/NDKKit/AsmKit/AsmKit.hpp @@ -0,0 +1,217 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include +#include + +namespace CompilerKit +{ + // + // @brief Frontend to Assembly mountpoint. + // + class AssemblyInterface + { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + MPCC_COPY_DEFAULT(AssemblyInterface); + + //@ brief compile to object file. + // Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; + }; + + /// @brief Simple assembly factory + class AssemblyFactory final + { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + MPCC_COPY_DEFAULT(AssemblyFactory); + + public: + enum + { + kArchAMD64, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchUnknown, + }; + + Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; + }; + + union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; + }; + + union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) + : raw(raw) + { + } + ~NumberCast64() + { + raw = 0; + } + + CharType number[8]; + UInt64 raw; + }; + + union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) + : raw(raw) + { + } + ~NumberCast32() + { + raw = 0; + } + + CharType number[4]; + UInt32 raw; + }; + + union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) + : raw(raw) + { + } + ~NumberCast16() + { + raw = 0; + } + + CharType number[2]; + UInt16 raw; + }; + + union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) + : raw(raw) + { + } + ~NumberCast8() + { + raw = 0; + } + + CharType number; + UInt8 raw; + }; + + class EncoderInterface + { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + MPCC_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string& line, const std::string& file) = 0; + virtual bool WriteLine(std::string& line, const std::string& file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; + }; + +#ifdef __ASM_NEED_AMD64__ + + class EncoderAMD64 final : public EncoderInterface + { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; + + MPCC_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + + virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); + }; + +#endif // __ASM_NEED_AMD64__ + +#ifdef __ASM_NEED_64x0__ + + class Encoder64x0 final : public EncoderInterface + { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + MPCC_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_64x0__ + +#ifdef __ASM_NEED_32x0__ + + class Encoder32x0 final : public EncoderInterface + { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; + + MPCC_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ + +#ifdef __ASM_NEED_PPC__ + + class EncoderPowerPC final : public EncoderInterface + { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; + + MPCC_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string& line, + const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, + std::string& from_what) override; + }; + +#endif // __ASM_NEED_32x0__ +} // namespace CompilerKit diff --git a/NDKKit/AsmKit/CPU/32x0.hpp b/NDKKit/AsmKit/CPU/32x0.hpp new file mode 100644 index 0000000..7fa02ad --- /dev/null +++ b/NDKKit/AsmKit/CPU/32x0.hpp @@ -0,0 +1,95 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @brief 32x0 support. +// @file CPU/32x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 + +#define kAsmByte 0 +#define kAsmHWord 1 +#define kAsmWord 2 + +struct CpuCode32x0 +{ + const char fName[32]; + char fOpcode; + char fSize; + char fFunct3; + char fFunct7; +}; + +#define kAsmDWordStr ".dword" /* 64 bit */ +#define kAsmWordStr ".word" /* 32-bit */ +#define kAsmHWordStr ".half" /* 16-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ + +inline std::vector kOpcodes32x0 = { + kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. + kAsmOpcodeDecl("br", 0b1110011, 0b001, kAsmJump) // jump to branch + kAsmOpcodeDecl("mr", 0b0100011, 0b101, kAsmImmediate) // move registers + kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp + kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. + kAsmOpcodeDecl("cls", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR. + kAsmOpcodeDecl("rts", 0b0111011, 0b110, + kAsmImmediate) // pull stack and return form CR. + kAsmOpcodeDecl("int", 0b0111111, 0b000, kAsmSyscall) // raise interrupt +}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: TODO: find one +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/NDKKit/AsmKit/CPU/64x0.hpp b/NDKKit/AsmKit/CPU/64x0.hpp new file mode 100644 index 0000000..3bd1f80 --- /dev/null +++ b/NDKKit/AsmKit/CPU/64x0.hpp @@ -0,0 +1,108 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +// @brief 64x0 support. +// @file CPU/64x0.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, \ + .fOpcode = __OPCODE, \ + .fFunct3 = __FUNCT3, \ + .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 + +typedef char e64k_character_t; +typedef uint8_t e64k_num_t; + +struct CpuOpcode64x0 +{ + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; +}; + +inline std::vector kOpcodes64x0 = { + kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) + kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("int", 0b1110011, 0b00, kAsmSyscall) + kAsmOpcodeDecl("pha", 0b1110011, 0b00, kAsmNoArgs) + kAsmOpcodeDecl("pla", 0b1110011, 0b01, kAsmNoArgs)}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL/JUMP ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/NDKKit/AsmKit/CPU/amd64.hpp b/NDKKit/AsmKit/CPU/amd64.hpp new file mode 100644 index 0000000..3edd5ca --- /dev/null +++ b/NDKKit/AsmKit/CPU/amd64.hpp @@ -0,0 +1,57 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @brief AMD64 support. +// @file CPU/amd64.hpp + +#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, + +typedef char i64_character_t; +typedef uint8_t i64_byte_t; +typedef uint16_t i64_hword_t; +typedef uint32_t i64_word_t; + +struct CpuOpcodeAMD64 +{ + std::string fName; + i64_byte_t fPrefixBytes[4]; + i64_hword_t fOpcode; + i64_hword_t fModReg; + i64_word_t fDisplacment; + i64_word_t fImmediate; +}; + +/// these two are edge cases +#define kAsmIntOpcode 0xCC +#define kasmIntOpcodeAlt 0xCD + +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 +#define kJumpLimitStandardLimit 0xEB + +inline std::vector kOpcodesAMD64 = { + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF) +}; + +#define kAsmRegisterLimit 15 diff --git a/NDKKit/AsmKit/CPU/arm64.hpp b/NDKKit/AsmKit/CPU/arm64.hpp new file mode 100644 index 0000000..a63ddfb --- /dev/null +++ b/NDKKit/AsmKit/CPU/arm64.hpp @@ -0,0 +1,26 @@ +/* ------------------------------------------- + +Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +/// @brief ARM64 encoding support. +/// @file CPU/arm64.hpp + +struct CpuOpcodeArm64; + +/// @brief ARM64 opcode header. +struct CpuOpcodeArm64 final +{ + uint8_t fOpcode; // opcode + uint8_t fRegisterLeft; // left register index + uint8_t fRegisterRight; // right register index + bool fRegisterLeftHooked; + bool fRegisterRightHooked; + uint32_t fImmediateValue; // immediate 32-bit value + bool fImmediateValueHooked; +}; diff --git a/NDKKit/AsmKit/CPU/ppc.hpp b/NDKKit/AsmKit/CPU/ppc.hpp new file mode 100644 index 0000000..e3ea6c5 --- /dev/null +++ b/NDKKit/AsmKit/CPU/ppc.hpp @@ -0,0 +1,1929 @@ +/* ------------------------------------------- + + Some modifications are copyrighted under: + ZKA Technologies + + Original author: + Apple Inc + +------------------------------------------- */ + +#pragma once + +#include + +/// @note Based of: +/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html + +/* + * These defines are use in the cpus field of the instructions. If the field + * is zero it can execute on all cpus. The defines are or'ed together. This + * information is used to set the cpusubtype in the resulting object file. + */ +#define CPU601 0x1 +#define IMPL64 0x2 +#define OPTIONAL 0x4 +#define VMX 0x8 +#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ +#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ + +enum optype +{ + NONE, /* no operand */ + JBSR, /* jbsr pseudo op */ + PCREL, /* PC relative (branch offset) */ + BADDR, /* Branch address (sign extended absolute address) */ + D, /* 16 bit displacement */ + DS, /* 14 bit displacement (double word) */ + SI, /* signed 16 bit immediate */ + UI, /* unsigned 16 bit immediate */ + HI, /* high 16 bit immediate (with truncation) */ + GREG, /* general register */ + G0REG, /* general register r1-r31 or 0 */ + FREG, /* float register */ + VREG, /* vector register */ + SGREG, /* segment register */ + SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ + BCND, /* branch condition opcode */ + CRF, /* condition register field */ + CRFONLY, /* condition register field only no expression allowed */ + sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ + mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ + NUM, /* number */ + SNUM, /* signed number */ + NUM0, /* number (where 1< + +#define SizeType size_t + +#define VoidPtr void* +#define voidPtr VoidPtr + +#define UIntPtr uintptr_t + +#define Int64 int64_t +#define UInt64 uint64_t + +#define Int32 int +#define UInt32 unsigned + +#define Bool bool + +#define Int16 int16_t +#define UInt16 uint16_t + +#define Int8 int8_t +#define UInt8 uint8_t + +#define CharType char +#define Boolean bool + +#include +#include +#include + +#define nullPtr std::nullptr_t + +#define MUST_PASS(E) assert(E) + +#ifndef __FORCE_STRLEN +#define __FORCE_STRLEN 1 + +#define string_length(len) strlen(len) +#endif + +#ifndef __FORCE_MEMCPY +#define __FORCE_MEMCPY 1 + +#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) +#endif + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#include +#include +#include +#include + +namespace CompilerKit +{ + inline constexpr int BASE_YEAR = 1900; + + inline std::string current_date() noexcept + { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); + + std::string fmt = std::to_string(BASE_YEAR + time_struct->tm_year); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); + + return fmt; + } + + inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept + { + if (limit == 0) + return false; + + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; + + while (limit != 1) + { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; + } +} // namespace CompilerKit + +#define PACKED __attribute__((packed)) + +typedef char char_type; + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts \ + { \ + ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ + } + +#ifdef __NDK_MODULE__ +#define NDK_MODULE(name) int name(int argc, char** argv) +#else +#define NDK_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __NDK_MODULE__ */ + +#pragma scalar_storage_order big-endian + +#endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/NDKKit/Macros.hpp b/NDKKit/Macros.hpp new file mode 100644 index 0000000..c190cda --- /dev/null +++ b/NDKKit/Macros.hpp @@ -0,0 +1,33 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// @brief provide support for Macros.hpp header. + +#ifndef _CK_CL_HPP +#define _CK_CL_HPP + +#define MPCC_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define MPCC_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define MPCC_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define MPCC_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +/// @note xxxx is the error placeholder, in hexadecimal. +#define MPCC_ERROR_PREFIX_CXX "CXXxxxx" +#define MPCC_ERROR_PREFIX_CL "CLxxxx" +#define MPCC_ERROR_PREFIX_ASM "ASMxxxx" + +#endif /* ifndef _CK_CL_HPP */ diff --git a/NDKKit/NFC/AE.hpp b/NDKKit/NFC/AE.hpp new file mode 100644 index 0000000..1c929f9 --- /dev/null +++ b/NDKKit/NFC/AE.hpp @@ -0,0 +1,143 @@ +/* + * ======================================================== + * + * NDK + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include + +#define kAEMag0 'A' +#define kAEMag1 'E' + +#define kAESymbolLen 64 +#define kAEPad 8 +#define kAEMagLen 2 +#define kAEInvalidOpcode 0x00 + +// Advanced Executable File Format for MetroLink. +// Reloctable by offset is the default strategy. +// You can also relocate at runtime but that's up to the operating system +// loader. + +namespace CompilerKit +{ + // @brief Advanced Executable Header + // One thing to keep in mind. + // This object format, is reloctable. + typedef struct AEHeader final + { + CharType fMagic[kAEMagLen]; + CharType fArch; + CharType fSubArch; + SizeType fCount; + CharType fSize; + SizeType fStartCode; + SizeType fCodeSize; + CharType fPad[kAEPad]; + } PACKED AEHeader, *AEHeaderPtr; + + // @brief Advanced Executable Record. + // Could be data, code or bss. + // fKind must be filled with PEF fields. + + typedef struct AERecordHeader final + { + CharType fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + CharType fPad[kAEPad]; + } PACKED AERecordHeader, *AERecordHeaderPtr; + + enum + { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, + }; +} // namespace CompilerKit + +// provide operator<< for AE + +std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AEHeader)); + + return fp; +} + +std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::AERecordHeader)); + + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AEHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::AERecordHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::AERecordHeader)); + return fp; +} + +namespace CompilerKit::Utils +{ + /** + * @brief AE Reader protocol + * + */ + class AEReadableProtocol final + { + public: + std::ifstream FP; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + MPCC_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) + { + if (!raw) + return nullptr; + + return this->_Read(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template + TypeClass* _Read(char* raw, std::size_t sz) + { + FP.read(raw, std::streamsize(sz)); + return reinterpret_cast(raw); + } + }; +} // namespace CompilerKit::Utils diff --git a/NDKKit/NFC/ELF.hpp b/NDKKit/NFC/ELF.hpp new file mode 100644 index 0000000..4f0d0ae --- /dev/null +++ b/NDKKit/NFC/ELF.hpp @@ -0,0 +1,389 @@ +#pragma once + +#include +#include + +struct file; + +#ifndef elf_read_implies_exec +/* Executables for which elf_read_implies_exec() returns TRUE will + have the READ_IMPLIES_EXEC personality flag set automatically. + Override in asm/elf.h as needed. */ +#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 +#endif + +/* 32-bit ELF base types. */ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + +/* 64-bit ELF base types. */ +typedef uintptr_t Elf64_Addr; +typedef uint16_t Elf64_Half; +typedef int16_t Elf64_SHalf; +typedef uint64_t Elf64_Off; +typedef int32_t Elf64_Sword; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* These constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff +#define PT_GNU_EH_FRAME 0x6474e550 + +#define PT_GNU_STACK (PT_LOOS + 0x474e551) + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_ENCODING 32 +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6ffff000 +#define DT_VALRNGLO 0x6ffffd00 +#define DT_VALRNGHI 0x6ffffdff +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_VERSYM 0x6ffffff0 +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff +#define OLD_DT_HIOS 0x6fffffff +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_COMMON 5 +#define STT_TLS 6 + +#define ELF_ST_BIND(x) ((x) >> 4) +#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf) +#define ELF32_ST_BIND(x) ELF_ST_BIND(x) +#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) +#define ELF64_ST_BIND(x) ELF_ST_BIND(x) +#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) + +typedef struct dynamic +{ + Elf32_Sword d_tag; + union { + Elf32_Sword d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* entry tag value */ + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + +/* The following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x)&0xff) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffff) + +typedef struct elf32_rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +} Elf32_Rel; + +typedef struct elf64_rel +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ +} Elf64_Rel; + +typedef struct elf32_rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +} Elf32_Rela; + +typedef struct elf64_rela +{ + Elf64_Addr r_offset; /* Location at which to apply the action */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + +typedef struct elf32_sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +typedef struct elf64_sym +{ + Elf64_Word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + Elf64_Half st_shndx; /* Associated section index */ + Elf64_Addr st_value; /* Value of the symbol */ + Elf64_Xword st_size; /* Associated symbol size */ +} Elf64_Sym; + +#define EI_NIDENT 16 + +typedef struct elf32_hdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; /* Entry point */ + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +} Elf32_Ehdr; + +typedef struct elf64_hdr +{ + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; +} Elf64_Ehdr; + +/* These constants define the permissions on sections in the program + header, p_flags. */ +#define PF_R 0x4 +#define PF_W 0x2 +#define PF_X 0x1 + +typedef struct elf32_phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +typedef struct elf64_phdr +{ + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + +/* sh_type */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_NUM 12 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xffffffff + +/* sh_flags */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* special section indexes */ +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + +typedef struct +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +} Elf32_Shdr; + +typedef struct elf64_shdr +{ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +#define EI_MAG0 0 /* e_ident[] indexes */ +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_PAD 8 + +#define ELFMAG0 0x7f /* EI_MAG */ +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define ELFCLASSNONE 0 /* EI_CLASS */ +#define ELFCLASS32 1 +#define ELFCLASS64 2 +#define ELFCLASSNUM 3 + +#define ELFDATANONE 0 /* e_ident[EI_DATA] */ +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_NONE 0 /* e_version, EI_VERSION */ +#define EV_CURRENT 1 +#define EV_NUM 2 + +#define ELFOSABI_NONE 0 +#define ELFOSABI_LINUX 3 + +#ifndef ELF_OSABI +#define ELF_OSABI ELFOSABI_NONE +#endif + +/* Notes used in ET_CORE */ +#define NT_PRSTATUS 1 +#define NT_PRFPREG 2 +#define NT_PRPSINFO 3 +#define NT_TASKSTRUCT 4 +#define NT_AUXV 6 +#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ +#define NT_PPC_VMX 0x100 /* POWER Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* POWER SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* POWER VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_PRXSTATUS 0x300 /* s390 upper register halves */ + +/* Note header in a PT_NOTE section */ +typedef struct elf32_note +{ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ +} Elf32_Nhdr; + +/* Note header in a PT_NOTE section */ +typedef struct elf64_note +{ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ +} Elf64_Nhdr; diff --git a/NDKKit/NFC/ErrorID.hpp b/NDKKit/NFC/ErrorID.hpp new file mode 100644 index 0000000..c45b4b0 --- /dev/null +++ b/NDKKit/NFC/ErrorID.hpp @@ -0,0 +1,22 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +#define MPCC_EXEC_ERROR -30 +#define MPCC_FILE_NOT_FOUND -31 +#define MPCC_DIR_NOT_FOUND -32 +#define MPCC_FILE_EXISTS -33 +#define MPCC_TOO_LONG -34 +#define MPCC_INVALID_DATA -35 +#define MPCC_UNIMPLEMENTED -36 +#define MPCC_FAT_ERROR -37 diff --git a/NDKKit/NFC/ErrorOr.hpp b/NDKKit/NFC/ErrorOr.hpp new file mode 100644 index 0000000..ed134a7 --- /dev/null +++ b/NDKKit/NFC/ErrorOr.hpp @@ -0,0 +1,61 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + using ErrorT = UInt32; + + template + class ErrorOr final + { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) + : mId(err) + { + } + + explicit ErrorOr(nullPtr Null) + { + } + + explicit ErrorOr(T Class) + : mRef(Class) + { + } + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref Leak() + { + return mRef; + } + + operator bool() + { + return mRef; + } + + private: + Ref mRef; + Int32 mId{0}; + }; + + using ErrorOrAny = ErrorOr; + +} // namespace CompilerKit diff --git a/NDKKit/NFC/PEF.hpp b/NDKKit/NFC/PEF.hpp new file mode 100644 index 0000000..2f460b7 --- /dev/null +++ b/NDKKit/NFC/PEF.hpp @@ -0,0 +1,134 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +// @file PEF.hpp +// @brief Preferred Executable Format + +#define kPefMagic "Joy!" +#define kPefMagicFat "yoJ!" + +#define kPefExt ".exec" +#define kPefDylibExt ".lib" +#define kPefLibExt ".slib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" + +#define kPefMagicLen 5 + +#define kPefVersion 2 +#define kPefNameLen 255 + +#define kPefBaseOrigin (0x1000000) + +#define kPefStart "__ImageStart" + +namespace CompilerKit +{ + enum + { + kPefArchStart = 99, + kPefArchIntel86S = 100, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* 64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, + }; + + enum + { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchGeneric, + kPefSubArchIBM, + }; + + enum + { + kPefKindExec = 1, /* .exe */ + kPefKindSharedObject = 2, /* .lib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, + }; + + /* PEF container */ + typedef struct PEFContainer final + { + CharType Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ + } PACKED PEFContainer; + + /* First PEFCommandHeader starts after PEFContainer */ + /* Last container is __exec_end */ + + /* PEF executable section and commands. */ + + typedef struct PEFCommandHeader final + { + CharType Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* file offset */ + SizeType Size; /* file size */ + } PACKED PEFCommandHeader; + + enum + { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, + kPefInvalid = 0xFF, + }; +} // namespace CompilerKit + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.write((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFContainer& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +std::ifstream& operator>>(std::ifstream& fp, + CompilerKit::PEFCommandHeader& container) +{ + fp.read((char*)&container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} diff --git a/NDKKit/NFC/Ref.hpp b/NDKKit/NFC/Ref.hpp new file mode 100644 index 0000000..0f9c0e3 --- /dev/null +++ b/NDKKit/NFC/Ref.hpp @@ -0,0 +1,97 @@ + +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +namespace CompilerKit +{ + // @author Amlal + // @brief Reference holder class, refers to a pointer of data in static memory. + template + class Ref final + { + public: + explicit Ref() = default; + + ~Ref() + { + if (m_Strong) + { + (*m_Class).~T(); + } + } + + public: + explicit Ref(T cls, const bool& strong = false) + : m_Class(&cls), m_Strong(strong) + { + } + + Ref& operator=(T ref) + { + m_Class = ref; + return *this; + } + + public: + T operator->() const + { + return m_Class; + } + + T& Leak() + { + return *m_Class; + } + + T operator*() + { + return *m_Class; + } + + bool IsStrong() const + { + return m_Strong; + } + + operator bool() + { + return *m_Class; + } + + private: + T* m_Class; + bool m_Strong{false}; + }; + + template + class NonNullRef final + { + public: + explicit NonNullRef() = delete; + + explicit NonNullRef(T* ref) + : m_Ref(ref, true) + { + } + + Ref& operator->() + { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef& ref) = delete; + NonNullRef(const NonNullRef& ref) = default; + + private: + Ref m_Ref{nullptr}; + }; +} // namespace CompilerKit diff --git a/NDKKit/NFC/String.hpp b/NDKKit/NFC/String.hpp new file mode 100644 index 0000000..200bf2c --- /dev/null +++ b/NDKKit/NFC/String.hpp @@ -0,0 +1,90 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + /** + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + + class StringView final + { + public: + explicit StringView() = delete; + + explicit StringView(SizeType Sz) noexcept + : m_Sz(Sz) + { + m_Data = new char[Sz]; + assert(m_Data); + } + + ~StringView() noexcept + { + if (m_Data) + { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + MPCC_COPY_DEFAULT(StringView); + + CharType* Data(); + const CharType* CData() const; + SizeType Length() const; + + bool operator==(const CharType* rhs) const; + bool operator!=(const CharType* rhs) const; + + bool operator==(const StringView& rhs) const; + bool operator!=(const StringView& rhs) const; + + StringView& operator+=(const CharType* rhs); + StringView& operator+=(const StringView& rhs); + + operator bool() + { + return m_Data && m_Data[0] != 0; + } + + bool operator!() + { + return !m_Data || m_Data[0] == 0; + } + + private: + char* m_Data{nullptr}; + SizeType m_Sz{0}; + SizeType m_Cur{0}; + + friend class StringBuilder; + }; + + /** + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ + struct StringBuilder final + { + static StringView Construct(const CharType* data); + static const char* FromInt(const char* fmt, int n); + static const char* FromBool(const char* fmt, bool n); + static const char* Format(const char* fmt, const char* from); + static bool Equals(const char* lhs, const char* rhs); + }; +} // namespace CompilerKit diff --git a/NDKKit/NFC/XCOFF.hxx b/NDKKit/NFC/XCOFF.hxx new file mode 100644 index 0000000..57ecfd2 --- /dev/null +++ b/NDKKit/NFC/XCOFF.hxx @@ -0,0 +1,41 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + + File: XCOFF.hpp + Purpose: XCOFF for NewOS. + + Revision History: + + 04/07/24: Added file (amlel) + +------------------------------------------- */ + +#ifndef __XCOFF__ +#define __XCOFF__ + +#include + +#define kXCOFF64Magic 0x01F7 + +#define kXCOFFRelFlg 0x0001 +#define kXCOFFExecutable 0x0002 +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace CompilerKit +{ + /// @brief XCoff identification header. + typedef struct XCoffFileHeader + { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header + } XCoffFileHeader; +} // namespace CompilerKit + +#endif // ifndef __XCOFF__ diff --git a/NDKKit/Parser.hpp b/NDKKit/Parser.hpp new file mode 100644 index 0000000..c67057d --- /dev/null +++ b/NDKKit/Parser.hpp @@ -0,0 +1,178 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +namespace CompilerKit +{ + inline auto cInvalidLang = "?"; + + /// @brief Compiler backend, implements a frontend, such as C, C++... + /// See Toolchain, for some examples. + class CompilerBackend + { + public: + explicit CompilerBackend() = default; + virtual ~CompilerBackend() = default; + + MPCC_COPY_DEFAULT(CompilerBackend); + + // NOTE: cast this to your user defined ast. + typedef void* AstType; + + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + + virtual bool Compile(const std::string& text, const char* file) = 0; + + //! @brief What language are we dealing with? + virtual const char* Language() + { + return cInvalidLang; + } + + virtual bool IsValid() + { + return strcmp(this->Language(), cInvalidLang); + } + }; + + struct SyntaxLeafList; + struct SyntaxLeafList; + struct CompilerKeyword; + + /// we want to do that because to separate keywords. + enum KeywordKind + { + eKeywordKindNamespace, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, + eKeywordKindVariable, + eKeywordKindVariablePtr, + eKeywordKindType, + eKeywordKindTypePtr, + eKeywordKindExpressionBegin, + eKeywordKindExpressionEnd, + eKeywordKindArgSeparator, + eKeywordKindBodyStart, + eKeywordKindBodyEnd, + eKeywordKindClass, + eKeywordKindPtrAccess, + eKeywordKindAccess, + eKeywordKindIf, + eKeywordKindElse, + eKeywordKindElseIf, + eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, + eKeywordKindConstant, + eKeywordKindTypedef, + eKeywordKindEndInstr, + eKeywordKindSpecifier, + eKeywordKindInvalid, + eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, + }; + + /// \brief Compiler keyword information struct. + struct CompilerKeyword + { + std::string keyword_name; + KeywordKind keyword_kind = eKeywordKindInvalid; + }; + struct SyntaxLeafList final + { + struct SyntaxLeaf final + { + Int32 fUserType; +#ifdef __PK_USE_STRUCT_INSTEAD__ + CompilerKeyword fUserData; +#else + std::string fUserData; +#endif + + std::string fUserValue; + struct SyntaxLeaf* fNext; + }; + + std::vector fLeafList; + SizeType fNumLeafs; + + size_t SizeOf() + { + return fNumLeafs; + } + std::vector& Get() + { + return fLeafList; + } + SyntaxLeaf& At(size_t index) + { + return fLeafList[index]; + } + }; + + /// find the perfect matching word in a haystack. + /// \param haystack base string + /// \param needle the string we search for. + /// \return if we found it or not. + inline bool find_word(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) + return true; + + if (index < 0 || index >= haystack.size()) + return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); + } + + /// find a word within strict conditions and returns a range of it. + /// \param haystack + /// \param needle + /// \return position of needle. + inline std::size_t find_word_range(const std::string& haystack, + const std::string& needle) noexcept + { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) + return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) + { + return index; + } + + return false; + } +} // namespace CompilerKit diff --git a/NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx b/NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx new file mode 100644 index 0000000..02b3123 --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx @@ -0,0 +1,15 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +typedef void* ptr_type; +typedef __SIZE_TYPE__ size_type; + +inline void* __mpcc_alloca_gcc(size_type sz) +{ + return __builtin_alloca(sz); +} diff --git a/NDKKit/Public/SDK/CRT/__mpcc_defines.hxx b/NDKKit/Public/SDK/CRT/__mpcc_defines.hxx new file mode 100644 index 0000000..19ed8a4 --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_defines.hxx @@ -0,0 +1,83 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#ifndef __MPCC_DEF__ +#define __MPCC_DEF__ + +#ifndef __GNUC__ + +typedef __SIZE_TYPE__ size_t; + +#ifdef __LP64__ +typedef long int ssize_t; +#else +typedef int ssize_t; +#endif // __LP64__ + +typedef size_t ptrdiff_t; +typedef size_t uintptr_t; +typedef void* voidptr_t; +typedef void* any_t; +typedef char* caddr_t; + +#ifndef NULL +#define NULL ((voidptr_t)0) +#endif // !null + +#ifdef __GNUC__ +#include +#define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#define __packed__ __attribute__((packed)) +#elif defined(__MPCC__) +#define __packed__ __mpcc_packed__ +#define __alloca(sz) __mpcc_alloca(sz) +#endif + +#define __deref(ptr) (*(ptr)) + +#ifdef __cplusplus +#define __init_decl() \ + extern "C" \ + { + + +#define __fini_decl() \ + }; \ + + +#else +#define __init_decl() +#define __fini_decl() +#endif + +typedef long long off_t; +typedef unsigned long long uoff_t; + +typedef union float_cast { + struct + { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int sign : 1; + }; + + float f; +} __packed__ float_cast_t; + +typedef union double_cast { + struct + { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; +} __packed__ double_cast_t; + +#endif // ifndef __GNUC__ + +#endif /* __MPCC_DEF__ */ diff --git a/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx b/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx new file mode 100644 index 0000000..dac42ad --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +/// This file is an implementation of __throw* family of functions. + +#include +#include +#include + +namespace std +{ + inline void __throw_general(void) + { + throw std::runtime_error("NDK C++ Runtime error."); + } + + inline void __throw_domain_error(const char* error) + { + std::cout << "NDK C++: Domain error: " << error << "\r"; + __throw_general(); + } +} // namespace std diff --git a/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx b/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx new file mode 100644 index 0000000..02dbc94 --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#pragma compiler(hint_manifest) + +#define _Input +#define _Output + +#define _Optional + +#define _StrictCheckInput +#define _StrictCheckOutput + +#define _InOut +#define _StrictInOut diff --git a/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx b/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx new file mode 100644 index 0000000..eeaa67b --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include + +namespace stdx +{ + /// @brief allocate a new class. + /// @tparam KindClass the class type to allocate. + template + inline void* allocate(Args&&... args) + { + return new KindClass(std::forward(args)...); + } + + /// @brief free a class. + /// @tparam KindClass the class type to allocate. + template + inline void release(KindClass ptr) + { + if (!ptr) + return; + delete ptr; + } +} // namespace stdx diff --git a/NDKKit/Public/SDK/CRT/__mpcc_power.inc b/NDKKit/Public/SDK/CRT/__mpcc_power.inc new file mode 100644 index 0000000..90b1364 --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_power.inc @@ -0,0 +1,35 @@ +# Path: SDK/__mpcc_power.inc +# Language: NDK POWER Assembly support for GNU. +# Build Date: 2024-6-4 + +%ifdef __CODETOOLS__ + +%def lda li +%def sta stw +%def ldw li + +%def r0 0 +%def r1 1 +%def r2 2 +%def r3 3 +%def r4 4 +%def r5 5 +%def r6 6 +%def r7 7 +%def r8 8 +%def r9 9 +%def r10 10 +%def r11 11 +%def r12 12 +%def r13 13 +%def r14 14 +%def r15 15 +%def r16 16 +%def r17 17 +%def r18 18 +%def r19 19 +%def r20 20 + +%endif + +%def nop mr 0, 0 diff --git a/NDKKit/UUID.hpp b/NDKKit/UUID.hpp new file mode 100644 index 0000000..00b153b --- /dev/null +++ b/NDKKit/UUID.hpp @@ -0,0 +1,983 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define LIBUUID_CPP20_OR_GREATER +#endif + +#endif + +#ifdef LIBUUID_CPP20_OR_GREATER +#include +#else +#include +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#ifdef UUID_TIME_GENERATOR +#include +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#endif + +namespace uuids +{ +#ifdef __cpp_lib_span + template + using span = std::span; +#else + template + using span = gsl::span; +#endif + + namespace detail + { + template + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept + { + if (ch >= static_cast('0') && ch <= static_cast('9')) + return static_cast(ch - static_cast('0')); + if (ch >= static_cast('a') && ch <= static_cast('f')) + return static_cast(10 + ch - static_cast('a')); + if (ch >= static_cast('A') && ch <= static_cast('F')) + return static_cast(10 + ch - static_cast('A')); + return 0; + } + + template + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept + { + return (ch >= static_cast('0') && ch <= static_cast('9')) || + (ch >= static_cast('a') && ch <= static_cast('f')) || + (ch >= static_cast('A') && ch <= static_cast('F')); + } + + template + [[nodiscard]] constexpr std::basic_string_view to_string_view( + TChar const* str) noexcept + { + if (str) + return str; + return {}; + } + + template + [[nodiscard]] constexpr std::basic_string_view + to_string_view(StringType const& str) noexcept + { + return str; + } + + class sha1 + { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate( + uint32_t value, size_t const count) noexcept + { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() + { + reset(); + } + + void reset() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) + { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) + { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) + { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) + { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) + { + const uint8_t* block = static_cast(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) + { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) + { + while (m_blockByteIndex != 0) + { + process_byte(0); + } + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + else + { + while (m_blockByteIndex < 56) + { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast((bitCount >> 24) & 0xFF)); + process_byte(static_cast((bitCount >> 16) & 0xFF)); + process_byte(static_cast((bitCount >> 8) & 0xFF)); + process_byte(static_cast((bitCount)&0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) + { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast(d32[0] >> 24); + digest[di++] = static_cast(d32[0] >> 16); + digest[di++] = static_cast(d32[0] >> 8); + digest[di++] = static_cast(d32[0] >> 0); + + digest[di++] = static_cast(d32[1] >> 24); + digest[di++] = static_cast(d32[1] >> 16); + digest[di++] = static_cast(d32[1] >> 8); + digest[di++] = static_cast(d32[1] >> 0); + + digest[di++] = static_cast(d32[2] >> 24); + digest[di++] = static_cast(d32[2] >> 16); + digest[di++] = static_cast(d32[2] >> 8); + digest[di++] = static_cast(d32[2] >> 0); + + digest[di++] = static_cast(d32[3] >> 24); + digest[di++] = static_cast(d32[3] >> 16); + digest[di++] = static_cast(d32[3] >> 8); + digest[di++] = static_cast(d32[3] >> 0); + + digest[di++] = static_cast(d32[4] >> 24); + digest[di++] = static_cast(d32[4] >> 16); + digest[di++] = static_cast(d32[4] >> 8); + digest[di++] = static_cast(d32[4] >> 0); + + return digest; + } + + private: + void process_block() + { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) + { + w[i] = static_cast(m_block[i * 4 + 0] << 24); + w[i] |= static_cast(m_block[i * 4 + 1] << 16); + w[i] |= static_cast(m_block[i * 4 + 2] << 8); + w[i] |= static_cast(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) + { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) + { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) + { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid[37] = + L"00000000-0000-0000-0000-000000000000"; + + template + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; + } // namespace detail + + // -------------------------------------------------------------------------------------------------------------------------- + // UUID format https://tools.ietf.org/html/rfc4122 + // -------------------------------------------------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------------------------------------------------- + // Field NDR Data Type Octet # Note + // -------------------------------------------------------------------------------------------------------------------------- + // time_low unsigned long 0 - 3 The low field + // of the timestamp. time_mid unsigned short 4 - 5 + // The middle field of the timestamp. time_hi_and_version unsigned + // short 6 - 7 The high field of the timestamp multiplexed + // with the version number. clock_seq_hi_and_reserved unsigned small 8 + // The high field of the clock sequence multiplexed with the variant. + // clock_seq_low unsigned small 9 The low + // field of the clock sequence. node character 10 + // - 15 The spatially unique node identifier. + // -------------------------------------------------------------------------------------------------------------------------- + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // -------------------------------------------------------------------------------------------------------------------------- + // enumerations + // -------------------------------------------------------------------------------------------------------------------------- + + // indicated by a bit pattern in octet 8, marked with N in + // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx + enum class uuid_variant + { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved + }; + + // indicated by a bit pattern in octet 6, marked with M in + // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx + enum class uuid_version + { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = + 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = + 5 // The name-based version specified in RFS 4122 with SHA1 hashing + }; + + // Forward declare uuid & to_string so that we can declare to_string as a friend + // later. + class uuid; + template , class Allocator = std::allocator> + std::basic_string to_string(uuid const& id); + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid class + // -------------------------------------------------------------------------------------------------------------------------- + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept + { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array const& arr) noexcept + : data{arr} + { + } + + explicit uuid(span bytes) + { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template + explicit uuid(ForwardIterator first, ForwardIterator last) + { + if (std::distance(first, last) == 16) + std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept + { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept + { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept + { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) + return false; + return true; + } + + void swap(uuid& other) noexcept + { + data.swap(other.data); + } + + [[nodiscard]] inline span as_bytes() const + { + return span( + reinterpret_cast(data.data()), 16); + } + + template + [[nodiscard]] constexpr static bool is_valid_uuid( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) + return false; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return false; + } + + if (firstDigit) + { + firstDigit = false; + } + else + { + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return false; + } + + return true; + } + + template + [[nodiscard]] constexpr static std::optional from_string( + StringType const& in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array data{{0}}; + + if (str.empty()) + return {}; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') + continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return {}; + } + + if (firstDigit) + { + data[index] = static_cast(detail::hex2char(str[i]) << 4); + firstDigit = false; + } + else + { + data[index] = + static_cast(data[index] | detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return {}; + } + + return uuid{data}; + } + + private: + std::array data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template + friend std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id); + + template + friend std::basic_string to_string(uuid const& id); + + friend std::hash; + }; + + // -------------------------------------------------------------------------------------------------------------------------- + // operators and non-member functions + // -------------------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] inline bool operator==(uuid const& lhs, + uuid const& rhs) noexcept + { + return lhs.data == rhs.data; + } + + [[nodiscard]] inline bool operator!=(uuid const& lhs, + uuid const& rhs) noexcept + { + return !(lhs == rhs); + } + + [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data < rhs.data; + } + + template + [[nodiscard]] inline std::basic_string to_string( + uuid const& id) + { + std::basic_string uustr{detail::empty_guid}; + + for (size_t i = 0, index = 0; i < 36; ++i) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + continue; + } + uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; + uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; + index++; + } + + return uustr; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& s, uuid const& id) + { + s << to_string(id); + return s; + } + + inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept + { + lhs.swap(rhs); + } + + // -------------------------------------------------------------------------------------------------------------------------- + // namespace IDs that could be used for generating name-based uuids + // -------------------------------------------------------------------------------------------------------------------------- + + // Name string is a fully-qualified domain name + static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is a URL + static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an ISO OID (See https://oidref.com/, + // https://en.wikipedia.org/wiki/Object_identifier) + static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // Name string is an X.500 DN, in DER or a text output format (See + // https://en.wikipedia.org/wiki/X.500, + // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) + static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, + 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, + 0xc8}}; + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid generators + // -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR + class uuid_system_generator + { + public: + using result_type = uuid; + + uuid operator()() + { +#ifdef _WIN32 + + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) + { + throw std::system_error(hr, std::system_category(), + "CoCreateGuid failed"); + } + + std::array bytes = { + {static_cast((newId.Data1 >> 24) & 0xFF), + static_cast((newId.Data1 >> 16) & 0xFF), + static_cast((newId.Data1 >> 8) & 0xFF), + static_cast((newId.Data1) & 0xFF), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xFF), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], + newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], + id[6], id[7], id[8], id[9], id[10], + id[11], id[12], id[13], id[14], id[15]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array arrbytes = { + {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, + bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, + bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, + bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; +#else + return uuid{}; +#endif + } + }; +#endif + + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) + : generator(&gen, [](auto) {}) + { + } + explicit basic_uuid_random_generator(engine_type* gen) + : generator(gen, [](auto) {}) + { + } + + [[nodiscard]] uuid operator()() + { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution distribution; + std::shared_ptr generator; + }; + + using uuid_random_generator = basic_uuid_random_generator; + + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept + : nsuuid(namespace_uuid) + { + } + + template + [[nodiscard]] uuid operator()(StringType const& name) + { + reset(); + process_characters(detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() + { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template + void process_characters(std::basic_string_view const str) + { + for (uint32_t c : str) + { + hasher.process_byte(static_cast(c & 0xFF)); + if constexpr (!std::is_same_v) + { + hasher.process_byte(static_cast((c >> 8) & 0xFF)); + hasher.process_byte(static_cast((c >> 16) & 0xFF)); + hasher.process_byte(static_cast((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() + { + detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + detail::sha1 hasher; + }; + +#ifdef UUID_TIME_GENERATOR + // !!! DO NOT USE THIS IN PRODUCTION + // this implementation is unreliable for good uuids + class uuid_time_generator + { + using mac_address = std::array; + + std::optional device_address; + + [[nodiscard]] bool get_mac_address() + { + if (device_address.has_value()) + { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) + return false; + std::vector buf(len); + auto pips = reinterpret_cast(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) + return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() + { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = + std::chrono::duration_cast(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() + { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() + { + if (get_mac_address()) + { + std::array data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } + }; +#endif +} // namespace uuids + +namespace std +{ + template <> + struct hash + { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const + { +#ifdef UUID_HASH_STRING_BASED + std::hash hasher; + return static_cast(hasher(uuids::to_string(uuid))); +#else + uint64_t l = static_cast(uuid.data[0]) << 56 | + static_cast(uuid.data[1]) << 48 | + static_cast(uuid.data[2]) << 40 | + static_cast(uuid.data[3]) << 32 | + static_cast(uuid.data[4]) << 24 | + static_cast(uuid.data[5]) << 16 | + static_cast(uuid.data[6]) << 8 | + static_cast(uuid.data[7]); + uint64_t h = static_cast(uuid.data[8]) << 56 | + static_cast(uuid.data[9]) << 48 | + static_cast(uuid.data[10]) << 40 | + static_cast(uuid.data[11]) << 32 | + static_cast(uuid.data[12]) << 24 | + static_cast(uuid.data[13]) << 16 | + static_cast(uuid.data[14]) << 8 | + static_cast(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) + { + return result_type(l ^ h); + } + else + { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } + }; +} // namespace std + +#endif /* STDUUID_H */ \ No newline at end of file diff --git a/NDKKit/Version.hpp b/NDKKit/Version.hpp new file mode 100644 index 0000000..38fd537 --- /dev/null +++ b/NDKKit/Version.hpp @@ -0,0 +1,4 @@ +#pragma once + +#define kDistVersion "v1.22" +#define kDistRelease "Havok" \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md index 60e7433..dfbfd65 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,6 +1,6 @@ -# NDK +# NDKKit (C++ SDK for ZKA) -## Install +## Installing Start by cloning the repo: @@ -8,6 +8,8 @@ Start by cloning the repo: git clone git@bitbucket.org:mahrouss/codetools.git ``` +## Running makefiles + And then: ``` @@ -16,4 +18,4 @@ make -f .make all You can now use the programs. -##### Copyright ZKA Technologies, all rights reserved. +###### Copyright ZKA Technologies, all rights reserved. diff --git a/Sources/32asm.cxx b/Sources/32asm.cxx index 8577722..23111bc 100644 --- a/Sources/32asm.cxx +++ b/Sources/32asm.cxx @@ -19,10 +19,10 @@ #define __ASM_NEED_32x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/Sources/64asm.cxx b/Sources/64asm.cxx index 777f448..0a92157 100644 --- a/Sources/64asm.cxx +++ b/Sources/64asm.cxx @@ -19,10 +19,10 @@ #define __ASM_NEED_64x0__ 1 -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -107,24 +107,24 @@ void print_warning(std::string reason, const std::string &file) noexcept { NDK_MODULE(NewOSAssembler64000) { for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " "ZKA Technologies.\n"; return 0; - } else if (strcmp(argv[i], "-h") == 0) { + } else if (strcmp(argv[i], "/h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " "Logic.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; - kStdOut << "-64xxx: Compile for a subset of the X64000.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + kStdOut << "/64xxx: Compile for a subset of the X64000.\n"; return 0; - } else if (strcmp(argv[i], "-binary") == 0) { + } else if (strcmp(argv[i], "/binary") == 0) { kOutputAsBinary = true; continue; - } else if (strcmp(argv[i], "-verbose") == 0) { + } else if (strcmp(argv[i], "/verbose") == 0) { kVerbose = true; continue; } @@ -303,7 +303,7 @@ asm_fail_exit: static bool asm_read_attributes(std::string &line) { // import is the opposite of export, it signals to the ld // that we need this symbol. - if (ParserKit::find_word(line, "import")) { + if (CompilerKit::find_word(line, "import")) { if (kOutputAsBinary) { detail::print_error("Invalid import directive in flat binary mode.", "64asm"); @@ -314,7 +314,7 @@ static bool asm_read_attributes(std::string &line) { /// sanity check to avoid stupid linker errors. if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); + detail::print_error("Invalid import", "power-as"); throw std::runtime_error("invalid_import"); } @@ -364,7 +364,7 @@ static bool asm_read_attributes(std::string &line) { // export is a special keyword used by 64asm to tell the AE output stage to // mark this section as a header. it currently supports .code64, .data64., // .zero64 - else if (ParserKit::find_word(line, "export")) { + else if (CompilerKit::find_word(line, "export")) { if (kOutputAsBinary) { detail::print_error("Invalid export directive in flat binary mode.", "64asm"); @@ -454,9 +454,9 @@ std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, const std::string &file) { std::string err_str; - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { if (line.find('#') != std::string::npos) { line.erase(line.find('#')); } else if (line.find(';') != std::string::npos) { @@ -539,7 +539,7 @@ std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode64x0.fName); it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcode64x0.fName)) { + if (CompilerKit::find_word(line, opcode64x0.fName)) { if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) { err_str += "\nMissing space between "; @@ -668,11 +668,11 @@ bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, bool CompilerKit::Encoder64x0::WriteLine(std::string &line, const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; + if (CompilerKit::find_word(line, "export ")) return true; for (auto &opcode64x0 : kOpcodes64x0) { // strict check here - if (ParserKit::find_word(line, opcode64x0.fName) && + if (CompilerKit::find_word(line, opcode64x0.fName) && detail::algorithm::is_valid(line)) { std::string name(opcode64x0.fName); std::string jump_label, cpy_jump_label; diff --git a/Sources/64x0-cc.cxx b/Sources/64x0-cc.cxx index 28667d8..4adf7f8 100644 --- a/Sources/64x0-cc.cxx +++ b/Sources/64x0-cc.cxx @@ -10,9 +10,9 @@ /// BUGS: ? /// TODO: -#include -#include -#include +#include +#include +#include #include #include #include @@ -79,10 +79,10 @@ namespace detail struct CompilerState final { - std::vector fSyntaxTreeList; + std::vector fSyntaxTreeList; std::vector kStackFrame; std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; std::unique_ptr fOutputAssembly; std::string fLastFile; std::string fLastError; @@ -172,7 +172,7 @@ static bool kIfFound = false; static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend +class CompilerBackendCLang final : public CompilerKit::CompilerBackend { public: explicit CompilerBackendCLang() = default; @@ -249,7 +249,7 @@ bool CompilerBackendCLang::Compile(const std::string& text, const char* file) // start parsing for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); auto gen = uuids::uuid_random_generator{generator}; uuids::uuid out = gen(); @@ -767,7 +767,7 @@ bool CompilerBackendCLang::Compile(const std::string& text, const char* file) syntaxLeaf.fUserValue.clear(); } - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); syntaxLeaf.fUserValue = "\n"; kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); @@ -1035,7 +1035,7 @@ cc_next: // extern does not declare anything, it imports a variable. // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) + if (CompilerKit::find_word(ln, "extern")) { auto substr = ln.substr(ln.find("extern") + strlen("extern")); kCompilerVariables.push_back({.fValue = substr}); @@ -1106,7 +1106,7 @@ skip_braces_check: for (auto& key : kCompilerTypes) { - if (ParserKit::find_word(ln, key.fName)) + if (CompilerKit::find_word(ln, key.fName)) { if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { @@ -1207,9 +1207,9 @@ skip_braces_check: if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { bool found_func = false; size_t i = ln.find('('); @@ -1374,7 +1374,7 @@ public: << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - ParserKit::SyntaxLeafList syntax; + CompilerKit::SyntaxLeafList syntax; kState.fSyntaxTreeList.push_back(syntax); kState.fSyntaxTree = @@ -1411,7 +1411,7 @@ public: for (auto& access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { for (auto& struc : kState.kStructMap) { @@ -1422,7 +1422,7 @@ public: for (auto& keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) + if (CompilerKit::find_word(leaf.fUserValue, keyword)) { std::size_t cnt = 0UL; @@ -1453,7 +1453,7 @@ public: } } - if (ParserKit::find_word(leaf.fUserValue, needle)) + if (CompilerKit::find_word(leaf.fUserValue, needle)) { if (leaf.fUserValue.find("import " + needle) != std::string::npos) @@ -1509,7 +1509,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////// -#include +#include #define kPrintF printf #define kSplashCxx() \ diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx index 61dbebd..9f1b768 100644 --- a/Sources/AssemblyFactory.cxx +++ b/Sources/AssemblyFactory.cxx @@ -4,8 +4,8 @@ ------------------------------------------- */ -#include -#include +#include +#include /** * @file AssemblyFactory.cxx diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx index bf05830..abb7f82 100644 --- a/Sources/Detail/asmutils.hxx +++ b/Sources/Detail/asmutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include using namespace CompilerKit; diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx index 6f6361c..fd2b6d2 100644 --- a/Sources/Detail/compilerutils.hxx +++ b/Sources/Detail/compilerutils.hxx @@ -6,8 +6,8 @@ #pragma once -#include -#include +#include +#include #define kZero64Section ".zero64" #define kCode64Section ".code64" diff --git a/Sources/String.cxx b/Sources/String.cxx index 8b8cb9c..f69f9b9 100644 --- a/Sources/String.cxx +++ b/Sources/String.cxx @@ -18,7 +18,7 @@ * */ -#include +#include namespace CompilerKit { CharType *StringView::Data() { return m_Data; } diff --git a/Sources/bpp.cxx b/Sources/bpp.cxx index 5dc70a1..9a2943c 100644 --- a/Sources/bpp.cxx +++ b/Sources/bpp.cxx @@ -9,8 +9,8 @@ /// BUGS: 0 -#include -#include +#include +#include #include #include #include @@ -279,7 +279,7 @@ void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { } for (auto macro : kMacros) { - if (ParserKit::find_word(hdr_line, macro.fName) && + if (CompilerKit::find_word(hdr_line, macro.fName) && hdr_line.find("%def") == std::string::npos) { auto value = macro.fValue; diff --git a/Sources/coff2ae.cxx b/Sources/coff2ae.cxx index 2f7e062..c9ea8c0 100644 --- a/Sources/coff2ae.cxx +++ b/Sources/coff2ae.cxx @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx index 61be2a6..ae4a300 100644 --- a/Sources/cplusplus.cxx +++ b/Sources/cplusplus.cxx @@ -20,8 +20,8 @@ // import, @MLAutoRelease { ... }, fn foo() -> auto { ... } -#include -#include +#include +#include #include #include @@ -83,10 +83,10 @@ namespace detail struct CompilerState final { - std::vector fSyntaxTreeList; + std::vector fSyntaxTreeList; std::vector kStackFrame; std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; std::unique_ptr fOutputAssembly; std::string fLastFile; std::string fLastError; @@ -159,7 +159,7 @@ static size_t kRegisterCnt = kAsmRegisterLimit; static size_t kStartUsable = 8; static size_t kUsableLimit = 15; static size_t kRegisterCounter = kStartUsable; -static std::vector kKeywords; +static std::vector kKeywords; ///////////////////////////////////////// @@ -176,7 +176,7 @@ static bool kInBraces = false; static size_t kBracesCount = 0UL; /* @brief C++ compiler backend for the ZKA C++ driver */ -class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend +class CompilerBackendCPlusPlus final : public CompilerKit::CompilerBackend { public: explicit CompilerBackendCPlusPlus() = default; @@ -252,7 +252,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, // expr; std::size_t index = 0UL; - std::vector> keywords_list; + std::vector> keywords_list; bool found = false; static bool commentBlock = false; @@ -263,15 +263,15 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, { switch (keyword.keyword_kind) { - case ParserKit::eKeywordKindCommentMultiLineStart: { + case CompilerKit::eKeywordKindCommentMultiLineStart: { commentBlock = true; return true; } - case ParserKit::eKeywordKindCommentMultiLineEnd: { + case CompilerKit::eKeywordKindCommentMultiLineEnd: { commentBlock = false; break; } - case ParserKit::eKeywordKindCommentInline: { + case CompilerKit::eKeywordKindCommentInline: { break; } default: @@ -279,15 +279,15 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } if (text[text.find(keyword.keyword_name) - 1] == '+' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) continue; if (text[text.find(keyword.keyword_name) - 1] == '-' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) continue; if (text[text.find(keyword.keyword_name) + 1] == '=' && - keyword.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) continue; keywords_list.emplace_back(std::make_pair(keyword, index)); @@ -311,11 +311,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, for (auto& keyword : keywords_list) { - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + auto syntax_tree = CompilerKit::SyntaxLeafList::SyntaxLeaf(); switch (keyword.first.keyword_kind) { - case ParserKit::KeywordKind::eKeywordKindIf: { + case CompilerKit::KeywordKind::eKeywordKindIf: { auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); if (expr.find(">=") != std::string::npos) @@ -407,7 +407,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, break; } - case ParserKit::KeywordKind::eKeywordKindFunctionStart: { + case CompilerKit::KeywordKind::eKeywordKindFunctionStart: { if (text.ends_with(";")) { break; @@ -439,7 +439,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, ++kLevelFunction; } - case ParserKit::KeywordKind::eKeywordKindFunctionEnd: { + case CompilerKit::KeywordKind::eKeywordKindFunctionEnd: { if (text.ends_with(";")) break; @@ -454,50 +454,50 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, kRegisterMap.clear(); break; } - case ParserKit::KeywordKind::eKeywordKindEndInstr: - case ParserKit::KeywordKind::eKeywordKindVariableInc: - case ParserKit::KeywordKind::eKeywordKindVariableDec: - case ParserKit::KeywordKind::eKeywordKindVariableAssign: { + case CompilerKit::KeywordKind::eKeywordKindEndInstr: + case CompilerKit::KeywordKind::eKeywordKindVariableInc: + case CompilerKit::KeywordKind::eKeywordKindVariableDec: + case CompilerKit::KeywordKind::eKeywordKindVariableAssign: { std::string valueOfVar = ""; - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) { valueOfVar = text.substr(text.find("+=") + 2); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) { valueOfVar = text.substr(text.find("-=") + 2); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) { valueOfVar = text.substr(text.find("=") + 1); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) { break; } while (valueOfVar.find(";") != std::string::npos && - keyword.first.keyword_kind != ParserKit::KeywordKind::eKeywordKindEndInstr) + keyword.first.keyword_kind != CompilerKit::KeywordKind::eKeywordKindEndInstr) { valueOfVar.erase(valueOfVar.find(";")); } std::string varName = text; - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) { varName.erase(varName.find("+=")); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) { varName.erase(varName.find("-=")); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableAssign) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) { varName.erase(varName.find("=")); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) { varName.erase(varName.find(";")); } @@ -506,7 +506,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, for (auto& keyword : kKeywords) { - if (keyword.keyword_kind == ParserKit::eKeywordKindType) + if (keyword.keyword_kind == CompilerKit::eKeywordKindType) { if (text.find(keyword.keyword_name) != std::string::npos) { @@ -525,11 +525,11 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, if (typeFound) { - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) { detail::print_error("Can't increment variable when it's being created.", file); } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) { detail::print_error("Can't decrement variable when it's being created.", file); } @@ -595,24 +595,24 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, } else { - if (kKeywords[keyword.second - 1].keyword_kind == ParserKit::eKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == ParserKit::eKeywordKindTypePtr) + if (kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindTypePtr) { syntax_tree.fUserValue = "\n"; continue; } - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindEndInstr) + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) { syntax_tree.fUserValue = "\n"; continue; } - if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableInc) + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) { instr = "add "; } - else if (keyword.first.keyword_kind == ParserKit::KeywordKind::eKeywordKindVariableDec) + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) { instr = "sub "; } @@ -697,7 +697,7 @@ bool CompilerBackendCPlusPlus::Compile(const std::string& text, break; } - case ParserKit::KeywordKind::eKeywordKindReturn: { + case CompilerKit::KeywordKind::eKeywordKindReturn: { auto pos = text.find("return") + strlen("return") + 1; std::string subText = text.substr(pos); subText = subText.erase(subText.find(";")); @@ -817,7 +817,7 @@ public: (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" << "\n"; - ParserKit::SyntaxLeafList syntax; + CompilerKit::SyntaxLeafList syntax; kState.fSyntaxTreeList.emplace_back(syntax); kState.fSyntaxTree = @@ -863,63 +863,63 @@ NDK_MODULE(CompilerCPlusPlus) { bool skip = false; - kKeywords.push_back({.keyword_name = "if", .keyword_kind = ParserKit::eKeywordKindIf}); - kKeywords.push_back({.keyword_name = "else", .keyword_kind = ParserKit::eKeywordKindElse}); - kKeywords.push_back({.keyword_name = "else if", .keyword_kind = ParserKit::eKeywordKindElseIf}); - - kKeywords.push_back({.keyword_name = "class", .keyword_kind = ParserKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "struct", .keyword_kind = ParserKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = ParserKit::eKeywordKindNamespace}); - kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "using", .keyword_kind = ParserKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = ParserKit::eKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = ParserKit::eKeywordKindBodyEnd}); - kKeywords.push_back({.keyword_name = "auto", .keyword_kind = ParserKit::eKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "bool", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "short", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "char", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "long", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "float", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "double", .keyword_kind = ParserKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "void", .keyword_kind = ParserKit::eKeywordKindType}); - - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = ParserKit::eKeywordKindVariablePtr}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = ParserKit::eKeywordKindTypePtr}); - - kKeywords.push_back({.keyword_name = "(", .keyword_kind = ParserKit::eKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = ParserKit::eKeywordKindFunctionEnd}); - kKeywords.push_back({.keyword_name = "=", .keyword_kind = ParserKit::eKeywordKindVariableAssign}); - kKeywords.push_back({.keyword_name = "+=", .keyword_kind = ParserKit::eKeywordKindVariableInc}); - kKeywords.push_back({.keyword_name = "-=", .keyword_kind = ParserKit::eKeywordKindVariableDec}); - kKeywords.push_back({.keyword_name = "const", .keyword_kind = ParserKit::eKeywordKindConstant}); - kKeywords.push_back({.keyword_name = "*", .keyword_kind = ParserKit::eKeywordKindPtr}); - kKeywords.push_back({.keyword_name = "->", .keyword_kind = ParserKit::eKeywordKindPtrAccess}); - kKeywords.push_back({.keyword_name = ".", .keyword_kind = ParserKit::eKeywordKindAccess}); - kKeywords.push_back({.keyword_name = ",", .keyword_kind = ParserKit::eKeywordKindArgSeparator}); - kKeywords.push_back({.keyword_name = ";", .keyword_kind = ParserKit::eKeywordKindEndInstr}); - kKeywords.push_back({.keyword_name = ":", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "public:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "private:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "final", .keyword_kind = ParserKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "return", .keyword_kind = ParserKit::eKeywordKindReturn}); - kKeywords.push_back({.keyword_name = "/*", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "*/", .keyword_kind = ParserKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "//", .keyword_kind = ParserKit::eKeywordKindCommentInline}); - kKeywords.push_back({.keyword_name = "==", .keyword_kind = ParserKit::eKeywordKindEq}); - kKeywords.push_back({.keyword_name = "!=", .keyword_kind = ParserKit::eKeywordKindNotEq}); - kKeywords.push_back({.keyword_name = ">=", .keyword_kind = ParserKit::eKeywordKindGreaterEq}); - kKeywords.push_back({.keyword_name = "<=", .keyword_kind = ParserKit::eKeywordKindLessEq}); + kKeywords.push_back({.keyword_name = "if", .keyword_kind = CompilerKit::eKeywordKindIf}); + kKeywords.push_back({.keyword_name = "else", .keyword_kind = CompilerKit::eKeywordKindElse}); + kKeywords.push_back({.keyword_name = "else if", .keyword_kind = CompilerKit::eKeywordKindElseIf}); + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = CompilerKit::eKeywordKindNamespace}); + kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = CompilerKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = CompilerKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = CompilerKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = CompilerKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = CompilerKit::eKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + + kKeywords.push_back({.keyword_name = "(", .keyword_kind = CompilerKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = CompilerKit::eKeywordKindFunctionEnd}); + kKeywords.push_back({.keyword_name = "=", .keyword_kind = CompilerKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = CompilerKit::eKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = CompilerKit::eKeywordKindVariableDec}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = CompilerKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = CompilerKit::eKeywordKindPtr}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = CompilerKit::eKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = CompilerKit::eKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = CompilerKit::eKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = CompilerKit::eKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "public:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "private:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "final", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = CompilerKit::eKeywordKindReturn}); + kKeywords.push_back({.keyword_name = "/*", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "*/", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "//", .keyword_kind = CompilerKit::eKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = CompilerKit::eKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = CompilerKit::eKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = CompilerKit::eKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = CompilerKit::eKeywordKindLessEq}); kFactory.Mount(new AssemblyCPlusPlusInterface()); kCompilerBackend = new CompilerBackendCPlusPlus(); diff --git a/Sources/elf2ae.cxx b/Sources/elf2ae.cxx index 3409f6e..451c706 100644 --- a/Sources/elf2ae.cxx +++ b/Sources/elf2ae.cxx @@ -4,9 +4,9 @@ ------------------------------------------- */ -#include -#include -#include +#include +#include +#include #include #include #include diff --git a/Sources/i64asm.cxx b/Sources/i64asm.cxx index a1f57b3..ed77988 100644 --- a/Sources/i64asm.cxx +++ b/Sources/i64asm.cxx @@ -27,10 +27,10 @@ #define kAssemblerPragmaSymStr "#" #define kAssemblerPragmaSym '#' -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include @@ -412,7 +412,7 @@ static bool asm_read_attributes(std::string& line) { // import is the opposite of export, it signals to the ld // that we need this symbol. - if (ParserKit::find_word(line, "import")) + if (CompilerKit::find_word(line, "import")) { if (kOutputAsBinary) { @@ -424,7 +424,7 @@ static bool asm_read_attributes(std::string& line) if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); + detail::print_error("Invalid import", "power-as"); throw std::runtime_error("invalid_import"); } @@ -483,7 +483,7 @@ static bool asm_read_attributes(std::string& line) // export is a special keyword used by i64asm to tell the AE output stage to // mark this section as a header. it currently supports .code64, .data64 and // .zero64. - else if (ParserKit::find_word(line, "export")) + else if (CompilerKit::find_word(line, "export")) { if (kOutputAsBinary) { @@ -596,10 +596,10 @@ std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, { std::string err_str; - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - ParserKit::find_word(line, kAssemblerPragmaSymStr) || - ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + CompilerKit::find_word(line, kAssemblerPragmaSymStr) || + CompilerKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) { if (line.find(';') != std::string::npos) { @@ -671,7 +671,7 @@ std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, } for (auto& opcodeAMD64 : kOpcodesAMD64) { - if (ParserKit::find_word(line, opcodeAMD64.fName)) + if (CompilerKit::find_word(line, opcodeAMD64.fName)) { return err_str; } @@ -1184,7 +1184,7 @@ bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, const std::string& file) { - if (ParserKit::find_word(line, "export ")) + if (CompilerKit::find_word(line, "export ")) return true; struct RegMapAMD64 @@ -1216,7 +1216,7 @@ bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, for (auto& opcodeAMD64 : kOpcodesAMD64) { // strict check here - if (ParserKit::find_word(line, opcodeAMD64.fName) && + if (CompilerKit::find_word(line, opcodeAMD64.fName) && detail::algorithm::is_valid(line)) { foundInstruction = true; diff --git a/Sources/link.cxx b/Sources/link.cxx index d0d2628..d59c982 100644 --- a/Sources/link.cxx +++ b/Sources/link.cxx @@ -13,23 +13,23 @@ /// @note Do not look up for anything with .code64/.data64/.zero64! /// It will be loaded when program will start up! -#include +#include //! Assembler Kit -#include +#include //! Preferred Executable Format -#include -#include +#include +#include #include #include #include //! Dist version -#include +#include //! Advanced Executable Object Format -#include +#include //! C++ I/O headers. #include diff --git a/Sources/power-as.cxx b/Sources/power-as.cxx new file mode 100644 index 0000000..8a6b7ef --- /dev/null +++ b/Sources/power-as.cxx @@ -0,0 +1,976 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file power-as.cxx +/// @author Amlal EL Mahrouss +/// @brief POWER Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that li will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_PPC__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +constexpr auto cPowerIPAlignment = 0x4U; + +static CharType kOutputArch = CompilerKit::kPefArchPowerPC; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +static bool kVerbose = false; + +static std::vector kBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string &line); + +namespace detail { +void print_error(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << kRed << "[ power-as ] " << kWhite + << ((file == "power-as") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ power-as ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +void print_warning(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (!file.empty()) { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ power-as ] " << kWhite << reason << kBlank + << std::endl; +} +} // namespace detail + +/// Do not move it on top! it uses the assembler detail namespace! +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief POWER assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerPowerPC) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: " << kDistVersion << "\npower-as: " + "Copyright (c) " + "ZKA Technologies.\n"; + return 0; + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version,/v: print program version.\n"; + kStdOut << "/verbose: print verbose output.\n"; + kStdOut << "/binary: output as flat binary.\n"; + + return 0; + } else if (strcmp(argv[i], "/binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "/verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "power-as: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "power-as: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto &ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "power-as: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderPowerPC asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + detail::print_error(ln, argv[i]); + continue; + } + + try { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } catch (const std::exception &e) { + if (kVerbose) { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "power-as"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "power-as: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) { + kStdErr << "power-as: At least one record is needed to write an object " + "file.\npower-as: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + std::size_t record_count = 0UL; + + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; + ++record_count; + + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "power-as: Wrote record " << record_hdr.fName << "...\n"; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto &sym : kUndefinedSymbols) { + CompilerKit::AERecordHeader undefined_sym{0}; + + if (kVerbose) + kStdOut << "power-as: Wrote symbol " << sym << " to file...\n"; + + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; + + ++record_count; + + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); + + file_ptr_out << undefined_sym; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "power-as: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto &byte : kBytes) { + file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); + } + + if (kVerbose) kStdOut << "power-as: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "power-as: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "power-as: Exit failed.\n"; + + return MPCC_EXEC_ERROR; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string &line) { + // import is the opposite of export, it signals to the li + // that we need this symbol. + if (CompilerKit::find_word(line, "import")) { + if (kOutputAsBinary) { + detail::print_error("Invalid import directive in flat binary mode.", + "power-as"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) { + detail::print_error("Invalid import", "power-as"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char &j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by power-as to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (CompilerKit::find_word(line, "export")) { + if (kOutputAsBinary) { + detail::print_error("Invalid export directive in flat binary mode.", + "power-as"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export")); + + std::string name_copy = name; + + for (char &j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm { +// \brief authorize a brief set of characters. +static inline bool is_not_alnum_space(char c) { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.')); +} + +bool is_valid(const std::string &str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, + const std::string &file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + /// does the line contains valid input? + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) { + if (line.find(',') + 1 == line.size()) { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } else { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto &ch : substr) { + if (ch != ' ' && ch != '\t') { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + + // these do take an argument. + std::vector operands_inst = {"stw", "li"}; + + // these don't. + std::vector filter_inst = {"blr", "bl", "sc"}; + + for (auto &opcodePPC : kOpcodesPowerPC) { + if (CompilerKit::find_word(line, opcodePPC.name)) { + for (auto &op : operands_inst) { + // if only the instruction was found. + if (line == op) { + err_str += "\nMalformed "; + err_str += op; + err_str += " instruction, here -> "; + err_str += line; + } + } + + // if it is like that -> addr1, 0x0 + if (auto it = + std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); + it == filter_inst.cend()) { + if (CompilerKit::find_word(line, opcodePPC.name)) { + if (!isspace( + line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { + err_str += "\nMissing space between "; + err_str += opcodePPC.name; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; +} + +bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, + std::string &jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) { + if (errno != 0) { + detail::print_error("invalid hex number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "power-as: found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) { + if (errno != 0) { + detail::print_error("invalid binary number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "power-as: found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) { + if (errno != 0) { + detail::print_error("invalid octal number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "power-as: found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "power-as: found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, + const std::string &file) { + if (CompilerKit::find_word(line, "export")) return true; + if (!detail::algorithm::is_valid(line)) return true; + + for (auto &opcodePPC : kOpcodesPowerPC) { + // strict check here + if (CompilerKit::find_word(line, opcodePPC.name)) { + std::string name(opcodePPC.name); + std::string jump_label, cpy_jump_label; + std::vector found_registers_index; + + // check funct7 type. + switch (opcodePPC.ops->type) { + default: { + NumberCast32 num(opcodePPC.opcode); + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + break; + } + case BADDR: + case PCREL: { + auto num = GetNumber32(line, name); + + kBytes.emplace_back(num.number[0]); + kBytes.emplace_back(num.number[1]); + kBytes.emplace_back(num.number[2]); + kBytes.emplace_back(0x48); + + break; + } + /// General purpose, float, vector operations. Everything that involve + /// registers. + case G0REG: + case FREG: + case VREG: + case GREG: { + // \brief how many registers we found. + std::size_t found_some_count = 0UL; + std::size_t register_count = 0UL; + std::string opcodeName = opcodePPC.name; + std::size_t register_sum = 0; + + NumberCast64 num(opcodePPC.opcode); + + for (size_t line_index = 0UL; line_index < line.size(); + line_index++) { + if (line[line_index] == kAsmRegisterPrefix[0] && + isdigit(line[line_index + 1])) { + std::string register_syntax = kAsmRegisterPrefix; + register_syntax += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + register_syntax += line[line_index + 2]; + + std::string reg_str; + reg_str += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + reg_str += line[line_index + 2]; + + // it ranges from r0 to r19 + // something like r190 doesn't exist in the instruction set. + if (isdigit(line[line_index + 3]) && + isdigit(line[line_index + 2])) { + reg_str += line[line_index + 3]; + detail::print_error( + "invalid register index, r" + reg_str + + "\nnote: The POWER accepts registers from r0 to r32.", + file); + throw std::runtime_error("invalid_register_index"); + } + + // finally cast to a size_t + std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + + if (reg_index > kAsmRegisterLimit) { + detail::print_error("invalid register index, r" + reg_str, + file); + throw std::runtime_error("invalid_register_index"); + } + + if (opcodeName == "li") { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + auto num = GetNumber32(line, reg_str); + + kBytes.push_back(num.number[0]); + kBytes.push_back(num.number[1]); + kBytes.push_back(numIndex); + kBytes.push_back(0x38); + + // check if bigger than two. + for (size_t i = 2; i < 4; i++) { + if (num.number[i] > 0) { + detail::print_warning("number overflow on li operation.", + file); + break; + } + } + + break; + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + if (register_sum == 0) { + for (size_t indexReg = 0UL; indexReg < reg_index; + ++indexReg) { + register_sum += 0x20; + } + } else { + register_sum += reg_index; + } + } + + if (opcodeName == "mr") { + switch (register_count) { + case 0: { + kBytes.push_back(0x78); + + char numIndex = 0x3; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x8; + } + + kBytes.push_back(numIndex); + + break; + } + case 1: { + char numIndex = 0x1; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + for (size_t i = 0; i != reg_index; i++) { + kBytes[kBytes.size() - 1] += 0x8; + } + + kBytes[kBytes.size() - 1] -= 0x8; + + kBytes.push_back(numIndex); + + if (reg_index >= 10 && reg_index < 20) + kBytes.push_back(0x7d); + else if (reg_index >= 20 && reg_index < 30) + kBytes.push_back(0x7e); + else if (reg_index >= 30) + kBytes.push_back(0x7f); + else + kBytes.push_back(0x7c); + + break; + } + default: + break; + } + + ++register_count; + ++found_some_count; + } + + if (opcodeName == "addi") { + if (found_some_count == 2 || found_some_count == 0) + kBytes.emplace_back(reg_index); + else if (found_some_count == 1) + kBytes.emplace_back(0x00); + + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("cmp") != std::string::npos) { + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("mf") != std::string::npos || + opcodeName.find("mt") != std::string::npos) { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + num.number[2] += numIndex; + + ++found_some_count; + + if (found_some_count > 1) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + + if (kVerbose) { + kStdOut << "power-as: Found register: " << register_syntax + << "\n"; + kStdOut << "power-as: Amount of registers in instruction: " + << found_some_count << "\n"; + } + + if (reg_index >= 10 && reg_index < 20) + num.number[3] = 0x7d; + else if (reg_index >= 20 && reg_index < 30) + num.number[3] = 0x7e; + else if (reg_index >= 30) + num.number[3] = 0x7f; + else + num.number[3] = 0x7c; + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + } + + found_registers_index.push_back(reg_index); + } + } + + if (opcodeName == "addi") { + kBytes.emplace_back(0x38); + } + + if (opcodeName.find("cmp") != std::string::npos) { + char rightReg = 0x0; + + for (size_t i = 0; i != found_registers_index[1]; i++) { + rightReg += 0x08; + } + + kBytes.emplace_back(0x00); + kBytes.emplace_back(rightReg); + kBytes.emplace_back(found_registers_index[0]); + kBytes.emplace_back(0x7c); + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + size_t offset = 0UL; + + if (line.find('+') != std::string::npos) { + auto number = GetNumber32(line.substr(line.find("+")), "+"); + offset = number.raw; + } + + kBytes.push_back(offset); + kBytes.push_back(0x00); + kBytes.push_back(register_sum); + + kBytes.emplace_back(0x90); + } + + if (opcodeName == "mr") { + if (register_count == 1) { + detail::print_error("Too few registers. -> " + line, file); + throw std::runtime_error("too_few_registers"); + } + } + + // we're not in immediate addressing, reg to reg. + if (opcodePPC.ops->type != GREG) { + // remember! register to register! + if (found_some_count == 1) { + detail::print_error( + "Unrecognized register found.\ntip: each power-as register " + "starts with 'r'.\nline: " + + line, + file); + + throw std::runtime_error("not_a_register"); + } + } + + if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } + + break; + } + } + + kOrigin += cPowerIPAlignment; + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/Sources/power-cc.cxx b/Sources/power-cc.cxx index 41cb334..4c07a04 100644 --- a/Sources/power-cc.cxx +++ b/Sources/power-cc.cxx @@ -7,9 +7,9 @@ * ======================================================== */ -#include -#include -#include +#include +#include +#include #include #include #include @@ -70,10 +70,10 @@ namespace detail struct CompilerState final { - std::vector fSyntaxTreeList; + std::vector fSyntaxTreeList; std::vector kStackFrame; std::vector kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; std::unique_ptr fOutputAssembly; std::string fLastFile; std::string fLastError; @@ -161,7 +161,7 @@ static bool kIfFound = false; static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend +class CompilerBackendCLang final : public CompilerKit::CompilerBackend { public: explicit CompilerBackendCLang() = default; @@ -238,7 +238,7 @@ bool CompilerBackendCLang::Compile(const std::string& text, const char* file) // start parsing for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); auto gen = uuids::uuid_random_generator{generator}; uuids::uuid out = gen(); @@ -788,7 +788,7 @@ bool CompilerBackendCLang::Compile(const std::string& text, const char* file) syntaxLeaf.fUserValue.clear(); } - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); syntaxLeaf.fUserValue = "\n"; kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); @@ -1056,7 +1056,7 @@ cc_next: // extern does not declare anything, it imports a variable. // so that's why it's not declare upper. - if (ParserKit::find_word(ln, "extern")) + if (CompilerKit::find_word(ln, "extern")) { auto substr = ln.substr(ln.find("extern") + strlen("extern")); kCompilerVariables.push_back({.fValue = substr}); @@ -1127,7 +1127,7 @@ skip_braces_check: for (auto& key : kCompilerTypes) { - if (ParserKit::find_word(ln, key.fName)) + if (CompilerKit::find_word(ln, key.fName)) { if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { @@ -1228,9 +1228,9 @@ skip_braces_check: if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { bool found_func = false; size_t i = ln.find('('); @@ -1395,7 +1395,7 @@ public: << "# Language: POWER Assembly (Generated from C)\n"; (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - ParserKit::SyntaxLeafList syntax; + CompilerKit::SyntaxLeafList syntax; kState.fSyntaxTreeList.push_back(syntax); kState.fSyntaxTree = @@ -1431,7 +1431,7 @@ public: for (auto& access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { for (auto& struc : kState.kStructMap) { @@ -1442,7 +1442,7 @@ public: for (auto& keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) + if (CompilerKit::find_word(leaf.fUserValue, keyword)) { std::size_t cnt = 0UL; @@ -1473,7 +1473,7 @@ public: } } - if (ParserKit::find_word(leaf.fUserValue, needle)) + if (CompilerKit::find_word(leaf.fUserValue, needle)) { if (leaf.fUserValue.find("import ") != std::string::npos) { @@ -1527,7 +1527,7 @@ public: ///////////////////////////////////////////////////////////////////////////////////////// -#include +#include #define kPrintF printf #define kSplashCxx() \ diff --git a/Sources/ppcasm.cxx b/Sources/ppcasm.cxx deleted file mode 100644 index 01e8124..0000000 --- a/Sources/ppcasm.cxx +++ /dev/null @@ -1,976 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file ppcasm.cxx -/// @author Amlal EL Mahrouss -/// @brief POWER Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_PPC__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -constexpr auto cPowerIPAlignment = 0x4U; - -static CharType kOutputArch = CompilerKit::kPefArchPowerPC; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static bool kVerbose = false; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ ppcasm ] " << kWhite - << ((file == "ppcasm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ ppcasm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ ppcasm ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail - -/// Do not move it on top! it uses the assembler detail namespace! -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssemblerPowerPC) { - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '/') { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { - kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: " << kDistVersion << "\nppcasm: " - "Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "ppcasm: POWER64 Assembler Driver.\nppcasm: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version,/v: print program version.\n"; - kStdOut << "/verbose: print verbose output.\n"; - kStdOut << "/binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "/binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "/verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "ppcasm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "ppcasm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "ppcasm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "ppcasm"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "ppcasm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "ppcasm: At least one record is needed to write an object " - "file.\nppcasm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) - kStdOut << "ppcasm: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) - kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAEInvalidOpcode; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "ppcasm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "ppcasm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "ppcasm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; - - return MPCC_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the li - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "ppcasm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by ppcasm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "ppcasm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export")); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "li"}; - - // these don't. - std::vector filter_inst = {"blr", "bl", "sc"}; - - for (auto &opcodePPC : kOpcodesPowerPC) { - if (ParserKit::find_word(line, opcodePPC.name)) { - for (auto &op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = - std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); - it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcodePPC.name)) { - if (!isspace( - line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { - err_str += "\nMissing space between "; - err_str += opcodePPC.name; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "ppcasm: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "ppcasm: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "ppcasm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "ppcasm: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "ppcasm: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export")) return true; - if (!detail::algorithm::is_valid(line)) return true; - - for (auto &opcodePPC : kOpcodesPowerPC) { - // strict check here - if (ParserKit::find_word(line, opcodePPC.name)) { - std::string name(opcodePPC.name); - std::string jump_label, cpy_jump_label; - std::vector found_registers_index; - - // check funct7 type. - switch (opcodePPC.ops->type) { - default: { - NumberCast32 num(opcodePPC.opcode); - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - break; - } - case BADDR: - case PCREL: { - auto num = GetNumber32(line, name); - - kBytes.emplace_back(num.number[0]); - kBytes.emplace_back(num.number[1]); - kBytes.emplace_back(num.number[2]); - kBytes.emplace_back(0x48); - - break; - } - /// General purpose, float, vector operations. Everything that involve - /// registers. - case G0REG: - case FREG: - case VREG: - case GREG: { - // \brief how many registers we found. - std::size_t found_some_count = 0UL; - std::size_t register_count = 0UL; - std::string opcodeName = opcodePPC.name; - std::size_t register_sum = 0; - - NumberCast64 num(opcodePPC.opcode); - - for (size_t line_index = 0UL; line_index < line.size(); - line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && - isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (isdigit(line[line_index + 3]) && - isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - detail::print_error( - "invalid register index, r" + reg_str + - "\nnote: The POWER accepts registers from r0 to r32.", - file); - throw std::runtime_error("invalid_register_index"); - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - detail::print_error("invalid register index, r" + reg_str, - file); - throw std::runtime_error("invalid_register_index"); - } - - if (opcodeName == "li") { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - auto num = GetNumber32(line, reg_str); - - kBytes.push_back(num.number[0]); - kBytes.push_back(num.number[1]); - kBytes.push_back(numIndex); - kBytes.push_back(0x38); - - // check if bigger than two. - for (size_t i = 2; i < 4; i++) { - if (num.number[i] > 0) { - detail::print_warning("number overflow on li operation.", - file); - break; - } - } - - break; - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - if (register_sum == 0) { - for (size_t indexReg = 0UL; indexReg < reg_index; - ++indexReg) { - register_sum += 0x20; - } - } else { - register_sum += reg_index; - } - } - - if (opcodeName == "mr") { - switch (register_count) { - case 0: { - kBytes.push_back(0x78); - - char numIndex = 0x3; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x8; - } - - kBytes.push_back(numIndex); - - break; - } - case 1: { - char numIndex = 0x1; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - for (size_t i = 0; i != reg_index; i++) { - kBytes[kBytes.size() - 1] += 0x8; - } - - kBytes[kBytes.size() - 1] -= 0x8; - - kBytes.push_back(numIndex); - - if (reg_index >= 10 && reg_index < 20) - kBytes.push_back(0x7d); - else if (reg_index >= 20 && reg_index < 30) - kBytes.push_back(0x7e); - else if (reg_index >= 30) - kBytes.push_back(0x7f); - else - kBytes.push_back(0x7c); - - break; - } - default: - break; - } - - ++register_count; - ++found_some_count; - } - - if (opcodeName == "addi") { - if (found_some_count == 2 || found_some_count == 0) - kBytes.emplace_back(reg_index); - else if (found_some_count == 1) - kBytes.emplace_back(0x00); - - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("cmp") != std::string::npos) { - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("mf") != std::string::npos || - opcodeName.find("mt") != std::string::npos) { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - num.number[2] += numIndex; - - ++found_some_count; - - if (found_some_count > 1) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - - if (kVerbose) { - kStdOut << "ppcasm: Found register: " << register_syntax - << "\n"; - kStdOut << "ppcasm: Amount of registers in instruction: " - << found_some_count << "\n"; - } - - if (reg_index >= 10 && reg_index < 20) - num.number[3] = 0x7d; - else if (reg_index >= 20 && reg_index < 30) - num.number[3] = 0x7e; - else if (reg_index >= 30) - num.number[3] = 0x7f; - else - num.number[3] = 0x7c; - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - } - - found_registers_index.push_back(reg_index); - } - } - - if (opcodeName == "addi") { - kBytes.emplace_back(0x38); - } - - if (opcodeName.find("cmp") != std::string::npos) { - char rightReg = 0x0; - - for (size_t i = 0; i != found_registers_index[1]; i++) { - rightReg += 0x08; - } - - kBytes.emplace_back(0x00); - kBytes.emplace_back(rightReg); - kBytes.emplace_back(found_registers_index[0]); - kBytes.emplace_back(0x7c); - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - size_t offset = 0UL; - - if (line.find('+') != std::string::npos) { - auto number = GetNumber32(line.substr(line.find("+")), "+"); - offset = number.raw; - } - - kBytes.push_back(offset); - kBytes.push_back(0x00); - kBytes.push_back(register_sum); - - kBytes.emplace_back(0x90); - } - - if (opcodeName == "mr") { - if (register_count == 1) { - detail::print_error("Too few registers. -> " + line, file); - throw std::runtime_error("too_few_registers"); - } - } - - // we're not in immediate addressing, reg to reg. - if (opcodePPC.ops->type != GREG) { - // remember! register to register! - if (found_some_count == 1) { - detail::print_error( - "Unrecognized register found.\ntip: each ppcasm register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/posix.make b/posix.make index 0b44aed..33d6dc3 100644 --- a/posix.make +++ b/posix.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail +COMMON_INC=-I./NDKKit -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 LINK_SRC=Sources/link.cxx LINK_OUTPUT=Output/link @@ -42,8 +42,8 @@ IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm # Power4 Assembler (IBM RISC) -PPCASM_SRC=Sources/ppcasm.cxx $(SRC_COMMON) -PPCASM_OUTPUT=Output/ppcasm +PPCASM_SRC=Sources/power-as.cxx $(SRC_COMMON) +PPCASM_OUTPUT=Output/power-as .PHONY: all all: pre-processor compiler linker diff --git a/win64.make b/win64.make index ff73f42..fb0ae91 100644 --- a/win64.make +++ b/win64.make @@ -7,7 +7,7 @@ # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail +COMMON_INC=-I./NDKKit -I./ -I./Sources/Detail LINK_CC=clang++ -std=c++20 -Xlinker -s LINK_SRC=Sources/link.cxx LINK_OUTPUT=Output/link.exe @@ -41,8 +41,8 @@ IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm.exe # POWER Assembler -PPCASM_SRC=Sources/ppcasm.cxx $(SRC_COMMON) -PPCASM_OUTPUT=Output/ppcasm.exe +PPCASM_SRC=Sources/power-as.cxx $(SRC_COMMON) +PPCASM_OUTPUT=Output/power-as.exe .PHONY: all all: pre-processor compiler linker -- cgit v1.2.3 From 00df8fa52de0a5a379bfd36b34d4502251ceec72 Mon Sep 17 00:00:00 2001 From: Amlal EL Mahrouss Date: Sun, 28 Jul 2024 06:25:47 +0200 Subject: [META] Refactor codebase. Signed-off-by: Amlal EL Mahrouss --- NDKKit/Sources/32asm.cxx | 52 + NDKKit/Sources/64asm.cxx | 954 ++++++++++++++++++ NDKKit/Sources/64x0-cc.cxx | 1627 ++++++++++++++++++++++++++++++ NDKKit/Sources/AssemblyFactory.cxx | 59 ++ NDKKit/Sources/Detail/ReadMe.md | 3 + NDKKit/Sources/Detail/asmutils.hxx | 111 +++ NDKKit/Sources/Detail/compilerutils.hxx | 14 + NDKKit/Sources/String.cxx | 200 ++++ NDKKit/Sources/bpp.cxx | 899 +++++++++++++++++ NDKKit/Sources/coff2ae.cxx | 23 + NDKKit/Sources/compile_flags.txt | 5 + NDKKit/Sources/cplusplus.cxx | 1025 +++++++++++++++++++ NDKKit/Sources/elf2ae.cxx | 22 + NDKKit/Sources/i64asm.cxx | 1484 ++++++++++++++++++++++++++++ NDKKit/Sources/link.cxx | 741 ++++++++++++++ NDKKit/Sources/power-as.cxx | 976 ++++++++++++++++++ NDKKit/Sources/power-cc.cxx | 1645 +++++++++++++++++++++++++++++++ ReadMe.md | 10 +- Sources/32asm.cxx | 52 - Sources/64asm.cxx | 954 ------------------ Sources/64x0-cc.cxx | 1627 ------------------------------ Sources/AssemblyFactory.cxx | 59 -- Sources/Detail/ReadMe.md | 3 - Sources/Detail/asmutils.hxx | 111 --- Sources/Detail/compilerutils.hxx | 14 - Sources/String.cxx | 200 ---- Sources/bpp.cxx | 899 ----------------- Sources/coff2ae.cxx | 23 - Sources/compile_flags.txt | 5 - Sources/cplusplus.cxx | 1025 ------------------- Sources/elf2ae.cxx | 22 - Sources/i64asm.cxx | 1484 ---------------------------- Sources/link.cxx | 741 -------------- Sources/power-as.cxx | 976 ------------------ Sources/power-cc.cxx | 1645 ------------------------------- posix.make | 20 +- win64.make | 20 +- 37 files changed, 9865 insertions(+), 9865 deletions(-) create mode 100644 NDKKit/Sources/32asm.cxx create mode 100644 NDKKit/Sources/64asm.cxx create mode 100644 NDKKit/Sources/64x0-cc.cxx create mode 100644 NDKKit/Sources/AssemblyFactory.cxx create mode 100644 NDKKit/Sources/Detail/ReadMe.md create mode 100644 NDKKit/Sources/Detail/asmutils.hxx create mode 100644 NDKKit/Sources/Detail/compilerutils.hxx create mode 100644 NDKKit/Sources/String.cxx create mode 100644 NDKKit/Sources/bpp.cxx create mode 100644 NDKKit/Sources/coff2ae.cxx create mode 100644 NDKKit/Sources/compile_flags.txt create mode 100644 NDKKit/Sources/cplusplus.cxx create mode 100644 NDKKit/Sources/elf2ae.cxx create mode 100644 NDKKit/Sources/i64asm.cxx create mode 100644 NDKKit/Sources/link.cxx create mode 100644 NDKKit/Sources/power-as.cxx create mode 100644 NDKKit/Sources/power-cc.cxx delete mode 100644 Sources/32asm.cxx delete mode 100644 Sources/64asm.cxx delete mode 100644 Sources/64x0-cc.cxx delete mode 100644 Sources/AssemblyFactory.cxx delete mode 100644 Sources/Detail/ReadMe.md delete mode 100644 Sources/Detail/asmutils.hxx delete mode 100644 Sources/Detail/compilerutils.hxx delete mode 100644 Sources/String.cxx delete mode 100644 Sources/bpp.cxx delete mode 100644 Sources/coff2ae.cxx delete mode 100644 Sources/compile_flags.txt delete mode 100644 Sources/cplusplus.cxx delete mode 100644 Sources/elf2ae.cxx delete mode 100644 Sources/i64asm.cxx delete mode 100644 Sources/link.cxx delete mode 100644 Sources/power-as.cxx delete mode 100644 Sources/power-cc.cxx (limited to 'Sources') diff --git a/NDKKit/Sources/32asm.cxx b/NDKKit/Sources/32asm.cxx new file mode 100644 index 0000000..23111bc --- /dev/null +++ b/NDKKit/Sources/32asm.cxx @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file 32asm.cxx +// @author ZKA Technologies +// @brief 32x0 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_32x0__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 32x0 Assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/NDKKit/Sources/64asm.cxx b/NDKKit/Sources/64asm.cxx new file mode 100644 index 0000000..0a92157 --- /dev/null +++ b/NDKKit/Sources/64asm.cxx @@ -0,0 +1,954 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file 64asm.cxx +// @author Amlal EL Mahrouss +// @brief 64x000 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_64x0__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +static char kOutputArch = CompilerKit::kPefArch64000; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +constexpr auto c64x0IPAlignment = 0x4U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +static bool kVerbose = false; + +static std::vector kBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string &line); + +namespace detail { +void print_error(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << kRed << "[ 64asm ] " << kWhite + << ((file == "64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +void print_warning(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (!file.empty()) { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; +} +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 64x0 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssembler64000) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " + "ZKA Technologies.\n"; + return 0; + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " + "Logic.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + kStdOut << "/64xxx: Compile for a subset of the X64000.\n"; + + return 0; + } else if (strcmp(argv[i], "/binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "/verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto &ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::Encoder64x0 asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + detail::print_error(ln, argv[i]); + continue; + } + + try { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } catch (const std::exception &e) { + if (kVerbose) { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "64asm"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "64asm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) { + kStdErr << "64asm: At least one record is needed to write an object " + "file.\n64asm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + std::size_t record_count = 0UL; + + for (auto &rec : kRecords) { + if (kVerbose) + kStdOut << "64asm: Wrote record " << rec.fName << " to file...\n"; + + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; + + file_ptr_out << rec; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto &sym : kUndefinedSymbols) { + CompilerKit::AERecordHeader _record_hdr{0}; + + if (kVerbose) + kStdOut << "64asm: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + + file_ptr_out << _record_hdr; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "64asm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto &byte : kBytes) { + file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); + } + + if (kVerbose) kStdOut << "64asm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "64asm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "64asm: Exit failed.\n"; + + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string &line) { + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (CompilerKit::find_word(line, "import")) { + if (kOutputAsBinary) { + detail::print_error("Invalid import directive in flat binary mode.", + "64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import")); + + /// sanity check to avoid stupid linker errors. + if (name.size() == 0) { + detail::print_error("Invalid import", "power-as"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char &j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by 64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (CompilerKit::find_word(line, "export")) { + if (kOutputAsBinary) { + detail::print_error("Invalid export directive in flat binary mode.", + "64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export")); + + std::string name_copy = name; + + for (char &j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm { +// \brief authorize a brief set of characters. +static inline bool is_not_alnum_space(char c) { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.')); +} + +bool is_valid(const std::string &str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, + const std::string &file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) { + if (line.find(',') + 1 == line.size()) { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } else { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto &ch : substr) { + if (ch != ' ' && ch != '\t') { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + + // these do take an argument. + std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; + + // these don't. + std::vector filter_inst = {"jlr", "jrl", "int"}; + + for (auto &opcode64x0 : kOpcodes64x0) { + if (line.find(opcode64x0.fName) != std::string::npos) { + if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; + + for (auto &op : operands_inst) { + // if only the instruction was found. + if (line == op) { + err_str += "\nMalformed "; + err_str += op; + err_str += " instruction, here -> "; + err_str += line; + } + } + + // if it is like that -> addr1, 0x0 + if (auto it = std::find(filter_inst.begin(), filter_inst.end(), + opcode64x0.fName); + it == filter_inst.cend()) { + if (CompilerKit::find_word(line, opcode64x0.fName)) { + if (!isspace(line[line.find(opcode64x0.fName) + + strlen(opcode64x0.fName)])) { + err_str += "\nMissing space between "; + err_str += opcode64x0.fName; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; +} + +bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, + std::string &jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) { + if (errno != 0) { + detail::print_error("invalid hex number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_hex_number"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "64asm: found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) { + if (errno != 0) { + detail::print_error("invalid binary number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "64asm: found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) { + if (errno != 0) { + detail::print_error("invalid octal number: " + jump_label, "64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "64asm: found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "64asm: found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::Encoder64x0::WriteLine(std::string &line, + const std::string &file) { + if (CompilerKit::find_word(line, "export ")) return true; + + for (auto &opcode64x0 : kOpcodes64x0) { + // strict check here + if (CompilerKit::find_word(line, opcode64x0.fName) && + detail::algorithm::is_valid(line)) { + std::string name(opcode64x0.fName); + std::string jump_label, cpy_jump_label; + + kBytes.emplace_back(opcode64x0.fOpcode); + kBytes.emplace_back(opcode64x0.fFunct3); + kBytes.emplace_back(opcode64x0.fFunct7); + + // check funct7 type. + switch (opcode64x0.fFunct7) { + // reg to reg means register to register transfer operation. + case kAsmRegToReg: + case kAsmImmediate: { + // \brief how many registers we found. + std::size_t found_some = 0UL; + + for (size_t line_index = 0UL; line_index < line.size(); + line_index++) { + if (line[line_index] == kAsmRegisterPrefix[0] && + isdigit(line[line_index + 1])) { + std::string register_syntax = kAsmRegisterPrefix; + register_syntax += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + register_syntax += line[line_index + 2]; + + std::string reg_str; + reg_str += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + reg_str += line[line_index + 2]; + + // it ranges from r0 to r19 + // something like r190 doesn't exist in the instruction set. + if (kOutputArch == CompilerKit::kPefArch64000) { + if (isdigit(line[line_index + 3]) && + isdigit(line[line_index + 2])) { + reg_str += line[line_index + 3]; + detail::print_error( + "invalid register index, r" + reg_str + + "\nnote: The 64x0 accepts registers from r0 to r20.", + file); + throw std::runtime_error("invalid_register_index"); + } + } + + // finally cast to a size_t + std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + + if (reg_index > kAsmRegisterLimit) { + detail::print_error("invalid register index, r" + reg_str, + file); + throw std::runtime_error("invalid_register_index"); + } + + kBytes.emplace_back(reg_index); + ++found_some; + + if (kVerbose) { + kStdOut << "64asm: Register found: " << register_syntax << "\n"; + kStdOut << "64asm: Register amount in instruction: " + << found_some << "\n"; + } + } + } + + // we're not in immediate addressing, reg to reg. + if (opcode64x0.fFunct7 != kAsmImmediate) { + // remember! register to register! + if (found_some == 1) { + detail::print_error( + "Too few registers.\ntip: each 64asm register " + "starts with 'r'.\nline: " + + line, + file); + throw std::runtime_error("not_a_register"); + } + } + + if (found_some < 1 && name != "ldw" && name != "lda" && + name != "stw") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } else if (found_some == 1 && name == "add") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } else if (found_some == 1 && name == "sub") { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } + + if (found_some > 0 && name == "pop") { + detail::print_error( + "invalid combination for opcode 'pop'.\ntip: it expects " + "nothing.\nline: " + + line, + file); + throw std::runtime_error("invalid_comb_op_pop"); + } + } + default: + break; + } + + // try to fetch a number from the name + if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { + auto where_string = name; + + // if we load something, we'd need it's symbol/literal + if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || + name == "sta") + where_string = ","; + + jump_label = line; + + auto found_sym = false; + + while (jump_label.find(where_string) != std::string::npos) { + jump_label = jump_label.substr(jump_label.find(where_string) + + where_string.size()); + + while (jump_label.find(" ") != std::string::npos) { + jump_label.erase(jump_label.find(" "), 1); + } + + if (jump_label[0] != kAsmRegisterPrefix[0] && + !isdigit(jump_label[1])) { + if (found_sym) { + detail::print_error( + "invalid combination of opcode and operands.\nhere -> " + + jump_label, + file); + throw std::runtime_error("invalid_comb_op_ops"); + } else { + // death trap installed. + found_sym = true; + } + } + } + + cpy_jump_label = jump_label; + + // replace any spaces with $ + if (jump_label[0] == ' ') { + while (jump_label.find(' ') != std::string::npos) { + if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; + + jump_label.erase(jump_label.find(' '), 1); + } + } + + if (!this->WriteNumber(0, jump_label)) { + // sta expects this: sta 0x000000, r0 + if (name == "sta") { + detail::print_error( + "invalid combination of opcode and operands.\nHere ->" + line, + file); + throw std::runtime_error("invalid_comb_op_ops"); + } + } else { + if (name == "sta" && + cpy_jump_label.find("import ") != std::string::npos) { + detail::print_error("invalid usage import on 'sta', here: " + line, + file); + throw std::runtime_error("invalid_sta_usage"); + } + } + + goto asm_write_label; + } + + // This is the case where we jump to a label, it is also used as a goto. + if (name == "lda" || name == "sta") { + asm_write_label: + if (cpy_jump_label.find('\n') != std::string::npos) + cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); + + if (cpy_jump_label.find("import") != std::string::npos) { + cpy_jump_label.erase(cpy_jump_label.find("import"), strlen("import")); + + if (name == "sta") { + detail::print_error("import is not allowed on a sta operation.", + file); + throw std::runtime_error("import_sta_op"); + } else { + goto asm_end_label_cpy; + } + } + + if (name == "lda" || name == "sta") { + for (auto &label : kOriginLabel) { + if (cpy_jump_label == label.first) { + if (kVerbose) { + kStdOut << "64asm: Replace label " << cpy_jump_label + << " to address: " << label.second << std::endl; + } + + CompilerKit::NumberCast64 num(label.second); + + for (auto &num : num.number) { + kBytes.push_back(num); + } + + goto asm_end_label_cpy; + } + } + + if (cpy_jump_label[0] == '0') { + switch (cpy_jump_label[1]) { + case 'x': + case 'o': + case 'b': + if (this->WriteNumber(0, cpy_jump_label)) + goto asm_end_label_cpy; + + break; + default: + break; + } + + if (isdigit(cpy_jump_label[0])) { + if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; + + break; + } + } + } + + if (cpy_jump_label.size() < 1) { + detail::print_error("label is empty, can't jump on it.", file); + throw std::runtime_error("label_empty"); + } + + /// don't go any further if: + /// load word (ldw) or store word. (stw) + + if (name == "ldw" || name == "stw") break; + + auto mld_reloc_str = std::to_string(cpy_jump_label.size()); + mld_reloc_str += kUndefinedSymbol; + mld_reloc_str += cpy_jump_label; + + bool ignore_back_slash = false; + + for (auto &reloc_chr : mld_reloc_str) { + if (reloc_chr == '\\') { + ignore_back_slash = true; + continue; + } + + if (ignore_back_slash) { + ignore_back_slash = false; + continue; + } + + kBytes.push_back(reloc_chr); + } + + kBytes.push_back('\0'); + goto asm_end_label_cpy; + } + + asm_end_label_cpy: + kOrigin += c64x0IPAlignment; + + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/NDKKit/Sources/64x0-cc.cxx b/NDKKit/Sources/64x0-cc.cxx new file mode 100644 index 0000000..19d995d --- /dev/null +++ b/NDKKit/Sources/64x0-cc.cxx @@ -0,0 +1,1627 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 +/// TODO: none + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* C driver */ +/* This is part of the NDK. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file 64x0-cc.cxx +/// @brief 64x0 C Compiler. + +/// TODO: support structures, else if, else, . and -> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kOk (0) + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNAL STUFF OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "64k C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; +static std::vector kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, import "; + syntaxLeaf.fUserValue += + kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword export .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error("assignement of value in struct " + textBuffer, + file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } + else + { + substr += "\tldw "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + if (var_to_find == kCompilerVariables.cend()) + { + ++kRegisterCounter; + + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } + + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + if (textBuffer[text_index] == '=') + break; + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tlda r19, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "sub "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (CompilerKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (CompilerKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCCInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCCInterface); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArch64x0; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCCInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ldw", "stw", "lda", "sta", + "add", "sub", "mv"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (CompilerKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import " + needle) != + std::string::npos) + { + std::string range = "import " + needle; + leaf.fUserValue.replace( + leaf.fUserValue.find("import " + needle), range.size(), + needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && + keyword != "sub") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "ZKA C Driver, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLang64x0) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyCCInterface()); + kMachine = CompilerKit::AssemblyFactory::kArch64x0; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '/') + { + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/NDKKit/Sources/AssemblyFactory.cxx b/NDKKit/Sources/AssemblyFactory.cxx new file mode 100644 index 0000000..9f1b768 --- /dev/null +++ b/NDKKit/Sources/AssemblyFactory.cxx @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cxx + * @author amlal (amlal@zeta.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, ZKA Technologies + * + */ + +#include + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit +{ + ///! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + ///! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + ///! @brief Unmount assembler. + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit diff --git a/NDKKit/Sources/Detail/ReadMe.md b/NDKKit/Sources/Detail/ReadMe.md new file mode 100644 index 0000000..e9d0a2c --- /dev/null +++ b/NDKKit/Sources/Detail/ReadMe.md @@ -0,0 +1,3 @@ +# Compiler utilities. + +A list of headers used to make compiler/assemblers. diff --git a/NDKKit/Sources/Detail/asmutils.hxx b/NDKKit/Sources/Detail/asmutils.hxx new file mode 100644 index 0000000..abb7f82 --- /dev/null +++ b/NDKKit/Sources/Detail/asmutils.hxx @@ -0,0 +1,111 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +using namespace CompilerKit; + +/// @brief Get Number from lineBuffer. +/// @param lineBuffer the lineBuffer to fetch from. +/// @param numberKey where to seek that number. +/// @return +static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) +{ + auto pos = lineBuffer.find(numberKey) + numberKey.size(); + + if (lineBuffer.find(",") != std::string::npos) + lineBuffer.erase(lineBuffer.find(","), 1); + + while (lineBuffer[pos] == ' ') + ++pos; + + switch (lineBuffer[pos + 1]) + { + case 'x': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); + + if (kVerbose) + { + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'b': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number:" + lineBuffer, "asm"); + throw std::runtime_error("invalid_bin"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + case 'o': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_octal"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + default: { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + lineBuffer, "asm"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); + + if (kVerbose) + { + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) + << "\n"; + } + + return numOffset; + } + } +} diff --git a/NDKKit/Sources/Detail/compilerutils.hxx b/NDKKit/Sources/Detail/compilerutils.hxx new file mode 100644 index 0000000..fd2b6d2 --- /dev/null +++ b/NDKKit/Sources/Detail/compilerutils.hxx @@ -0,0 +1,14 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include +#include + +#define kZero64Section ".zero64" +#define kCode64Section ".code64" +#define kData64Section ".data64" diff --git a/NDKKit/Sources/String.cxx b/NDKKit/Sources/String.cxx new file mode 100644 index 0000000..f69f9b9 --- /dev/null +++ b/NDKKit/Sources/String.cxx @@ -0,0 +1,200 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/** + * @file String.cxx + * @author Amlal (amlal@mahrouss-logic.com) + * @brief C++ string manipulation API. + * @version 0.2 + * @date 2024-01-23 + * + * @copyright Copyright (c) ZKA Technologies + * + */ + +#include + +namespace CompilerKit { +CharType *StringView::Data() { return m_Data; } + +const CharType *StringView::CData() const { return m_Data; } + +SizeType StringView::Length() const { return strlen(m_Data); } + +bool StringView::operator==(const StringView &rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < Length(); ++index) { + if (rhs.m_Data[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator==(const CharType *rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const StringView &rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < rhs.Length(); ++index) { + if (rhs.m_Data[index] == m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const CharType *rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] == m_Data[index]) return false; + } + + return true; +} + +StringView StringBuilder::Construct(const CharType *data) { + if (!data || *data == 0) return StringView(0); + + StringView view(strlen(data)); + view += data; + + return view; +} + +const char *StringBuilder::FromInt(const char *fmt, int i) { + if (!fmt) return ("-1"); + + auto ret_len = 8 + string_length(fmt); + char *ret = new char[ret_len]; + + if (!ret) return ("-1"); + + memset(ret, 0, ret_len); + + CharType result[8]; + if (!to_str(result, sizeof(int), i)) { + delete[] ret; + return ("-1"); + } + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(result); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) { + ret[result_cnt] = result[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ +} + +const char *StringBuilder::FromBool(const char *fmt, bool i) { + if (!fmt) return ("?"); + + const char *boolean_expr = i ? "true" : "false"; + char *ret = new char[i ? 4 : 5 + string_length(fmt)]; + + if (!ret) return ("?"); + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(boolean_expr); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) { + ret[result_cnt] = boolean_expr[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +bool StringBuilder::Equals(const char *lhs, const char *rhs) { + if (string_length(rhs) != string_length(lhs)) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != lhs[index]) return false; + } + + return true; +} + +const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { + if (!fmt || !fmtRight) return ("?"); + + char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; + if (!ret) return ("?"); + + for (SizeType idx = 0; idx < string_length(fmt); ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { + ret[result_cnt] = fmtRight[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +StringView &StringView::operator+=(const CharType *rhs) { + if (strlen(rhs) > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); + this->m_Cur += strlen(rhs); + + return *this; +} + +StringView &StringView::operator+=(const StringView &rhs) { + if (rhs.m_Cur > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); + this->m_Cur += strlen(rhs.CData()); + + return *this; +} +} // namespace CompilerKit diff --git a/NDKKit/Sources/bpp.cxx b/NDKKit/Sources/bpp.cxx new file mode 100644 index 0000000..9a2943c --- /dev/null +++ b/NDKKit/Sources/bpp.cxx @@ -0,0 +1,899 @@ +/* + * ======================================================== + * + * bpp + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 + +#include +#include +#include +#include +#include +#include +#include + +#define kMacroPrefix '%' + +/// @author Amlal El Mahrouss (amlel) +/// @file bpp.cxx +/// @brief Preprocessor. + +typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, + std::ofstream &pp_out); + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Preprocessor internal types. + +///////////////////////////////////////////////////////////////////////////////////////// + +namespace details { +enum { + kEqual, + kGreaterEqThan, + kLesserEqThan, + kGreaterThan, + kLesserThan, + kNotEqual, +}; + +struct bpp_macro_condition final { + int32_t fType; + std::string fTypeName; +}; + +struct bpp_macro final { + std::vector fArgs; + std::string fName; + std::string fValue; +}; + +class bpp_pragma final { + public: + explicit bpp_pragma() = default; + ~bpp_pragma() = default; + + MPCC_COPY_DEFAULT(bpp_pragma); + + std::string fMacroName; + bpp_parser_fn_t fParse; +}; +} // namespace details + +static std::vector kFiles; +static std::vector kMacros; +static std::vector kIncludes; + +static std::string kWorkingDir; + +static std::vector kKeywords = { + "include", "if", "pragma", "def", "elif", + "ifdef", "ifndef", "else", "warning", "error"}; + +#define kKeywordCxxCnt kKeywords.size() + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_if_condition +// @brief parse #if condition + +///////////////////////////////////////////////////////////////////////////////////////// + +int32_t bpp_parse_if_condition(details::bpp_macro_condition &cond, + details::bpp_macro ¯o, bool &inactive_code, + bool &defined, std::string ¯o_str) { + if (cond.fType == details::kEqual) { + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fValue) != std::string::npos) { + if (macro.fValue == "0") { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + } else if (cond.fType == details::kNotEqual) { + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fName) != std::string::npos) { + if (substr_macro.find(macro.fValue) != std::string::npos) { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + auto substr_macro = + macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + std::string number; + + for (auto ¯o_num : kMacros) { + if (substr_macro.find(macro_num.fName) != std::string::npos) { + for (size_t i = 0; i < macro_num.fName.size(); ++i) { + if (isdigit(macro_num.fValue[i])) { + number += macro_num.fValue[i]; + } else { + number.clear(); + break; + } + } + + break; + } + } + + size_t y = 2; + + /* last try */ + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + size_t rhs = atol(macro.fValue.c_str()); + size_t lhs = atol(number.c_str()); + + if (lhs == 0) { + number.clear(); + ++y; + + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + lhs = atol(number.c_str()); + } + + if (cond.fType == details::kGreaterThan) { + if (lhs < rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kGreaterEqThan) { + if (lhs <= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kLesserEqThan) { + if (lhs >= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == details::kLesserThan) { + if (lhs > rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief stores every included file here. + +///////////////////////////////////////////////////////////////////////////////////////// + +std::vector kAllIncludes; + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_file +// @brief parse file to preprocess it. + +///////////////////////////////////////////////////////////////////////////////////////// + +void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { + std::string hdr_line; + std::string line_after_include; + + bool inactive_code = false; + bool defined = false; + + try { + while (std::getline(hdr_file, hdr_line)) { + /// BPP Documentation. + if (hdr_line.find("@bdoc") != std::string::npos) { + hdr_line.erase(hdr_line.find("@bdoc")); + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("endif") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = false; + + continue; + } + + continue; + } + + if (!defined && inactive_code) { + continue; + } + + if (defined && inactive_code) { + continue; + } + + for (auto macro : kMacros) { + if (CompilerKit::find_word(hdr_line, macro.fName) && + hdr_line.find("%def") == std::string::npos) { + auto value = macro.fValue; + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + value); + } + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("def ") != std::string::npos) { + auto line_after_define = + hdr_line.substr(hdr_line.find("def ") + strlen("def ")); + + std::string macro_value; + std::string macro_key; + + std::size_t pos = 0UL; + + std::vector args; + bool on_args = false; + + for (auto &ch : line_after_define) { + ++pos; + + if (ch == '(') { + on_args = true; + continue; + } + + if (ch == ')') { + on_args = false; + continue; + } + + if (ch == '\\') continue; + + if (on_args) continue; + + if (ch == ' ') { + for (size_t i = pos; i < line_after_define.size(); i++) { + macro_value += line_after_define[i]; + } + + break; + } + + macro_key += ch; + } + + std::vector dupls; + std::string str; + + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto &subc : line_after_define) { + if (subc == ',' || subc == ')') { + if (str.empty()) continue; + + dupls.push_back(str); + args.push_back(str); + + str.clear(); + + continue; + } + + if (isalnum(subc)) str.push_back(subc); + } + + for (auto &dupl : dupls) { + std::size_t cnt = 0; + + for (auto &arg : args) { + if (dupl == arg) ++cnt; + } + + if (cnt > 1) { + auto it = std::find(args.begin(), args.end(), dupl); + + while (it != args.end()) { + args.erase(it); + it = std::find(args.begin(), args.end(), dupl); + } + } + } + + details::bpp_macro macro; + + macro.fArgs = args; + macro.fName = macro_key; + macro.fValue = macro_value; + + kMacros.emplace_back(macro); + + continue; + } + + if (hdr_line[0] != kMacroPrefix) { + if (inactive_code) { + continue; + } + + for (auto ¯o : kMacros) { + if (hdr_line.find(macro.fName) != std::string::npos) { + std::vector arg_values; + + if (macro.fArgs.size() > 0) { + for (size_t i = 0; i < hdr_line.size(); ++i) { + if (hdr_line[i] == '(') { + std::string tmp_arg; + + for (size_t x = i; x < hdr_line.size(); x++) { + if (hdr_line[x] == ')') break; + + if (hdr_line[x] == ' ') continue; + + if (hdr_line[i] == '\\') continue; + + if (hdr_line[x] == ',') { + arg_values.push_back(tmp_arg); + tmp_arg.clear(); + continue; + } + + tmp_arg += hdr_line[x]; + } + + break; + } + } + + std::string symbol; + + for (char i : macro.fValue) { + if (i == '(') break; + + if (i == '\\') continue; + + symbol += i; + } + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + symbol); + + size_t x_arg_indx = 0; + + for (size_t i = hdr_line.find(macro.fValue); i < hdr_line.size(); + ++i) { + if (hdr_line.find(macro.fArgs[x_arg_indx]) == i) { + hdr_line.replace(i, macro.fArgs[x_arg_indx].size(), + arg_values[x_arg_indx]); + ++x_arg_indx; + } + } + } else { + std::string symbol; + + for (size_t i = 0; i < macro.fValue.size(); i++) { + if (macro.fValue[i] == ' ') continue; + + if (macro.fValue[i] == '\\') continue; + + symbol += macro.fValue[i]; + } + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), + symbol); + } + + break; + } + } + + pp_out << hdr_line << std::endl; + + continue; + } + + if (hdr_line[0] == kMacroPrefix && + hdr_line.find("ifndef") != std::string::npos) { + auto line_after_ifndef = + hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); + std::string macro; + + for (auto &ch : line_after_ifndef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = true; + inactive_code = false; + continue; + } + + if (macro == "1") { + defined = false; + inactive_code = true; + + continue; + } + + bool found = false; + + defined = true; + inactive_code = false; + + for (auto ¯o_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + found = true; + break; + } + } + + if (found) { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("else") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = true; + + continue; + } else { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("ifdef") != std::string::npos) { + auto line_after_ifdef = + hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); + std::string macro; + + for (auto &ch : line_after_ifdef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + defined = false; + inactive_code = true; + + for (auto ¯o_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + defined = true; + inactive_code = false; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("pragma") != std::string::npos) { + line_after_include = hdr_line.substr(hdr_line.find("pragma once")); + + // search for this file + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), + line_after_include); + + if (it == kAllIncludes.cend()) { + goto kIncludeFile; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("if") != std::string::npos) { + inactive_code = true; + + std::vector bpp_macro_condition_list = { + { + .fType = details::kEqual, + .fTypeName = "==", + }, + { + .fType = details::kNotEqual, + .fTypeName = "!=", + }, + { + .fType = details::kLesserThan, + .fTypeName = "<", + }, + { + .fType = details::kGreaterThan, + .fTypeName = ">", + }, + { + .fType = details::kLesserEqThan, + .fTypeName = "<=", + }, + { + .fType = details::kGreaterEqThan, + .fTypeName = ">=", + }, + }; + + int32_t good_to_go = 0; + + for (auto ¯o_condition : bpp_macro_condition_list) { + if (hdr_line.find(macro_condition.fTypeName) != std::string::npos) { + for (auto &found_macro : kMacros) { + if (hdr_line.find(found_macro.fName) != std::string::npos) { + good_to_go = + bpp_parse_if_condition(macro_condition, found_macro, + inactive_code, defined, hdr_line); + + break; + } + } + } + } + + if (good_to_go) continue; + + auto line_after_if = + hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); + std::string macro; + + for (auto &ch : line_after_if) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + // last try, is it defined to be one? + for (auto ¯o_ref : kMacros) { + if (macro_ref.fName.find(macro) != std::string::npos && + macro_ref.fValue == "1") { + inactive_code = false; + defined = true; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("warning") != std::string::npos) { + auto line_after_warning = + hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); + std::string message; + + for (auto &ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + std::cout << "Warning: " << message << std::endl; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("error") != std::string::npos) { + auto line_after_warning = + hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); + std::string message; + + for (auto &ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + throw std::runtime_error("Error: " + message); + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("inc ") != std::string::npos) { + line_after_include = + hdr_line.substr(hdr_line.find("inc ") + strlen("inc ")); + + kIncludeFile: + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), + line_after_include); + + if (it != kAllIncludes.cend()) { + continue; + } + + std::string path; + + kAllIncludes.push_back(line_after_include); + + bool enable = false; + bool not_local = false; + + for (auto &ch : line_after_include) { + if (ch == ' ') continue; + + if (ch == '<') { + not_local = true; + enable = true; + + continue; + } + + if (ch == '\'') { + enable = true; + continue; + } + + if (enable) { + if (not_local) { + if (ch == '>') break; + } else { + if (ch == '\'') { + break; + } + } + + path += ch; + } + } + + if (not_local) { + bool open = false; + + for (auto &include : kIncludes) { + std::string header_path = include; + header_path.push_back('/'); + header_path += path; + + std::ifstream header(header_path); + + if (!header.is_open()) continue; + + open = true; + + bpp_parse_file(header, pp_out); + + break; + } + + if (!open) { + throw std::runtime_error("bpp: no such include file: " + path); + } + } else { + std::ifstream header(kWorkingDir + path); + + if (!header.is_open()) + throw std::runtime_error("bpp: no such include file: " + path); + + bpp_parse_file(header, pp_out); + } + } else { + std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) + << "\n"; + continue; + } + } + } catch (std::out_of_range &oor) { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief main entrypoint of app. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSPreprocessor) { + try { + bool skip = false; + bool double_skip = false; + + details::bpp_macro macro_1; + macro_1.fName = "__true"; + macro_1.fValue = "1"; + + kMacros.push_back(macro_1); + + details::bpp_macro macro_0; + macro_0.fName = "__false"; + macro_0.fValue = "0"; + + kMacros.push_back(macro_0); + + details::bpp_macro macro_hcore; + macro_hcore.fName = "__MAHROUSS__"; + macro_hcore.fValue = "1"; + + kMacros.push_back(macro_hcore); + + for (auto index = 1UL; index < argc; ++index) { + if (skip) { + skip = false; + continue; + } + + if (double_skip) { + ++index; + double_skip = false; + continue; + } + + if (argv[index][0] == '/') { + if (strcmp(argv[index], "/version") == 0) { + printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); + return 0; + } + + if (strcmp(argv[index], "/help") == 0) { + printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) ZKA Technologies"); + printf("%s\n", "/working-dir : set directory to working path."); + printf("%s\n", "/include-dir : add directory to include path."); + printf("%s\n", "/def : def macro."); + printf("%s\n", "/version: print the version."); + printf("%s\n", "/help: show help."); + + return 0; + } + + if (strcmp(argv[index], "/include-dir") == 0) { + std::string inc = argv[index + 1]; + + skip = true; + + kIncludes.push_back(inc); + } + + if (strcmp(argv[index], "/working-dir") == 0) { + std::string inc = argv[index + 1]; + skip = true; + kWorkingDir = inc; + } + + if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && + argv[index + 2] != nullptr) { + std::string macro_key = argv[index + 1]; + + std::string macro_value; + bool is_string = false; + + for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); + ++argv_find_len) { + if (!isdigit(argv[index][argv_find_len])) { + is_string = true; + macro_value += "\""; + + break; + } + } + + macro_value += argv[index + 2]; + + if (is_string) macro_value += "\""; + + details::bpp_macro macro; + macro.fName = macro_key; + macro.fValue = macro_value; + + kMacros.push_back(macro); + + double_skip = true; + } + + continue; + } + + kFiles.emplace_back(argv[index]); + } + + if (kFiles.empty()) return MPCC_EXEC_ERROR; + + for (auto &file : kFiles) { + if (!std::filesystem::exists(file)) continue; + + std::ifstream file_descriptor(file); + std::ofstream file_descriptor_pp(file + ".pp"); + + bpp_parse_file(file_descriptor, file_descriptor_pp); + } + + return 0; + } catch (const std::runtime_error &e) { + std::cout << e.what() << '\n'; + } + + return 1; +} + +// Last rev 8-1-24 diff --git a/NDKKit/Sources/coff2ae.cxx b/NDKKit/Sources/coff2ae.cxx new file mode 100644 index 0000000..c9ea8c0 --- /dev/null +++ b/NDKKit/Sources/coff2ae.cxx @@ -0,0 +1,23 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file coff2ae.cxx +/// @brief COFF To AE, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/NDKKit/Sources/compile_flags.txt b/NDKKit/Sources/compile_flags.txt new file mode 100644 index 0000000..6ec6b8a --- /dev/null +++ b/NDKKit/Sources/compile_flags.txt @@ -0,0 +1,5 @@ +-std=c++20 +-I../ +-I../Headers +-I./ +-I./Detail/ diff --git a/NDKKit/Sources/cplusplus.cxx b/NDKKit/Sources/cplusplus.cxx new file mode 100644 index 0000000..ae4a300 --- /dev/null +++ b/NDKKit/Sources/cplusplus.cxx @@ -0,0 +1,1025 @@ +/* + * ======================================================== + * + * cplusplus + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// bugs: 0 + +#define __PK_USE_STRUCT_INSTEAD__ 1 + +#define kPrintF printf + +#define kOk (0) + +#define kSplashCxx() \ + kPrintF(kWhite "%s\n", "ZKA C++ Compiler Driver, (c) 2024 ZKA Electronics, all rights reserved.") + +// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* ZKA C++ driver */ +/* This is part of NDK. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief Optimized C++ Compiler. +/// @todo Throw error for scoped inside scoped variables when they get referenced outside. +/// @todo Add class/struct/enum support. + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNALS OF THE C COMPILER + +///////////////////////////////////// + +/// @internal +namespace detail +{ + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Offset based struct/class + struct CompilerStructMap final + { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; + +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cplusplus ] " << kWhite + << ((file == "cplusplus") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank + << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; + +///////////////////////////////////////// + +// ARGUMENTS REGISTERS (R8, R15) + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::vector kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static size_t kBracesCount = 0UL; + +/* @brief C++ compiler backend for the ZKA C++ driver */ +class CompilerBackendCPlusPlus final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCPlusPlus() = default; + ~CompilerBackendCPlusPlus() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); + + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override; +}; + +/// @internal compiler variables + +static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; + +static std::vector kRegisterMap; + +static std::vector cRegisters = { + "rbx", + "rsi", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "xmm12", + "xmm13", + "xmm14", + "xmm15", +}; + +/// @brief The PEF calling convention (caller must save rax, rbp) +/// @note callee must return via **rax**. +static std::vector cRegistersCall = { + "rcx", + "rdx", + "r8", + "r9", + "xmm8", + "xmm9", + "xmm10", + "xmm11", +}; + +static size_t kLevelFunction = 0UL; + +/// detail namespaces + +const char* CompilerBackendCPlusPlus::Language() +{ + return "ZKA C++"; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @name Compile +/// @brief Generate MASM assembly from a C++ source. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCPlusPlus::Compile(const std::string& text, + const char* file) +{ + if (text.empty()) + return false; + + // if (expr) + // int name = expr; + // expr; + + std::size_t index = 0UL; + std::vector> keywords_list; + + bool found = false; + static bool commentBlock = false; + + for (auto& keyword : kKeywords) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + switch (keyword.keyword_kind) + { + case CompilerKit::eKeywordKindCommentMultiLineStart: { + commentBlock = true; + return true; + } + case CompilerKit::eKeywordKindCommentMultiLineEnd: { + commentBlock = false; + break; + } + case CompilerKit::eKeywordKindCommentInline: { + break; + } + default: + break; + } + + if (text[text.find(keyword.keyword_name) - 1] == '+' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) + 1] == '=' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + + found = true; + } + } + + if (!found && !commentBlock) + { + for (size_t i = 0; i < text.size(); i++) + { + if (isalnum(text[i])) + { + detail::print_error("syntax error: " + text, file); + return false; + } + } + } + + for (auto& keyword : keywords_list) + { + auto syntax_tree = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + switch (keyword.first.keyword_kind) + { + case CompilerKit::KeywordKind::eKeywordKindIf: { + auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); + + if (expr.find(">=") != std::string::npos) + { + auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); + auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); + + size_t i = right.size() - 1; + + try + { + while (!std::isalnum(right[i])) + { + right.erase(i, 1); + --i; + } + + right.erase(0, i); + } + catch (...) + { + right.erase(0, i); + } + + i = left.size() - 1; + try + { + + while (!std::isalnum(left[i])) + { + left.erase(i, 1); + --i; + } + + left.erase(0, i); + } + catch (...) + { + left.erase(0, i); + } + + if (!isdigit(left[0]) || + !isdigit(right[0])) + { + auto indexRight = 0UL; + + auto& valueOfVar = !isdigit(left[0]) ? left : right; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + "," + cRegisters[indexRight + 1] + "\n"; + + goto done_iterarting_on_if; + } + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + ", " + cRegisters[indexRight + 1] + "\n"; + + break; + } + } + + done_iterarting_on_if: + + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue += "jge offset [rsp + 4]\n"; + } + + break; + } + case CompilerKit::KeywordKind::eKeywordKindFunctionStart: { + if (text.ends_with(";")) + { + break; + } + + for (auto& ch : text) + { + if (isdigit(ch)) + { + goto dont_accept; + } + } + + goto accept; + + dont_accept: + return true; + + accept: + std::string fnName = text; + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; + + ++kLevelFunction; + } + case CompilerKit::KeywordKind::eKeywordKindFunctionEnd: { + if (text.ends_with(";")) + break; + + --kLevelFunction; + + if (kRegisterMap.size() > cRegisters.size()) + { + --kLevelFunction; + } + + if (kLevelFunction < 1) + kRegisterMap.clear(); + break; + } + case CompilerKit::KeywordKind::eKeywordKindEndInstr: + case CompilerKit::KeywordKind::eKeywordKindVariableInc: + case CompilerKit::KeywordKind::eKeywordKindVariableDec: + case CompilerKit::KeywordKind::eKeywordKindVariableAssign: { + std::string valueOfVar = ""; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + valueOfVar = text.substr(text.find("+=") + 2); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + valueOfVar = text.substr(text.find("-=") + 2); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + { + valueOfVar = text.substr(text.find("=") + 1); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + break; + } + + while (valueOfVar.find(";") != std::string::npos && + keyword.first.keyword_kind != CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + valueOfVar.erase(valueOfVar.find(";")); + } + + std::string varName = text; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + varName.erase(varName.find("+=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + varName.erase(varName.find("-=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + { + varName.erase(varName.find("=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + varName.erase(varName.find(";")); + } + + static bool typeFound = false; + + for (auto& keyword : kKeywords) + { + if (keyword.keyword_kind == CompilerKit::eKeywordKindType) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + if (text[text.find(keyword.keyword_name)] == ' ') + { + typeFound = false; + continue; + } + + typeFound = true; + } + } + } + + std::string instr = "mov "; + + if (typeFound) + { + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + detail::print_error("Can't increment variable when it's being created.", file); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + detail::print_error("Can't decrement variable when it's being created.", file); + } + + if (kRegisterMap.size() > cRegisters.size()) + { + ++kLevelFunction; + } + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + std::size_t indexRight = 0UL; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + goto done; + } + + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + break; + } + + if (((int)indexRight - 1) < 0) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + } + + done: + kRegisterMap.push_back(varName); + } + else + { + if (kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindTypePtr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + instr = "add "; + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + instr = "sub "; + } + + std::string varErrCpy = varName; + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + std::size_t indxReg = 0UL; + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + while (valueOfVar.find(" ") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find(" "), 1); + } + + while (valueOfVar.find("\t") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find("\t"), 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + /// interpet boolean values, since we're on C++ + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != varName) + continue; + + std::size_t indexRight = 0ul; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != varName) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[indexRight - 1] + ", " + valueOfVar + "\n"; + break; + } + + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + varErrCpy, file); + } + } + + break; + } + case CompilerKit::KeywordKind::eKeywordKindReturn: { + auto pos = text.find("return") + strlen("return") + 1; + std::string subText = text.substr(pos); + subText = subText.erase(subText.find(";")); + size_t indxReg = 0UL; + + if (subText[0] != '\"' && + subText[0] != '\'') + { + if (!isdigit(subText[0])) + { + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != subText) + continue; + + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg] + "\r\nret\n"; + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + subText, file); + } + } + else + { + syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; + } + } + else + { + syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; + syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; + } + + break; + } + default: + break; + } + + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); + } + +_MpccOkay: + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCPlusPlusInterface() = default; + ~AssemblyCPlusPlusInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); + + [[maybe_unused]] + static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchAMD64; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCPlusPlusInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + + const char* cExts[] = kAsmFileExts; + + std::string dest = src_file; + dest += cExts[4]; + + if (dest.empty()) + { + dest = "CXX-NDK-"; + + std::random_device rd; + auto seed_data = std::array{}; + + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator(generator); + + auto id = gen(); + dest += uuids::to_string(id); + } + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "; Language: AMD64 assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; + (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" + << "\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.emplace_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string source; + + while (std::getline(src_fp, source)) + { + // Compile into an object file. + kCompilerBackend->Compile(source.c_str(), src.c_str()); + } + + for (auto& ast : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << ast.fUserValue; + } + + if (kAcceptableErrors > 0) + return -1; + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static void cxx_print_help() +{ + kSplashCxx(); + kPrintF("%s", "No help available, see:\n"); + kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExtListCxx \ + { \ + ".cpp", ".cxx", ".cc", ".c++", ".cp" \ + } + +NDK_MODULE(CompilerCPlusPlus) +{ + bool skip = false; + + kKeywords.push_back({.keyword_name = "if", .keyword_kind = CompilerKit::eKeywordKindIf}); + kKeywords.push_back({.keyword_name = "else", .keyword_kind = CompilerKit::eKeywordKindElse}); + kKeywords.push_back({.keyword_name = "else if", .keyword_kind = CompilerKit::eKeywordKindElseIf}); + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = CompilerKit::eKeywordKindNamespace}); + kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = CompilerKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = CompilerKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = CompilerKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = CompilerKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = CompilerKit::eKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + + kKeywords.push_back({.keyword_name = "(", .keyword_kind = CompilerKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = CompilerKit::eKeywordKindFunctionEnd}); + kKeywords.push_back({.keyword_name = "=", .keyword_kind = CompilerKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = CompilerKit::eKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = CompilerKit::eKeywordKindVariableDec}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = CompilerKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = CompilerKit::eKeywordKindPtr}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = CompilerKit::eKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = CompilerKit::eKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = CompilerKit::eKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = CompilerKit::eKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "public:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "private:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "final", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = CompilerKit::eKeywordKindReturn}); + kKeywords.push_back({.keyword_name = "/*", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "*/", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "//", .keyword_kind = CompilerKit::eKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = CompilerKit::eKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = CompilerKit::eKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = CompilerKit::eKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = CompilerKit::eKeywordKindLessEq}); + + kFactory.Mount(new AssemblyCPlusPlusInterface()); + kCompilerBackend = new CompilerBackendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) + { + if (argv[index][0] == '/') + { + if (skip) + { + skip = false; + continue; + } + + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cxx_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/max-errors") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + detail::print_error(err, "cplusplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + bool found = false; + + for (std::string ext : exts) + { + if (argv_i.find(ext) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + if (kState.fVerbose) + { + detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); + } + + return 1; + } + + if (kFactory.Compile(argv_i, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 +// diff --git a/NDKKit/Sources/elf2ae.cxx b/NDKKit/Sources/elf2ae.cxx new file mode 100644 index 0000000..451c706 --- /dev/null +++ b/NDKKit/Sources/elf2ae.cxx @@ -0,0 +1,22 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief COFF 2 AE entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/NDKKit/Sources/i64asm.cxx b/NDKKit/Sources/i64asm.cxx new file mode 100644 index 0000000..ed77988 --- /dev/null +++ b/NDKKit/Sources/i64asm.cxx @@ -0,0 +1,1484 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file i64asm.cxx +/// @author Amlal EL Mahrouss +/// @brief AMD64 Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +/// bugs: 0 + +/// feature request: 1 +/// Encode registers in mov, add, xor... + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_AMD64__ 1 + +#define kAssemblerPragmaSymStr "#" +#define kAssemblerPragmaSym '#' + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +static char kOutputArch = CompilerKit::kPefArchAMD64; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +constexpr auto cAMD64IPAlignment = 0x4U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +/// @brief keep it simple by default. +static std::int32_t kRegisterBitWidth = 16U; + +static bool kVerbose = false; + +static std::vector kAppBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kDefinedSymbols; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string& line); + +namespace detail +{ + void print_error(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + kStdErr << kRed << "[ i64asm ] " << kWhite + << ((file == "i64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + void print_warning(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (!file.empty()) + { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank + << std::endl; + } +} // namespace detail + +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief AMD64 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerAMD64) +{ + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = { + "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", + "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", + "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) + { + CpuOpcodeAMD64 code{ + .fName = opcodes_jump[i], + .fOpcode = static_cast(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) + { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) + { + if (argv[i][0] == '/') + { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " + "(c) ZKA Technologies.\n"; + return 0; + } + else if (strcmp(argv[i], "/h") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + + return 0; + } + else if (strcmp(argv[i], "/binary") == 0) + { + kOutputAsBinary = true; + continue; + } + else if (strcmp(argv[i], "/verbose") == 0) + { + kVerbose = true; + continue; + } + + kStdOut << "i64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) + { + kStdOut << "i64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) + { + if (object_output.find(ext) != std::string::npos) + { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) + { + if (kVerbose) + { + kStdOut << "i64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + while (std::getline(file_ptr, line)) + { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) + { + detail::print_error(ln, argv[i]); + continue; + } + + try + { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } + catch (const std::exception& e) + { + if (kVerbose) + { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "i64asm"); + } + + try + { + std::filesystem::remove(object_output); + } + catch (...) + { + } + + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) + { + if (kVerbose) + { + kStdOut << "i64asm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) + { + kStdErr << "i64asm: At least one record is needed to write an object " + "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + std::size_t record_count = 0UL; + + for (auto& rec : kRecords) + { + if (kVerbose) + kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; + + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; + + file_ptr_out << rec; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto& sym : kUndefinedSymbols) + { + CompilerKit::AERecordHeader _record_hdr{0}; + + if (kVerbose) + kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + + file_ptr_out << _record_hdr; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kAppBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto& byte : kAppBytes) + { + if (byte == 0) + continue; + + if (byte == 0xFF) + { + byte = 0; + } + + file_ptr_out << reinterpret_cast(&byte)[0]; + } + + if (kVerbose) + kStdOut << "i64asm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) + kStdOut << "i64asm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) + kStdOut << "i64asm: Exit failed.\n"; + + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string& line) +{ + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (CompilerKit::find_word(line, "import")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) + { + detail::print_error("Invalid import", "power-as"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) + { + if (j == ' ' || j == ',') + j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by i64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (CompilerKit::find_word(line, "export")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export") + 1); + + std::string name_copy = name; + + for (char& j : name) + { + if (j == ' ') + j = '$'; + } + + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != + kDefinedSymbols.end()) + { + detail::print_error("Symbol already defined.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + kDefinedSymbols.push_back(name); + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm +{ + // \brief authorize a brief set of characters. + static inline bool is_not_alnum_space(char c) + { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); + } + + bool is_valid(const std::string& str) + { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); + } +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, + const std::string& file) +{ + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + CompilerKit::find_word(line, kAssemblerPragmaSymStr) || + CompilerKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + { + if (line.find(';') != std::string::npos) + { + line.erase(line.find(';')); + } + else + { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non valid characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non alphanumeric characters.\nHere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) + { + if (line.find(',') + 1 == line.size()) + { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } + else + { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto& ch : substr) + { + if (ch != ' ' && ch != '\t') + { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + if (CompilerKit::find_word(line, opcodeAMD64.fName)) + { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; +} + +bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, + const std::string& file) +{ + if (CompilerKit::find_word(line, "export ")) + return true; + + struct RegMapAMD64 + { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector REGISTER_LIST{ + {.fName = "ax", .fModRM = 0x0}, + {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, + {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, + {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, + {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, + {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, + {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, + {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + // strict check here + if (CompilerKit::find_word(line, opcodeAMD64.fName) && + detail::algorithm::is_valid(line)) + { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (name.find("mov") != std::string::npos) + { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) + { + detail::print_error("Syntax error.", "i64asm"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector currentRegList; + + for (auto& reg : REGISTER_LIST) + { + std::vector regExt = {'e', 'r'}; + + for (auto& ext : regExt) + { + std::string registerName; + + if (bits > 16) + registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) + { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) + { + if (registerName[0] == 'r') + { + detail::print_error( + "invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back( + {.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) + onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) + { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || + currentRegList[1].fName[0] == 'r') + { + if (isdigit(currentRegList[0].fName[1]) && + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } + else if (isdigit(currentRegList[0].fName[1]) || + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) + { + if (!hasRBasedRegs && bits >= 32) + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x89); + } + else if (bits == 16) + { + if (hasRBasedRegs) + { + detail::print_error( + "Invalid combination of operands and registers.", "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + + if (currentRegList[1].fName[0] == 'r' && + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) + { + if (currentRegList[0].fName[0] == 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + else + { + if (currentRegList[0].fName[0] != 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | + currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } + else if (name == "int" || name == "into" || name == "intd") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } + else if (name == "jmp" || name == "call") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) + { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } + else + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) + { + if (foundInstruction) + { + detail::print_error("Syntax error: " + line, "i64asm"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) + { + kRegisterBitWidth = 64U; + } + else if (line.find("bits 32") != std::string::npos) + { + kRegisterBitWidth = 32U; + } + else if (line.find("bits 16") != std::string::npos) + { + kRegisterBitWidth = 16U; + } + else if (line.find("org") != std::string::npos) + { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) + { + if (kOrigin = strtol( + (line.substr(line.find("org") + strlen("org") + 1)).c_str(), + nullptr, base[i]); + kOrigin) + { + if (errno != 0) + { + continue; + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) + { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) + { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) + { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += cAMD64IPAlignment; + + return true; +} + +// Last rev 13-1-24 diff --git a/NDKKit/Sources/link.cxx b/NDKKit/Sources/link.cxx new file mode 100644 index 0000000..d59c982 --- /dev/null +++ b/NDKKit/Sources/link.cxx @@ -0,0 +1,741 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// @file link.cxx +/// @author Amlal EL Mahrouss (amlel) +/// @brief ZKA Technologies Linker. + +/// Last Rev: Sat Feb 24 CET 2024 + +/// @note Do not look up for anything with .code64/.data64/.zero64! +/// It will be loaded when program will start up! + +#include + +//! Assembler Kit +#include + +//! Preferred Executable Format +#include +#include +#include +#include +#include + +//! Dist version +#include + +//! Advanced Executable Object Format +#include + +//! C++ I/O headers. +#include +#include + +#define kLinkerVersion "ZKA Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" + +#define StringCompare(DST, SRC) strcmp(DST, SRC) + +#define kPefNoCpu 0U +#define kPefNoSubCpu 0U + +#define kWhite "\e[0;97m" +#define kStdOut (std::cout << kWhite) + +#define kLinkerDefaultOrigin kPefBaseOrigin +#define kLinkerId 0x5046FF +#define kLinkerAbiContainer "Container:Abi:" + +enum +{ + eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ + eABINewOSKrnl = 0x5046, /* PF (NewOSKrnl) */ + eABIMTL = 0x4650, /* FP (MTL firmware) */ + eABIInvalid = 1, +}; + +static std::string kOutput = ""; +static Int32 kAbi = eABINewOSKrnl; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = CompilerKit::kPefArchInvalid; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; +static Bool kVerbose = false; + +/* link is to be found, mld is to be found at runtime. */ +static const char* kLdDefineSymbol = ":UndefinedSymbol:"; +static const char* kLdDynamicSym = ":RuntimeSymbol:"; + +/* object code and list. */ +static std::vector kObjectList; +static std::vector kObjectBytes; + +#define kPrintF printf +#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) + +NDK_MODULE(NewOSLinker) +{ + bool is_executable = true; + + /** + * @brief parse flags and such. + * + */ + for (size_t i = 1; i < argc; ++i) + { + if (StringCompare(argv[i], "/help") == 0) + { + kLinkerSplash(); + kStdOut << "/version: Show linker version.\n"; + kStdOut << "/help: Show linker help.\n"; + kStdOut << "/verbose: Enable linker trace.\n"; + kStdOut << "/shared: Output as a shared PEF.\n"; + kStdOut << "/fat-bin: Output as a FAT PEF.\n"; + kStdOut << "/32x0: Output as a 32x0 PEF.\n"; + kStdOut << "/64x0: Output as a 64x0 PEF.\n"; + kStdOut << "/amd64: Output as a AMD64 PEF.\n"; + kStdOut << "/rv64: Output as a RISC-V PEF.\n"; + kStdOut << "/power64: Output as a POWER PEF.\n"; + kStdOut << "/arm64: Output as a ARM64 PEF.\n"; + kStdOut << "/output-file: Select the output file name.\n"; + + return 0; + } + else if (StringCompare(argv[i], "/version") == 0) + { + kLinkerSplash(); + return 0; + } + else if (StringCompare(argv[i], "/fat-bin") == 0) + { + kFatBinaryEnable = true; + + continue; + } + else if (StringCompare(argv[i], "/64x0") == 0) + { + kArch = CompilerKit::kPefArch64000; + + continue; + } + else if (StringCompare(argv[i], "/amd64") == 0) + { + kArch = CompilerKit::kPefArchAMD64; + + continue; + } + else if (StringCompare(argv[i], "/32x0") == 0) + { + kArch = CompilerKit::kPefArch32000; + + continue; + } + else if (StringCompare(argv[i], "/power64") == 0) + { + kArch = CompilerKit::kPefArchPowerPC; + + continue; + } + else if (StringCompare(argv[i], "/arm64") == 0) + { + kArch = CompilerKit::kPefArchARM64; + + continue; + } + else if (StringCompare(argv[i], "/verbose") == 0) + { + kVerbose = true; + + continue; + } + else if (StringCompare(argv[i], "/shared") == 0) + { + if (kOutput.empty()) + { + continue; + } + + if (kOutput.find(kPefExt) != std::string::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } + else if (StringCompare(argv[i], "/output-file") == 0) + { + kOutput = argv[i + 1]; + ++i; + + continue; + } + else + { + if (argv[i][0] == '/') + { + kStdOut << "link: unknown flag: " << argv[i] << "\n"; + return MPCC_EXEC_ERROR; + } + + kObjectList.emplace_back(argv[i]); + + continue; + } + } + + if (kOutput.empty()) + { + kStdOut << "link: no output filename set." << std::endl; + return MPCC_EXEC_ERROR; + } + + // sanity check. + if (kObjectList.empty()) + { + kStdOut << "link: no input files." << std::endl; + return MPCC_EXEC_ERROR; + } + else + { + namespace fs = std::filesystem; + + // check for existing files, if they don't throw an error. + for (auto& obj : kObjectList) + { + if (!fs::exists(obj)) + { + // if filesystem doesn't find file + // -> throw error. + kStdOut << "link: no such file: " << obj << std::endl; + return MPCC_EXEC_ERROR; + } + } + } + + // PEF expects a valid architecture when outputing a binary. + if (kArch == 0) + { + kStdOut << "link: no target architecture set, can't continue." << std::endl; + return MPCC_EXEC_ERROR; + } + + CompilerKit::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = CompilerKit::kPefKindExec; + pef_container.SubCpu = kSubArch; + pef_container.Linker = kLinkerId; // ZKA Technologies Linker + pef_container.Abi = kAbi; // Multi-Processor UX ABI + pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; + pef_container.Magic[1] = kPefMagic[1]; + pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; + pef_container.Magic[3] = kPefMagic[3]; + pef_container.Version = kPefVersion; + + // specify the start address, can be 0x10000 + pef_container.Start = kLinkerDefaultOrigin; + pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); + + std::ofstream outputFc(kOutput, std::ofstream::binary); + + if (outputFc.bad()) + { + if (kVerbose) + { + kStdOut << "link: error: " << strerror(errno) << "\n"; + } + + return MPCC_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector commandHdrsList; + CompilerKit::Utils::AEReadableProtocol readProto{}; + + for (const auto& i : kObjectList) + { + if (!std::filesystem::exists(i)) + continue; + + CompilerKit::AEHeader hdr{}; + + readProto.FP = std::ifstream(i, std::ifstream::binary); + readProto.FP >> hdr; + + auto ae_header = hdr; + + if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && + ae_header.fSize == sizeof(CompilerKit::AEHeader)) + { + if (ae_header.fArch != kArch) + { + if (kVerbose) + kStdOut << "link: info: is this a FAT binary? : "; + + if (!kFatBinaryEnable) + { + if (kVerbose) + kStdOut << "No.\n"; + + kStdOut << "link: error: object " << i + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + std::remove(kOutput.c_str()); + return MPCC_FAT_ERROR; + } + else + { + if (kVerbose) + { + kStdOut << "Yes.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= ae_header.fArch; + std::size_t cnt = ae_header.fCount; + + if (kVerbose) + kStdOut << "link: object header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = + new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); + + auto* ae_records = readProto.Read(raw_ae_records, cnt); + for (size_t ae_record_index = 0; ae_record_index < cnt; + ++ae_record_index) + { + CompilerKit::PEFCommandHeader command_header{0}; + size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; + + memcpy(command_header.Name, ae_records[ae_record_index].fName, + kPefNameLen); + + // check this header if it's any valid. + if (std::string(command_header.Name).find(".code64") == + std::string::npos && + std::string(command_header.Name).find(".data64") == + std::string::npos && + std::string(command_header.Name).find(".zero64") == + std::string::npos) + { + if (std::string(command_header.Name).find(kPefStart) == + std::string::npos && + *command_header.Name == 0) + { + if (std::string(command_header.Name).find(kLdDefineSymbol) != + std::string::npos) + { + goto ld_mark_header; + } + else + { + continue; + } + } + } + + if (std::string(command_header.Name).find(kPefStart) != + std::string::npos && + std::string(command_header.Name).find(".code64") != + std::string::npos) + { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offsetOfData; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = ae_header.fArch; + command_header.SubCpu = ae_header.fSubArch; + + if (kVerbose) + { + kStdOut << "link: object record: " + << ae_records[ae_record_index].fName << " was marked.\n"; + + kStdOut << "link: object record offset: " << command_header.Offset << "\n"; + } + + commandHdrsList.emplace_back(command_header); + } + + delete[] raw_ae_records; + + std::vector bytes; + bytes.resize(ae_header.fCodeSize); + + readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); + readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); + + for (auto& byte : bytes) + { + kObjectBytes.push_back(byte); + } + + readProto.FP.close(); + + continue; + } + + kStdOut << "link: not an object: " << i << std::endl; + std::remove(kOutput.c_str()); + + // don't continue, it is a fatal error. + return MPCC_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + outputFc << pef_container; + + if (kVerbose) + { + kStdOut << "link: wrote container header.\n"; + } + + outputFc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector not_found; + std::vector symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& commandHdr : commandHdrsList) + { + // check if this symbol needs to be resolved. + if (std::string(commandHdr.Name).find(kLdDefineSymbol) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; + + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it == not_found.end()) + { + not_found.emplace_back(commandHdr.Name); + } + } + + symbols.emplace_back(commandHdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); + ++not_found_idx) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdrsList[not_found_idx].Name)); + it != not_found.end()) + { + std::string symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) + continue; + + // erase the lookup prefix. + symbol_imp.erase( + 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != std::string::npos) + symbol_imp.erase(symbol_imp.find('$'), 1); + + // the reason we do is because, this may not match the symbol, and we need + // to look for other matching symbols. + for (auto& commandHdr : commandHdrsList) + { + if (std::string(commandHdr.Name).find(symbol_imp) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDefineSymbol) == + std::string::npos) + { + std::string undefined_symbol = commandHdr.Name; + auto result_of_sym = + undefined_symbol.substr(undefined_symbol.find(symbol_imp)); + + for (int i = 0; result_of_sym[i] != 0; ++i) + { + if (result_of_sym[i] != symbol_imp[i]) + goto ld_continue_search; + } + + not_found.erase(it); + + if (kVerbose) + kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) + { + if (kVerbose) + kStdOut + << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " + "against your compiler's runtime library.\n"; + + kStdOut << "link: undefined entrypoint " << kPefStart + << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + CompilerKit::PEFCommandHeader dateHeader{}; + + time_t timestamp = time(nullptr); + + std::string timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strcpy(dateHeader.Name, timeStampStr.c_str()); + + dateHeader.Flags = 0; + dateHeader.Kind = CompilerKit::kPefZero; + dateHeader.Offset = outputFc.tellp(); + dateHeader.Size = timeStampStr.size(); + + commandHdrsList.push_back(dateHeader); + + CompilerKit::PEFCommandHeader abiHeader{}; + + std::string abi = kLinkerAbiContainer; + + switch (kArch) + { + case CompilerKit::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case CompilerKit::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case CompilerKit::kPefArch32000: + case CompilerKit::kPefArch64000: { + abi += "MHRA"; + break; + } + default: { + abi += " IDK"; + break; + } + } + + memcpy(abiHeader.Name, abi.c_str(), abi.size()); + + abiHeader.Size = abi.size(); + abiHeader.Offset = outputFc.tellp(); + abiHeader.Flags = 0; + abiHeader.Kind = CompilerKit::kPefLinkerID; + + commandHdrsList.push_back(abiHeader); + + CompilerKit::PEFCommandHeader uuidHeader{}; + + std::random_device rd; + + auto seedData = std::array{}; + std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); + std::seed_seq seq(std::begin(seedData), std::end(seedData)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid id = gen(); + auto uuidStr = uuids::to_string(id); + + memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), + uuidStr.size()); + + uuidHeader.Size = 16; + uuidHeader.Offset = outputFc.tellp(); + uuidHeader.Flags = 0; + uuidHeader.Kind = CompilerKit::kPefZero; + + commandHdrsList.push_back(uuidHeader); + + // prepare a symbol vector. + std::vector undefSymbols; + std::vector duplSymbols; + std::vector resolveSymbols; + + constexpr Int32 cPaddingOffset = 16; + + size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; + commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) + { + if (std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + std::string symbolName = commandHdrsList[commandHeaderIndex].Name; + + if (!symbolName.empty()) + { + undefSymbols.emplace_back(symbolName); + } + + commandHdrsList[commandHeaderIndex].Offset += previousOffset; + previousOffset += commandHdrsList[commandHeaderIndex].Size; + + std::string name = commandHdrsList[commandHeaderIndex].Name; + + /// so this is valid when we get to the entrypoint. + /// it is always a code64 container. And should equal to kPefStart as well. + /// this chunk of code updates the pef_container.Start with the updated offset. + if (name.find(kPefStart) != std::string::npos && + name.find(".code64") != std::string::npos) + { + pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; + auto tellCurPos = outputFc.tellp(); + + outputFc.seekp(0); + outputFc << pef_container; + + outputFc.seekp(tellCurPos); + } + + if (kVerbose) + { + kStdOut << "link: command header name: " << name << "\n"; + kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; + } + + outputFc << commandHdrsList[commandHeaderIndex]; + + for (size_t subCommandHeaderIndex = 0UL; + subCommandHeaderIndex < commandHdrsList.size(); + ++subCommandHeaderIndex) + { + if (subCommandHeaderIndex == commandHeaderIndex) + continue; + + if (std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + { + kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; + + if (commandHdr.Name == + std::string(commandHdrsList[commandHeaderIndex].Name)) + { + if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), + commandHdr.Name) == duplSymbols.cend()) + { + duplSymbols.emplace_back(commandHdr.Name); + } + + if (kVerbose) + kStdOut << "link: found duplicate symbol: " << commandHdr.Name + << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!duplSymbols.empty()) + { + for (auto& symbol : duplSymbols) + { + kStdOut << "link: multiple symbols of " << symbol << ".\n"; + } + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + // step 2.5: write program bytes. + + for (auto byte : kObjectBytes) + { + outputFc << byte; + } + + if (kVerbose) + kStdOut << "link: wrote contents of: " << kOutput << "\n"; + + // step 3: check if we have those symbols + + std::vector unrefSyms; + + for (auto& commandHdr : commandHdrsList) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it != not_found.end()) + { + unrefSyms.emplace_back(commandHdr.Name); + } + } + + if (!unrefSyms.empty()) + { + for (auto& unreferenced_symbol : unrefSyms) + { + kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; + } + } + + if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || + !unrefSyms.empty()) + { + if (kVerbose) + kStdOut << "link: file: " << kOutput + << ", is corrupt, removing file...\n"; + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + return 0; +} + +// Last rev 13-1-24 diff --git a/NDKKit/Sources/power-as.cxx b/NDKKit/Sources/power-as.cxx new file mode 100644 index 0000000..8a6b7ef --- /dev/null +++ b/NDKKit/Sources/power-as.cxx @@ -0,0 +1,976 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file power-as.cxx +/// @author Amlal EL Mahrouss +/// @brief POWER Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that li will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_PPC__ 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +constexpr auto cPowerIPAlignment = 0x4U; + +static CharType kOutputArch = CompilerKit::kPefArchPowerPC; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +static bool kVerbose = false; + +static std::vector kBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector kRecords; +static std::vector kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string &line); + +namespace detail { +void print_error(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << kRed << "[ power-as ] " << kWhite + << ((file == "power-as") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ power-as ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(3); + + ++kAcceptableErrors; +} + +void print_warning(std::string reason, const std::string &file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + if (!file.empty()) { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ power-as ] " << kWhite << reason << kBlank + << std::endl; +} +} // namespace detail + +/// Do not move it on top! it uses the assembler detail namespace! +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief POWER assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerPowerPC) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: " << kDistVersion << "\npower-as: " + "Copyright (c) " + "ZKA Technologies.\n"; + return 0; + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version,/v: print program version.\n"; + kStdOut << "/verbose: print verbose output.\n"; + kStdOut << "/binary: output as flat binary.\n"; + + return 0; + } else if (strcmp(argv[i], "/binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "/verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "power-as: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "power-as: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto &ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "power-as: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderPowerPC asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + detail::print_error(ln, argv[i]); + continue; + } + + try { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } catch (const std::exception &e) { + if (kVerbose) { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "power-as"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "power-as: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) { + kStdErr << "power-as: At least one record is needed to write an object " + "file.\npower-as: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + std::size_t record_count = 0UL; + + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; + ++record_count; + + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "power-as: Wrote record " << record_hdr.fName << "...\n"; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto &sym : kUndefinedSymbols) { + CompilerKit::AERecordHeader undefined_sym{0}; + + if (kVerbose) + kStdOut << "power-as: Wrote symbol " << sym << " to file...\n"; + + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; + + ++record_count; + + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); + + file_ptr_out << undefined_sym; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "power-as: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto &byte : kBytes) { + file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); + } + + if (kVerbose) kStdOut << "power-as: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "power-as: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "power-as: Exit failed.\n"; + + return MPCC_EXEC_ERROR; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string &line) { + // import is the opposite of export, it signals to the li + // that we need this symbol. + if (CompilerKit::find_word(line, "import")) { + if (kOutputAsBinary) { + detail::print_error("Invalid import directive in flat binary mode.", + "power-as"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) { + detail::print_error("Invalid import", "power-as"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char &j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by power-as to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (CompilerKit::find_word(line, "export")) { + if (kOutputAsBinary) { + detail::print_error("Invalid export directive in flat binary mode.", + "power-as"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export")); + + std::string name_copy = name; + + for (char &j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm { +// \brief authorize a brief set of characters. +static inline bool is_not_alnum_space(char c) { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.')); +} + +bool is_valid(const std::string &str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, + const std::string &file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + /// does the line contains valid input? + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) { + if (line.find(',') + 1 == line.size()) { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } else { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto &ch : substr) { + if (ch != ' ' && ch != '\t') { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + + // these do take an argument. + std::vector operands_inst = {"stw", "li"}; + + // these don't. + std::vector filter_inst = {"blr", "bl", "sc"}; + + for (auto &opcodePPC : kOpcodesPowerPC) { + if (CompilerKit::find_word(line, opcodePPC.name)) { + for (auto &op : operands_inst) { + // if only the instruction was found. + if (line == op) { + err_str += "\nMalformed "; + err_str += op; + err_str += " instruction, here -> "; + err_str += line; + } + } + + // if it is like that -> addr1, 0x0 + if (auto it = + std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); + it == filter_inst.cend()) { + if (CompilerKit::find_word(line, opcodePPC.name)) { + if (!isspace( + line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { + err_str += "\nMissing space between "; + err_str += opcodePPC.name; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; +} + +bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, + std::string &jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) { + if (errno != 0) { + detail::print_error("invalid hex number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "power-as: found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) { + if (errno != 0) { + detail::print_error("invalid binary number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "power-as: found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) { + if (errno != 0) { + detail::print_error("invalid octal number: " + jump_label, "power-as"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "power-as: found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char &i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + CompilerKit::NumberCast64 num( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char &i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "power-as: found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, + const std::string &file) { + if (CompilerKit::find_word(line, "export")) return true; + if (!detail::algorithm::is_valid(line)) return true; + + for (auto &opcodePPC : kOpcodesPowerPC) { + // strict check here + if (CompilerKit::find_word(line, opcodePPC.name)) { + std::string name(opcodePPC.name); + std::string jump_label, cpy_jump_label; + std::vector found_registers_index; + + // check funct7 type. + switch (opcodePPC.ops->type) { + default: { + NumberCast32 num(opcodePPC.opcode); + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + break; + } + case BADDR: + case PCREL: { + auto num = GetNumber32(line, name); + + kBytes.emplace_back(num.number[0]); + kBytes.emplace_back(num.number[1]); + kBytes.emplace_back(num.number[2]); + kBytes.emplace_back(0x48); + + break; + } + /// General purpose, float, vector operations. Everything that involve + /// registers. + case G0REG: + case FREG: + case VREG: + case GREG: { + // \brief how many registers we found. + std::size_t found_some_count = 0UL; + std::size_t register_count = 0UL; + std::string opcodeName = opcodePPC.name; + std::size_t register_sum = 0; + + NumberCast64 num(opcodePPC.opcode); + + for (size_t line_index = 0UL; line_index < line.size(); + line_index++) { + if (line[line_index] == kAsmRegisterPrefix[0] && + isdigit(line[line_index + 1])) { + std::string register_syntax = kAsmRegisterPrefix; + register_syntax += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + register_syntax += line[line_index + 2]; + + std::string reg_str; + reg_str += line[line_index + 1]; + + if (isdigit(line[line_index + 2])) + reg_str += line[line_index + 2]; + + // it ranges from r0 to r19 + // something like r190 doesn't exist in the instruction set. + if (isdigit(line[line_index + 3]) && + isdigit(line[line_index + 2])) { + reg_str += line[line_index + 3]; + detail::print_error( + "invalid register index, r" + reg_str + + "\nnote: The POWER accepts registers from r0 to r32.", + file); + throw std::runtime_error("invalid_register_index"); + } + + // finally cast to a size_t + std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + + if (reg_index > kAsmRegisterLimit) { + detail::print_error("invalid register index, r" + reg_str, + file); + throw std::runtime_error("invalid_register_index"); + } + + if (opcodeName == "li") { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + auto num = GetNumber32(line, reg_str); + + kBytes.push_back(num.number[0]); + kBytes.push_back(num.number[1]); + kBytes.push_back(numIndex); + kBytes.push_back(0x38); + + // check if bigger than two. + for (size_t i = 2; i < 4; i++) { + if (num.number[i] > 0) { + detail::print_warning("number overflow on li operation.", + file); + break; + } + } + + break; + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + if (register_sum == 0) { + for (size_t indexReg = 0UL; indexReg < reg_index; + ++indexReg) { + register_sum += 0x20; + } + } else { + register_sum += reg_index; + } + } + + if (opcodeName == "mr") { + switch (register_count) { + case 0: { + kBytes.push_back(0x78); + + char numIndex = 0x3; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x8; + } + + kBytes.push_back(numIndex); + + break; + } + case 1: { + char numIndex = 0x1; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + for (size_t i = 0; i != reg_index; i++) { + kBytes[kBytes.size() - 1] += 0x8; + } + + kBytes[kBytes.size() - 1] -= 0x8; + + kBytes.push_back(numIndex); + + if (reg_index >= 10 && reg_index < 20) + kBytes.push_back(0x7d); + else if (reg_index >= 20 && reg_index < 30) + kBytes.push_back(0x7e); + else if (reg_index >= 30) + kBytes.push_back(0x7f); + else + kBytes.push_back(0x7c); + + break; + } + default: + break; + } + + ++register_count; + ++found_some_count; + } + + if (opcodeName == "addi") { + if (found_some_count == 2 || found_some_count == 0) + kBytes.emplace_back(reg_index); + else if (found_some_count == 1) + kBytes.emplace_back(0x00); + + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("cmp") != std::string::npos) { + ++found_some_count; + + if (found_some_count > 3) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + } + + if (opcodeName.find("mf") != std::string::npos || + opcodeName.find("mt") != std::string::npos) { + char numIndex = 0; + + for (size_t i = 0; i != reg_index; i++) { + numIndex += 0x20; + } + + num.number[2] += numIndex; + + ++found_some_count; + + if (found_some_count > 1) { + detail::print_error("Too much registers. -> " + line, file); + throw std::runtime_error("too_much_regs"); + } + + if (kVerbose) { + kStdOut << "power-as: Found register: " << register_syntax + << "\n"; + kStdOut << "power-as: Amount of registers in instruction: " + << found_some_count << "\n"; + } + + if (reg_index >= 10 && reg_index < 20) + num.number[3] = 0x7d; + else if (reg_index >= 20 && reg_index < 30) + num.number[3] = 0x7e; + else if (reg_index >= 30) + num.number[3] = 0x7f; + else + num.number[3] = 0x7c; + + for (auto ch : num.number) { + kBytes.emplace_back(ch); + } + } + + found_registers_index.push_back(reg_index); + } + } + + if (opcodeName == "addi") { + kBytes.emplace_back(0x38); + } + + if (opcodeName.find("cmp") != std::string::npos) { + char rightReg = 0x0; + + for (size_t i = 0; i != found_registers_index[1]; i++) { + rightReg += 0x08; + } + + kBytes.emplace_back(0x00); + kBytes.emplace_back(rightReg); + kBytes.emplace_back(found_registers_index[0]); + kBytes.emplace_back(0x7c); + } + + if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { + size_t offset = 0UL; + + if (line.find('+') != std::string::npos) { + auto number = GetNumber32(line.substr(line.find("+")), "+"); + offset = number.raw; + } + + kBytes.push_back(offset); + kBytes.push_back(0x00); + kBytes.push_back(register_sum); + + kBytes.emplace_back(0x90); + } + + if (opcodeName == "mr") { + if (register_count == 1) { + detail::print_error("Too few registers. -> " + line, file); + throw std::runtime_error("too_few_registers"); + } + } + + // we're not in immediate addressing, reg to reg. + if (opcodePPC.ops->type != GREG) { + // remember! register to register! + if (found_some_count == 1) { + detail::print_error( + "Unrecognized register found.\ntip: each power-as register " + "starts with 'r'.\nline: " + + line, + file); + + throw std::runtime_error("not_a_register"); + } + } + + if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { + detail::print_error( + "invalid combination of opcode and registers.\nline: " + line, + file); + throw std::runtime_error("invalid_comb_op_reg"); + } + + break; + } + } + + kOrigin += cPowerIPAlignment; + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/NDKKit/Sources/power-cc.cxx b/NDKKit/Sources/power-cc.cxx new file mode 100644 index 0000000..4c07a04 --- /dev/null +++ b/NDKKit/Sources/power-cc.cxx @@ -0,0 +1,1645 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kOk 0 + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief POWER C Compiler. + +///////////////////// + +/// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +/// INTERNAL STRUCT OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector> fOffsets; + }; + + struct CompilerState final + { + std::vector fSyntaxTreeList; + std::vector kStackFrame; + std::vector kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + file.erase(file.find(".pp"), 3); + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "POWER C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector kCompilerVariables; +static std::vector kCompilerFunctions; +static std::vector kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) + value.erase(value.find(' '), 1); + + while (value.find("import") != std::string::npos) + value.erase(value.find("import"), strlen("import")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) + { + if (value.find(reg.fName) != std::string::npos) + { + found = true; + syntaxLeaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) + syntaxLeaf.fUserValue += "r0"; + } + + syntaxLeaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + + " \ndword export .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error( + "assignement of value inside a struct " + textBuffer, file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } + else + { + substr += "\tli "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + kCompilerVariables.push_back({.fName = substr}); + + if (textBuffer[text_index] == ';') + break; + + std::string reg = kAsmRegisterPrefix; + + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); + + auto newSubstr = substr.substr(substr.find(" ")); + + std::string symbol; + + for (size_t start = 0; start < newSubstr.size(); ++start) + { + if (newSubstr[start] == ',') + break; + + if (newSubstr[start] == ' ') + continue; + + symbol += (newSubstr[start]); + } + + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + + syntaxLeaf.fUserValue += + "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tli r31, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + + syntaxLeaf.fUserValue += "\n\tblr\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (CompilerKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (CompilerKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector opens; + std::vector closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector keywords = {"ld", "stw", "add", "sub", "or"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (CompilerKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import ") != std::string::npos) + { + std::string range = "import "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), + range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLangPowerPC) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/ReadMe.md b/ReadMe.md index 4633971..14dfacf 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,16 +1,16 @@ -# NDK C++ SDK for ZKA. +# NDKKit, C++ SDK for ZKA. -## Installing +## Installing: -Start by cloning the repo: +Start by cloning the repo. ``` git clone git@bitbucket.org:mahrouss/codetools.git ``` -## Running makefiles +## Running makefiles: -And then: +And then run the makefile according to your platform. ``` make -f .make all diff --git a/Sources/32asm.cxx b/Sources/32asm.cxx deleted file mode 100644 index 23111bc..0000000 --- a/Sources/32asm.cxx +++ /dev/null @@ -1,52 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 32asm.cxx -// @author ZKA Technologies -// @brief 32x0 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_32x0__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 32x0 Assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/64asm.cxx b/Sources/64asm.cxx deleted file mode 100644 index 0a92157..0000000 --- a/Sources/64asm.cxx +++ /dev/null @@ -1,954 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 64asm.cxx -// @author Amlal EL Mahrouss -// @brief 64x000 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_64x0__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -static char kOutputArch = CompilerKit::kPefArch64000; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -constexpr auto c64x0IPAlignment = 0x4U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static bool kVerbose = false; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ 64asm ] " << kWhite - << ((file == "64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ 64asm ] " << kWhite << reason << kBlank << std::endl; -} -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 64x0 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssembler64000) { - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '/') { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { - kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " - "Logic.\n"; - kStdOut << "/version: Print program version.\n"; - kStdOut << "/verbose: Print verbose output.\n"; - kStdOut << "/binary: Output as flat binary.\n"; - kStdOut << "/64xxx: Compile for a subset of the X64000.\n"; - - return 0; - } else if (strcmp(argv[i], "/binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "/verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::Encoder64x0 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "64asm"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "64asm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "64asm: At least one record is needed to write an object " - "file.\n64asm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "64asm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) - kStdOut << "64asm: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "64asm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "64asm: Exit failed.\n"; - - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import")); - - /// sanity check to avoid stupid linker errors. - if (name.size() == 0) { - detail::print_error("Invalid import", "power-as"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by 64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export")); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; - - // these don't. - std::vector filter_inst = {"jlr", "jrl", "int"}; - - for (auto &opcode64x0 : kOpcodes64x0) { - if (line.find(opcode64x0.fName) != std::string::npos) { - if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; - - for (auto &op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), - opcode64x0.fName); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + - strlen(opcode64x0.fName)])) { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_hex_number"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "64asm: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "64asm: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "64asm: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "64asm: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::Encoder64x0::WriteLine(std::string &line, - const std::string &file) { - if (CompilerKit::find_word(line, "export ")) return true; - - for (auto &opcode64x0 : kOpcodes64x0) { - // strict check here - if (CompilerKit::find_word(line, opcode64x0.fName) && - detail::algorithm::is_valid(line)) { - std::string name(opcode64x0.fName); - std::string jump_label, cpy_jump_label; - - kBytes.emplace_back(opcode64x0.fOpcode); - kBytes.emplace_back(opcode64x0.fFunct3); - kBytes.emplace_back(opcode64x0.fFunct7); - - // check funct7 type. - switch (opcode64x0.fFunct7) { - // reg to reg means register to register transfer operation. - case kAsmRegToReg: - case kAsmImmediate: { - // \brief how many registers we found. - std::size_t found_some = 0UL; - - for (size_t line_index = 0UL; line_index < line.size(); - line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && - isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (kOutputArch == CompilerKit::kPefArch64000) { - if (isdigit(line[line_index + 3]) && - isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - detail::print_error( - "invalid register index, r" + reg_str + - "\nnote: The 64x0 accepts registers from r0 to r20.", - file); - throw std::runtime_error("invalid_register_index"); - } - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - detail::print_error("invalid register index, r" + reg_str, - file); - throw std::runtime_error("invalid_register_index"); - } - - kBytes.emplace_back(reg_index); - ++found_some; - - if (kVerbose) { - kStdOut << "64asm: Register found: " << register_syntax << "\n"; - kStdOut << "64asm: Register amount in instruction: " - << found_some << "\n"; - } - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode64x0.fFunct7 != kAsmImmediate) { - // remember! register to register! - if (found_some == 1) { - detail::print_error( - "Too few registers.\ntip: each 64asm register " - "starts with 'r'.\nline: " + - line, - file); - throw std::runtime_error("not_a_register"); - } - } - - if (found_some < 1 && name != "ldw" && name != "lda" && - name != "stw") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "add") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "sub") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - if (found_some > 0 && name == "pop") { - detail::print_error( - "invalid combination for opcode 'pop'.\ntip: it expects " - "nothing.\nline: " + - line, - file); - throw std::runtime_error("invalid_comb_op_pop"); - } - } - default: - break; - } - - // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { - auto where_string = name; - - // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || - name == "sta") - where_string = ","; - - jump_label = line; - - auto found_sym = false; - - while (jump_label.find(where_string) != std::string::npos) { - jump_label = jump_label.substr(jump_label.find(where_string) + - where_string.size()); - - while (jump_label.find(" ") != std::string::npos) { - jump_label.erase(jump_label.find(" "), 1); - } - - if (jump_label[0] != kAsmRegisterPrefix[0] && - !isdigit(jump_label[1])) { - if (found_sym) { - detail::print_error( - "invalid combination of opcode and operands.\nhere -> " + - jump_label, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } else { - // death trap installed. - found_sym = true; - } - } - } - - cpy_jump_label = jump_label; - - // replace any spaces with $ - if (jump_label[0] == ' ') { - while (jump_label.find(' ') != std::string::npos) { - if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; - - jump_label.erase(jump_label.find(' '), 1); - } - } - - if (!this->WriteNumber(0, jump_label)) { - // sta expects this: sta 0x000000, r0 - if (name == "sta") { - detail::print_error( - "invalid combination of opcode and operands.\nHere ->" + line, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } - } else { - if (name == "sta" && - cpy_jump_label.find("import ") != std::string::npos) { - detail::print_error("invalid usage import on 'sta', here: " + line, - file); - throw std::runtime_error("invalid_sta_usage"); - } - } - - goto asm_write_label; - } - - // This is the case where we jump to a label, it is also used as a goto. - if (name == "lda" || name == "sta") { - asm_write_label: - if (cpy_jump_label.find('\n') != std::string::npos) - cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); - - if (cpy_jump_label.find("import") != std::string::npos) { - cpy_jump_label.erase(cpy_jump_label.find("import"), strlen("import")); - - if (name == "sta") { - detail::print_error("import is not allowed on a sta operation.", - file); - throw std::runtime_error("import_sta_op"); - } else { - goto asm_end_label_cpy; - } - } - - if (name == "lda" || name == "sta") { - for (auto &label : kOriginLabel) { - if (cpy_jump_label == label.first) { - if (kVerbose) { - kStdOut << "64asm: Replace label " << cpy_jump_label - << " to address: " << label.second << std::endl; - } - - CompilerKit::NumberCast64 num(label.second); - - for (auto &num : num.number) { - kBytes.push_back(num); - } - - goto asm_end_label_cpy; - } - } - - if (cpy_jump_label[0] == '0') { - switch (cpy_jump_label[1]) { - case 'x': - case 'o': - case 'b': - if (this->WriteNumber(0, cpy_jump_label)) - goto asm_end_label_cpy; - - break; - default: - break; - } - - if (isdigit(cpy_jump_label[0])) { - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - } - } - } - - if (cpy_jump_label.size() < 1) { - detail::print_error("label is empty, can't jump on it.", file); - throw std::runtime_error("label_empty"); - } - - /// don't go any further if: - /// load word (ldw) or store word. (stw) - - if (name == "ldw" || name == "stw") break; - - auto mld_reloc_str = std::to_string(cpy_jump_label.size()); - mld_reloc_str += kUndefinedSymbol; - mld_reloc_str += cpy_jump_label; - - bool ignore_back_slash = false; - - for (auto &reloc_chr : mld_reloc_str) { - if (reloc_chr == '\\') { - ignore_back_slash = true; - continue; - } - - if (ignore_back_slash) { - ignore_back_slash = false; - continue; - } - - kBytes.push_back(reloc_chr); - } - - kBytes.push_back('\0'); - goto asm_end_label_cpy; - } - - asm_end_label_cpy: - kOrigin += c64x0IPAlignment; - - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/64x0-cc.cxx b/Sources/64x0-cc.cxx deleted file mode 100644 index 4adf7f8..0000000 --- a/Sources/64x0-cc.cxx +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: ? -/// TODO: - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* C driver */ -/* This is part of the NDK. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file 64x0-cc.cxx -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kOk (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public CompilerKit::CompilerBackend -{ -public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char* text, const char* file); - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override - { - return "64k C"; - } -}; - -static CompilerBackendCLang* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace detail -{ - union number_cast final { - public: - number_cast(UInt64 _Raw) - : _Raw(_Raw) - { - } - - public: - char _Num[8]; - UInt64 _Raw; - }; - - union double_cast final { - public: - double_cast(float _Raw) - : _Raw(_Raw) - { - } - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string& text, const char* file) -{ - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) - { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) - { - if (substr[y] == ' ') - { - while (match_type.find(' ') != std::string::npos) - { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) - { - if (clType.fName == match_type) - { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) - { - break; - } - - if (textBuffer.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) - { - if (textBuffer[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) - { - if (textBuffer[value_index] == ';') - break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') - { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, import "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword export .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (textBuffer[text_index] == ';' && kInStruct) - continue; - - if (textBuffer.find("typedef ") != std::string::npos) - continue; - - if (textBuffer[text_index] == '=' && kInStruct) - { - detail::print_error("assignement of value in struct " + textBuffer, - file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : textBuffer) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) - { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (textBuffer.find("*") != std::string::npos) - { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } - else - { - substr += "\tldw "; - } - } - else if (textBuffer.find('=') != std::string::npos && !kInBraces) - { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') - { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) - { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (textBuffer[text_index] == '=') - break; - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) - { - if (textBuffer[idx] == ',') - continue; - - if (textBuffer[idx] == ' ') - continue; - - if (textBuffer[idx] == ')') - break; - } - - for (char substr_first_index : textBuffer) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) - args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : textBuffer) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') - break; - - substr += _text_i; - } - - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') - { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) - { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') - { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) - kIfFound = false; - - if (kInStruct) - kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char* text, const char* file) -{ - std::string err_str; - std::string ln = text; - - if (ln.empty()) - { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (isalnum(ln[i])) - { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) - return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) - { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '\'') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } - else if (ln.find('"') != std::string::npos) - { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '"') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - else - { - break; - } - } - } - } - else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) - { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) - { - if (ln.find(forbidden) != std::string::npos) - { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final - { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, - {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, - {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, - {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, - {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, - {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, - {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, - {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, - {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, - {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) - { - if (ln.find(variable.fBegin) != std::string::npos) - { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') - ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == variable.fEnd[0]) - { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) - { - if (ln[index_keyword] == ' ') - { - continue; - } - - if (isdigit(ln[index_keyword])) - { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) - { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") - { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') - { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) - { - if (var.fValue.find(keyword) != std::string::npos) - { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) - { - if (fn.find(keyword[0]) != std::string::npos) - { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) - { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') - break; - - if (fn[where_begin] != keyword[keyword_begin]) - { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) - { - err_str.clear(); - goto cc_next; - } - else - { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) - return err_str; - - if (keyword.find(".") != std::string::npos) - return err_str; - - if (isalnum(keyword[0])) - err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (CompilerKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCCInterface); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCCInterface::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerBackend->Compile(line_src, src.data()); - } - else - { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) - return -1; - - std::vector keywords = {"ldw", "stw", "lda", "sta", - "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("import " + needle) != - std::string::npos) - { - std::string range = "import " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("import " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "sub") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "ZKA C Driver, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_MODULE(NewOSCompilerCLang64x0) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '/') - { - if (strcmp(argv[index], "/v") == 0 || - strcmp(argv[index], "/version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "/verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) - { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "/dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "/fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) - { - if (kState.fVerbose) - { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx deleted file mode 100644 index 9f1b768..0000000 --- a/Sources/AssemblyFactory.cxx +++ /dev/null @@ -1,59 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include - -/** - * @file AssemblyFactory.cxx - * @author amlal (amlal@zeta.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, ZKA Technologies - * - */ - -#include - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit -{ - ///! @brief Compile for specific format (ELF, PEF, ZBIN) - Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept - { - if (sourceFile.length() < 1 || !fMounted) - return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); - } - - ///! @brief mount assembly backend. - void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept - { - if (mountPtr) - { - fMounted = mountPtr; - } - } - - ///! @brief Unmount assembler. - AssemblyInterface* AssemblyFactory::Unmount() noexcept - { - auto mount_prev = fMounted; - - if (mount_prev) - { - fMounted = nullptr; - } - - return mount_prev; - } -} // namespace CompilerKit diff --git a/Sources/Detail/ReadMe.md b/Sources/Detail/ReadMe.md deleted file mode 100644 index e9d0a2c..0000000 --- a/Sources/Detail/ReadMe.md +++ /dev/null @@ -1,3 +0,0 @@ -# Compiler utilities. - -A list of headers used to make compiler/assemblers. diff --git a/Sources/Detail/asmutils.hxx b/Sources/Detail/asmutils.hxx deleted file mode 100644 index abb7f82..0000000 --- a/Sources/Detail/asmutils.hxx +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -using namespace CompilerKit; - -/// @brief Get Number from lineBuffer. -/// @param lineBuffer the lineBuffer to fetch from. -/// @param numberKey where to seek that number. -/// @return -static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) -{ - auto pos = lineBuffer.find(numberKey) + numberKey.size(); - - if (lineBuffer.find(",") != std::string::npos) - lineBuffer.erase(lineBuffer.find(","), 1); - - while (lineBuffer[pos] == ' ') - ++pos; - - switch (lineBuffer[pos + 1]) - { - case 'x': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "asm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) - { - kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number:" + lineBuffer, "asm"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + lineBuffer, "asm"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + lineBuffer, "asm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) - { - kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - } -} diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx deleted file mode 100644 index fd2b6d2..0000000 --- a/Sources/Detail/compilerutils.hxx +++ /dev/null @@ -1,14 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include -#include - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" diff --git a/Sources/String.cxx b/Sources/String.cxx deleted file mode 100644 index f69f9b9..0000000 --- a/Sources/String.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/** - * @file String.cxx - * @author Amlal (amlal@mahrouss-logic.com) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) ZKA Technologies - * - */ - -#include - -namespace CompilerKit { -CharType *StringView::Data() { return m_Data; } - -const CharType *StringView::CData() const { return m_Data; } - -SizeType StringView::Length() const { return strlen(m_Data); } - -bool StringView::operator==(const StringView &rhs) const { - if (rhs.Length() != Length()) return false; - - for (SizeType index = 0; index < Length(); ++index) { - if (rhs.m_Data[index] != m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator==(const CharType *rhs) const { - if (string_length(rhs) != Length()) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] != m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator!=(const StringView &rhs) const { - if (rhs.Length() != Length()) return false; - - for (SizeType index = 0; index < rhs.Length(); ++index) { - if (rhs.m_Data[index] == m_Data[index]) return false; - } - - return true; -} - -bool StringView::operator!=(const CharType *rhs) const { - if (string_length(rhs) != Length()) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] == m_Data[index]) return false; - } - - return true; -} - -StringView StringBuilder::Construct(const CharType *data) { - if (!data || *data == 0) return StringView(0); - - StringView view(strlen(data)); - view += data; - - return view; -} - -const char *StringBuilder::FromInt(const char *fmt, int i) { - if (!fmt) return ("-1"); - - auto ret_len = 8 + string_length(fmt); - char *ret = new char[ret_len]; - - if (!ret) return ("-1"); - - memset(ret, 0, ret_len); - - CharType result[8]; - if (!to_str(result, sizeof(int), i)) { - delete[] ret; - return ("-1"); - } - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(result); - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (auto y_idx = idx; y_idx < res_len; ++y_idx) { - ret[result_cnt] = result[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ -} - -const char *StringBuilder::FromBool(const char *fmt, bool i) { - if (!fmt) return ("?"); - - const char *boolean_expr = i ? "true" : "false"; - char *ret = new char[i ? 4 : 5 + string_length(fmt)]; - - if (!ret) return ("?"); - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(boolean_expr); - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (auto y_idx = idx; y_idx < res_len; ++y_idx) { - ret[result_cnt] = boolean_expr[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; -} - -bool StringBuilder::Equals(const char *lhs, const char *rhs) { - if (string_length(rhs) != string_length(lhs)) return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) { - if (rhs[index] != lhs[index]) return false; - } - - return true; -} - -const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { - if (!fmt || !fmtRight) return ("?"); - - char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; - if (!ret) return ("?"); - - for (SizeType idx = 0; idx < string_length(fmt); ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { - ret[result_cnt] = fmtRight[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; -} - -StringView &StringView::operator+=(const CharType *rhs) { - if (strlen(rhs) > this->m_Sz) { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); - this->m_Cur += strlen(rhs); - - return *this; -} - -StringView &StringView::operator+=(const StringView &rhs) { - if (rhs.m_Cur > this->m_Sz) { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); - this->m_Cur += strlen(rhs.CData()); - - return *this; -} -} // namespace CompilerKit diff --git a/Sources/bpp.cxx b/Sources/bpp.cxx deleted file mode 100644 index 9a2943c..0000000 --- a/Sources/bpp.cxx +++ /dev/null @@ -1,899 +0,0 @@ -/* - * ======================================================== - * - * bpp - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include -#include -#include -#include -#include -#include -#include - -#define kMacroPrefix '%' - -/// @author Amlal El Mahrouss (amlel) -/// @file bpp.cxx -/// @brief Preprocessor. - -typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, - std::ofstream &pp_out); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Preprocessor internal types. - -///////////////////////////////////////////////////////////////////////////////////////// - -namespace details { -enum { - kEqual, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, -}; - -struct bpp_macro_condition final { - int32_t fType; - std::string fTypeName; -}; - -struct bpp_macro final { - std::vector fArgs; - std::string fName; - std::string fValue; -}; - -class bpp_pragma final { - public: - explicit bpp_pragma() = default; - ~bpp_pragma() = default; - - MPCC_COPY_DEFAULT(bpp_pragma); - - std::string fMacroName; - bpp_parser_fn_t fParse; -}; -} // namespace details - -static std::vector kFiles; -static std::vector kMacros; -static std::vector kIncludes; - -static std::string kWorkingDir; - -static std::vector kKeywords = { - "include", "if", "pragma", "def", "elif", - "ifdef", "ifndef", "else", "warning", "error"}; - -#define kKeywordCxxCnt kKeywords.size() - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_if_condition -// @brief parse #if condition - -///////////////////////////////////////////////////////////////////////////////////////// - -int32_t bpp_parse_if_condition(details::bpp_macro_condition &cond, - details::bpp_macro ¯o, bool &inactive_code, - bool &defined, std::string ¯o_str) { - if (cond.fType == details::kEqual) { - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fValue) != std::string::npos) { - if (macro.fValue == "0") { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } else if (cond.fType == details::kNotEqual) { - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != std::string::npos) { - if (substr_macro.find(macro.fValue) != std::string::npos) { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - std::string number; - - for (auto ¯o_num : kMacros) { - if (substr_macro.find(macro_num.fName) != std::string::npos) { - for (size_t i = 0; i < macro_num.fName.size(); ++i) { - if (isdigit(macro_num.fValue[i])) { - number += macro_num.fValue[i]; - } else { - number.clear(); - break; - } - } - - break; - } - } - - size_t y = 2; - - /* last try */ - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - size_t rhs = atol(macro.fValue.c_str()); - size_t lhs = atol(number.c_str()); - - if (lhs == 0) { - number.clear(); - ++y; - - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - lhs = atol(number.c_str()); - } - - if (cond.fType == details::kGreaterThan) { - if (lhs < rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kGreaterEqThan) { - if (lhs <= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kLesserEqThan) { - if (lhs >= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == details::kLesserThan) { - if (lhs > rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief stores every included file here. - -///////////////////////////////////////////////////////////////////////////////////////// - -std::vector kAllIncludes; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_file -// @brief parse file to preprocess it. - -///////////////////////////////////////////////////////////////////////////////////////// - -void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { - std::string hdr_line; - std::string line_after_include; - - bool inactive_code = false; - bool defined = false; - - try { - while (std::getline(hdr_file, hdr_line)) { - /// BPP Documentation. - if (hdr_line.find("@bdoc") != std::string::npos) { - hdr_line.erase(hdr_line.find("@bdoc")); - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("endif") != std::string::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = false; - - continue; - } - - continue; - } - - if (!defined && inactive_code) { - continue; - } - - if (defined && inactive_code) { - continue; - } - - for (auto macro : kMacros) { - if (CompilerKit::find_word(hdr_line, macro.fName) && - hdr_line.find("%def") == std::string::npos) { - auto value = macro.fValue; - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - value); - } - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("def ") != std::string::npos) { - auto line_after_define = - hdr_line.substr(hdr_line.find("def ") + strlen("def ")); - - std::string macro_value; - std::string macro_key; - - std::size_t pos = 0UL; - - std::vector args; - bool on_args = false; - - for (auto &ch : line_after_define) { - ++pos; - - if (ch == '(') { - on_args = true; - continue; - } - - if (ch == ')') { - on_args = false; - continue; - } - - if (ch == '\\') continue; - - if (on_args) continue; - - if (ch == ' ') { - for (size_t i = pos; i < line_after_define.size(); i++) { - macro_value += line_after_define[i]; - } - - break; - } - - macro_key += ch; - } - - std::vector dupls; - std::string str; - - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto &subc : line_after_define) { - if (subc == ',' || subc == ')') { - if (str.empty()) continue; - - dupls.push_back(str); - args.push_back(str); - - str.clear(); - - continue; - } - - if (isalnum(subc)) str.push_back(subc); - } - - for (auto &dupl : dupls) { - std::size_t cnt = 0; - - for (auto &arg : args) { - if (dupl == arg) ++cnt; - } - - if (cnt > 1) { - auto it = std::find(args.begin(), args.end(), dupl); - - while (it != args.end()) { - args.erase(it); - it = std::find(args.begin(), args.end(), dupl); - } - } - } - - details::bpp_macro macro; - - macro.fArgs = args; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.emplace_back(macro); - - continue; - } - - if (hdr_line[0] != kMacroPrefix) { - if (inactive_code) { - continue; - } - - for (auto ¯o : kMacros) { - if (hdr_line.find(macro.fName) != std::string::npos) { - std::vector arg_values; - - if (macro.fArgs.size() > 0) { - for (size_t i = 0; i < hdr_line.size(); ++i) { - if (hdr_line[i] == '(') { - std::string tmp_arg; - - for (size_t x = i; x < hdr_line.size(); x++) { - if (hdr_line[x] == ')') break; - - if (hdr_line[x] == ' ') continue; - - if (hdr_line[i] == '\\') continue; - - if (hdr_line[x] == ',') { - arg_values.push_back(tmp_arg); - tmp_arg.clear(); - continue; - } - - tmp_arg += hdr_line[x]; - } - - break; - } - } - - std::string symbol; - - for (char i : macro.fValue) { - if (i == '(') break; - - if (i == '\\') continue; - - symbol += i; - } - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - symbol); - - size_t x_arg_indx = 0; - - for (size_t i = hdr_line.find(macro.fValue); i < hdr_line.size(); - ++i) { - if (hdr_line.find(macro.fArgs[x_arg_indx]) == i) { - hdr_line.replace(i, macro.fArgs[x_arg_indx].size(), - arg_values[x_arg_indx]); - ++x_arg_indx; - } - } - } else { - std::string symbol; - - for (size_t i = 0; i < macro.fValue.size(); i++) { - if (macro.fValue[i] == ' ') continue; - - if (macro.fValue[i] == '\\') continue; - - symbol += macro.fValue[i]; - } - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), - symbol); - } - - break; - } - } - - pp_out << hdr_line << std::endl; - - continue; - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifndef") != std::string::npos) { - auto line_after_ifndef = - hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - std::string macro; - - for (auto &ch : line_after_ifndef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = true; - inactive_code = false; - continue; - } - - if (macro == "1") { - defined = false; - inactive_code = true; - - continue; - } - - bool found = false; - - defined = true; - inactive_code = false; - - for (auto ¯o_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != std::string::npos) { - found = true; - break; - } - } - - if (found) { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != std::string::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = true; - - continue; - } else { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifdef") != std::string::npos) { - auto line_after_ifdef = - hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - std::string macro; - - for (auto &ch : line_after_ifdef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - defined = false; - inactive_code = true; - - for (auto ¯o_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != std::string::npos) { - defined = true; - inactive_code = false; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("pragma") != std::string::npos) { - line_after_include = hdr_line.substr(hdr_line.find("pragma once")); - - // search for this file - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), - line_after_include); - - if (it == kAllIncludes.cend()) { - goto kIncludeFile; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != std::string::npos) { - inactive_code = true; - - std::vector bpp_macro_condition_list = { - { - .fType = details::kEqual, - .fTypeName = "==", - }, - { - .fType = details::kNotEqual, - .fTypeName = "!=", - }, - { - .fType = details::kLesserThan, - .fTypeName = "<", - }, - { - .fType = details::kGreaterThan, - .fTypeName = ">", - }, - { - .fType = details::kLesserEqThan, - .fTypeName = "<=", - }, - { - .fType = details::kGreaterEqThan, - .fTypeName = ">=", - }, - }; - - int32_t good_to_go = 0; - - for (auto ¯o_condition : bpp_macro_condition_list) { - if (hdr_line.find(macro_condition.fTypeName) != std::string::npos) { - for (auto &found_macro : kMacros) { - if (hdr_line.find(found_macro.fName) != std::string::npos) { - good_to_go = - bpp_parse_if_condition(macro_condition, found_macro, - inactive_code, defined, hdr_line); - - break; - } - } - } - } - - if (good_to_go) continue; - - auto line_after_if = - hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); - std::string macro; - - for (auto &ch : line_after_if) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - // last try, is it defined to be one? - for (auto ¯o_ref : kMacros) { - if (macro_ref.fName.find(macro) != std::string::npos && - macro_ref.fValue == "1") { - inactive_code = false; - defined = true; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != std::string::npos) { - auto line_after_warning = - hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - std::string message; - - for (auto &ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - std::cout << "Warning: " << message << std::endl; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != std::string::npos) { - auto line_after_warning = - hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - std::string message; - - for (auto &ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - throw std::runtime_error("Error: " + message); - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("inc ") != std::string::npos) { - line_after_include = - hdr_line.substr(hdr_line.find("inc ") + strlen("inc ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), - line_after_include); - - if (it != kAllIncludes.cend()) { - continue; - } - - std::string path; - - kAllIncludes.push_back(line_after_include); - - bool enable = false; - bool not_local = false; - - for (auto &ch : line_after_include) { - if (ch == ' ') continue; - - if (ch == '<') { - not_local = true; - enable = true; - - continue; - } - - if (ch == '\'') { - enable = true; - continue; - } - - if (enable) { - if (not_local) { - if (ch == '>') break; - } else { - if (ch == '\'') { - break; - } - } - - path += ch; - } - } - - if (not_local) { - bool open = false; - - for (auto &include : kIncludes) { - std::string header_path = include; - header_path.push_back('/'); - header_path += path; - - std::ifstream header(header_path); - - if (!header.is_open()) continue; - - open = true; - - bpp_parse_file(header, pp_out); - - break; - } - - if (!open) { - throw std::runtime_error("bpp: no such include file: " + path); - } - } else { - std::ifstream header(kWorkingDir + path); - - if (!header.is_open()) - throw std::runtime_error("bpp: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } else { - std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) - << "\n"; - continue; - } - } - } catch (std::out_of_range &oor) { - return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief main entrypoint of app. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSPreprocessor) { - try { - bool skip = false; - bool double_skip = false; - - details::bpp_macro macro_1; - macro_1.fName = "__true"; - macro_1.fValue = "1"; - - kMacros.push_back(macro_1); - - details::bpp_macro macro_0; - macro_0.fName = "__false"; - macro_0.fValue = "0"; - - kMacros.push_back(macro_0); - - details::bpp_macro macro_hcore; - macro_hcore.fName = "__MAHROUSS__"; - macro_hcore.fValue = "1"; - - kMacros.push_back(macro_hcore); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (double_skip) { - ++index; - double_skip = false; - continue; - } - - if (argv[index][0] == '/') { - if (strcmp(argv[index], "/version") == 0) { - printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); - return 0; - } - - if (strcmp(argv[index], "/help") == 0) { - printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) ZKA Technologies"); - printf("%s\n", "/working-dir : set directory to working path."); - printf("%s\n", "/include-dir : add directory to include path."); - printf("%s\n", "/def : def macro."); - printf("%s\n", "/version: print the version."); - printf("%s\n", "/help: show help."); - - return 0; - } - - if (strcmp(argv[index], "/include-dir") == 0) { - std::string inc = argv[index + 1]; - - skip = true; - - kIncludes.push_back(inc); - } - - if (strcmp(argv[index], "/working-dir") == 0) { - std::string inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } - - if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) { - std::string macro_key = argv[index + 1]; - - std::string macro_value; - bool is_string = false; - - for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); - ++argv_find_len) { - if (!isdigit(argv[index][argv_find_len])) { - is_string = true; - macro_value += "\""; - - break; - } - } - - macro_value += argv[index + 2]; - - if (is_string) macro_value += "\""; - - details::bpp_macro macro; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.push_back(macro); - - double_skip = true; - } - - continue; - } - - kFiles.emplace_back(argv[index]); - } - - if (kFiles.empty()) return MPCC_EXEC_ERROR; - - for (auto &file : kFiles) { - if (!std::filesystem::exists(file)) continue; - - std::ifstream file_descriptor(file); - std::ofstream file_descriptor_pp(file + ".pp"); - - bpp_parse_file(file_descriptor, file_descriptor_pp); - } - - return 0; - } catch (const std::runtime_error &e) { - std::cout << e.what() << '\n'; - } - - return 1; -} - -// Last rev 8-1-24 diff --git a/Sources/coff2ae.cxx b/Sources/coff2ae.cxx deleted file mode 100644 index c9ea8c0..0000000 --- a/Sources/coff2ae.cxx +++ /dev/null @@ -1,23 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file coff2ae.cxx -/// @brief COFF To AE, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/compile_flags.txt b/Sources/compile_flags.txt deleted file mode 100644 index 6ec6b8a..0000000 --- a/Sources/compile_flags.txt +++ /dev/null @@ -1,5 +0,0 @@ --std=c++20 --I../ --I../Headers --I./ --I./Detail/ diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx deleted file mode 100644 index ae4a300..0000000 --- a/Sources/cplusplus.cxx +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * ======================================================== - * - * cplusplus - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// bugs: 0 - -#define __PK_USE_STRUCT_INSTEAD__ 1 - -#define kPrintF printf - -#define kOk (0) - -#define kSplashCxx() \ - kPrintF(kWhite "%s\n", "ZKA C++ Compiler Driver, (c) 2024 ZKA Electronics, all rights reserved.") - -// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* ZKA C++ driver */ -/* This is part of NDK. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cxx -/// @brief Optimized C++ Compiler. -/// @todo Throw error for scoped inside scoped variables when they get referenced outside. -/// @todo Add class/struct/enum support. - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNALS OF THE C COMPILER - -///////////////////////////////////// - -/// @internal -namespace detail -{ - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Offset based struct/class - struct CompilerStructMap final - { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; - -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cplusplus ] " << kWhite - << ((file == "cplusplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::vector kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for the ZKA C++ driver */ -class CompilerBackendCPlusPlus final : public CompilerKit::CompilerBackend -{ -public: - explicit CompilerBackendCPlusPlus() = default; - ~CompilerBackendCPlusPlus() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); - - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override; -}; - -/// @internal compiler variables - -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; - -static std::vector kRegisterMap; - -static std::vector cRegisters = { - "rbx", - "rsi", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "xmm12", - "xmm13", - "xmm14", - "xmm15", -}; - -/// @brief The PEF calling convention (caller must save rax, rbp) -/// @note callee must return via **rax**. -static std::vector cRegistersCall = { - "rcx", - "rdx", - "r8", - "r9", - "xmm8", - "xmm9", - "xmm10", - "xmm11", -}; - -static size_t kLevelFunction = 0UL; - -/// detail namespaces - -const char* CompilerBackendCPlusPlus::Language() -{ - return "ZKA C++"; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @name Compile -/// @brief Generate MASM assembly from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCPlusPlus::Compile(const std::string& text, - const char* file) -{ - if (text.empty()) - return false; - - // if (expr) - // int name = expr; - // expr; - - std::size_t index = 0UL; - std::vector> keywords_list; - - bool found = false; - static bool commentBlock = false; - - for (auto& keyword : kKeywords) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - switch (keyword.keyword_kind) - { - case CompilerKit::eKeywordKindCommentMultiLineStart: { - commentBlock = true; - return true; - } - case CompilerKit::eKeywordKindCommentMultiLineEnd: { - commentBlock = false; - break; - } - case CompilerKit::eKeywordKindCommentInline: { - break; - } - default: - break; - } - - if (text[text.find(keyword.keyword_name) - 1] == '+' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) - 1] == '-' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) + 1] == '=' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - - found = true; - } - } - - if (!found && !commentBlock) - { - for (size_t i = 0; i < text.size(); i++) - { - if (isalnum(text[i])) - { - detail::print_error("syntax error: " + text, file); - return false; - } - } - } - - for (auto& keyword : keywords_list) - { - auto syntax_tree = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - switch (keyword.first.keyword_kind) - { - case CompilerKit::KeywordKind::eKeywordKindIf: { - auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); - - if (expr.find(">=") != std::string::npos) - { - auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); - auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - - size_t i = right.size() - 1; - - try - { - while (!std::isalnum(right[i])) - { - right.erase(i, 1); - --i; - } - - right.erase(0, i); - } - catch (...) - { - right.erase(0, i); - } - - i = left.size() - 1; - try - { - - while (!std::isalnum(left[i])) - { - left.erase(i, 1); - --i; - } - - left.erase(0, i); - } - catch (...) - { - left.erase(0, i); - } - - if (!isdigit(left[0]) || - !isdigit(right[0])) - { - auto indexRight = 0UL; - - auto& valueOfVar = !isdigit(left[0]) ? left : right; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - - syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + "," + cRegisters[indexRight + 1] + "\n"; - - goto done_iterarting_on_if; - } - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + ", " + cRegisters[indexRight + 1] + "\n"; - - break; - } - } - - done_iterarting_on_if: - - std::string fnName = text; - fnName.erase(fnName.find(keyword.first.keyword_name)); - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue += "jge offset [rsp + 4]\n"; - } - - break; - } - case CompilerKit::KeywordKind::eKeywordKindFunctionStart: { - if (text.ends_with(";")) - { - break; - } - - for (auto& ch : text) - { - if (isdigit(ch)) - { - goto dont_accept; - } - } - - goto accept; - - dont_accept: - return true; - - accept: - std::string fnName = text; - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; - - ++kLevelFunction; - } - case CompilerKit::KeywordKind::eKeywordKindFunctionEnd: { - if (text.ends_with(";")) - break; - - --kLevelFunction; - - if (kRegisterMap.size() > cRegisters.size()) - { - --kLevelFunction; - } - - if (kLevelFunction < 1) - kRegisterMap.clear(); - break; - } - case CompilerKit::KeywordKind::eKeywordKindEndInstr: - case CompilerKit::KeywordKind::eKeywordKindVariableInc: - case CompilerKit::KeywordKind::eKeywordKindVariableDec: - case CompilerKit::KeywordKind::eKeywordKindVariableAssign: { - std::string valueOfVar = ""; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - valueOfVar = text.substr(text.find("+=") + 2); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - valueOfVar = text.substr(text.find("-=") + 2); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - { - valueOfVar = text.substr(text.find("=") + 1); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - break; - } - - while (valueOfVar.find(";") != std::string::npos && - keyword.first.keyword_kind != CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - valueOfVar.erase(valueOfVar.find(";")); - } - - std::string varName = text; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - varName.erase(varName.find("+=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - varName.erase(varName.find("-=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - { - varName.erase(varName.find("=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - varName.erase(varName.find(";")); - } - - static bool typeFound = false; - - for (auto& keyword : kKeywords) - { - if (keyword.keyword_kind == CompilerKit::eKeywordKindType) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - if (text[text.find(keyword.keyword_name)] == ' ') - { - typeFound = false; - continue; - } - - typeFound = true; - } - } - } - - std::string instr = "mov "; - - if (typeFound) - { - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - detail::print_error("Can't increment variable when it's being created.", file); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - detail::print_error("Can't decrement variable when it's being created.", file); - } - - if (kRegisterMap.size() > cRegisters.size()) - { - ++kLevelFunction; - } - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - goto done; - } - - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - break; - } - - if (((int)indexRight - 1) < 0) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - } - - done: - kRegisterMap.push_back(varName); - } - else - { - if (kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindTypePtr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - instr = "add "; - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - instr = "sub "; - } - - std::string varErrCpy = varName; - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - while (valueOfVar.find(" ") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find(" "), 1); - } - - while (valueOfVar.find("\t") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find("\t"), 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != varName) - continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != varName) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - continue; - } - - syntax_tree.fUserValue = instr + cRegisters[indexRight - 1] + ", " + valueOfVar + "\n"; - break; - } - - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + varErrCpy, file); - } - } - - break; - } - case CompilerKit::KeywordKind::eKeywordKindReturn: { - auto pos = text.find("return") + strlen("return") + 1; - std::string subText = text.substr(pos); - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (subText[0] != '\"' && - subText[0] != '\'') - { - if (!isdigit(subText[0])) - { - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != subText) - continue; - - syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg] + "\r\nret\n"; - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + subText, file); - } - } - else - { - syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; - } - } - else - { - syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; - syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; - } - - break; - } - default: - break; - } - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } - -_MpccOkay: - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCPlusPlusInterface() = default; - ~AssemblyCPlusPlusInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); - - [[maybe_unused]] - static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchAMD64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCPlusPlusInterface::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - - const char* cExts[] = kAsmFileExts; - - std::string dest = src_file; - dest += cExts[4]; - - if (dest.empty()) - { - dest = "CXX-NDK-"; - - std::random_device rd; - auto seed_data = std::array{}; - - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator(generator); - - auto id = gen(); - dest += uuids::to_string(id); - } - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: AMD64 assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; - (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" - << "\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string source; - - while (std::getline(src_fp, source)) - { - // Compile into an object file. - kCompilerBackend->Compile(source.c_str(), src.c_str()); - } - - for (auto& ast : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << ast.fUserValue; - } - - if (kAcceptableErrors > 0) - return -1; - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static void cxx_print_help() -{ - kSplashCxx(); - kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { \ - ".cpp", ".cxx", ".cc", ".c++", ".cp" \ - } - -NDK_MODULE(CompilerCPlusPlus) -{ - bool skip = false; - - kKeywords.push_back({.keyword_name = "if", .keyword_kind = CompilerKit::eKeywordKindIf}); - kKeywords.push_back({.keyword_name = "else", .keyword_kind = CompilerKit::eKeywordKindElse}); - kKeywords.push_back({.keyword_name = "else if", .keyword_kind = CompilerKit::eKeywordKindElseIf}); - - kKeywords.push_back({.keyword_name = "class", .keyword_kind = CompilerKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "struct", .keyword_kind = CompilerKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = CompilerKit::eKeywordKindNamespace}); - kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = CompilerKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "using", .keyword_kind = CompilerKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = CompilerKit::eKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = CompilerKit::eKeywordKindBodyEnd}); - kKeywords.push_back({.keyword_name = "auto", .keyword_kind = CompilerKit::eKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "bool", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "short", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "char", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "long", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "float", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "double", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "void", .keyword_kind = CompilerKit::eKeywordKindType}); - - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = CompilerKit::eKeywordKindVariablePtr}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - - kKeywords.push_back({.keyword_name = "(", .keyword_kind = CompilerKit::eKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = CompilerKit::eKeywordKindFunctionEnd}); - kKeywords.push_back({.keyword_name = "=", .keyword_kind = CompilerKit::eKeywordKindVariableAssign}); - kKeywords.push_back({.keyword_name = "+=", .keyword_kind = CompilerKit::eKeywordKindVariableInc}); - kKeywords.push_back({.keyword_name = "-=", .keyword_kind = CompilerKit::eKeywordKindVariableDec}); - kKeywords.push_back({.keyword_name = "const", .keyword_kind = CompilerKit::eKeywordKindConstant}); - kKeywords.push_back({.keyword_name = "*", .keyword_kind = CompilerKit::eKeywordKindPtr}); - kKeywords.push_back({.keyword_name = "->", .keyword_kind = CompilerKit::eKeywordKindPtrAccess}); - kKeywords.push_back({.keyword_name = ".", .keyword_kind = CompilerKit::eKeywordKindAccess}); - kKeywords.push_back({.keyword_name = ",", .keyword_kind = CompilerKit::eKeywordKindArgSeparator}); - kKeywords.push_back({.keyword_name = ";", .keyword_kind = CompilerKit::eKeywordKindEndInstr}); - kKeywords.push_back({.keyword_name = ":", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "public:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "private:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "final", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "return", .keyword_kind = CompilerKit::eKeywordKindReturn}); - kKeywords.push_back({.keyword_name = "/*", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "*/", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "//", .keyword_kind = CompilerKit::eKeywordKindCommentInline}); - kKeywords.push_back({.keyword_name = "==", .keyword_kind = CompilerKit::eKeywordKindEq}); - kKeywords.push_back({.keyword_name = "!=", .keyword_kind = CompilerKit::eKeywordKindNotEq}); - kKeywords.push_back({.keyword_name = ">=", .keyword_kind = CompilerKit::eKeywordKindGreaterEq}); - kKeywords.push_back({.keyword_name = "<=", .keyword_kind = CompilerKit::eKeywordKindLessEq}); - - kFactory.Mount(new AssemblyCPlusPlusInterface()); - kCompilerBackend = new CompilerBackendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) - { - if (argv[index][0] == '/') - { - if (skip) - { - skip = false; - continue; - } - - if (strcmp(argv[index], "/v") == 0 || - strcmp(argv[index], "/version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "/verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) - { - cxx_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "/dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "/max-errors") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - detail::print_error(err, "cplusplus"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - bool found = false; - - for (std::string ext : exts) - { - if (argv_i.find(ext) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - if (kState.fVerbose) - { - detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 -// diff --git a/Sources/elf2ae.cxx b/Sources/elf2ae.cxx deleted file mode 100644 index 451c706..0000000 --- a/Sources/elf2ae.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief COFF 2 AE entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/Sources/i64asm.cxx b/Sources/i64asm.cxx deleted file mode 100644 index ed77988..0000000 --- a/Sources/i64asm.cxx +++ /dev/null @@ -1,1484 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file i64asm.cxx -/// @author Amlal EL Mahrouss -/// @brief AMD64 Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -/// bugs: 0 - -/// feature request: 1 -/// Encode registers in mov, add, xor... - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_AMD64__ 1 - -#define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -static char kOutputArch = CompilerKit::kPefArchAMD64; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -constexpr auto cAMD64IPAlignment = 0x4U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -/// @brief keep it simple by default. -static std::int32_t kRegisterBitWidth = 16U; - -static bool kVerbose = false; - -static std::vector kAppBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kDefinedSymbols; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string& line); - -namespace detail -{ - void print_error(std::string reason, const std::string& file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - kStdErr << kRed << "[ i64asm ] " << kWhite - << ((file == "i64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - void print_warning(std::string reason, const std::string& file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (!file.empty()) - { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank - << std::endl; - } -} // namespace detail - -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssemblerAMD64) -{ - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) - { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) - { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) - { - if (argv[i][0] == '/') - { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) - { - kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " - "(c) ZKA Technologies.\n"; - return 0; - } - else if (strcmp(argv[i], "/h") == 0) - { - kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version: Print program version.\n"; - kStdOut << "/verbose: Print verbose output.\n"; - kStdOut << "/binary: Output as flat binary.\n"; - - return 0; - } - else if (strcmp(argv[i], "/binary") == 0) - { - kOutputAsBinary = true; - continue; - } - else if (strcmp(argv[i], "/verbose") == 0) - { - kVerbose = true; - continue; - } - - kStdOut << "i64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) - { - kStdOut << "i64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) - { - if (object_output.find(ext) != std::string::npos) - { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) - { - if (kVerbose) - { - kStdOut << "i64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderAMD64 asm64; - - while (std::getline(file_ptr, line)) - { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) - { - detail::print_error(ln, argv[i]); - continue; - } - - try - { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } - catch (const std::exception& e) - { - if (kVerbose) - { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "i64asm"); - } - - try - { - std::filesystem::remove(object_output); - } - catch (...) - { - } - - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "i64asm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) - { - kStdErr << "i64asm: At least one record is needed to write an object " - "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) - { - if (kVerbose) - kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) - { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) - kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "i64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kAppBytes) - { - if (byte == 0) - continue; - - if (byte == 0xFF) - { - byte = 0; - } - - file_ptr_out << reinterpret_cast(&byte)[0]; - } - - if (kVerbose) - kStdOut << "i64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) - kStdOut << "i64asm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) - kStdOut << "i64asm: Exit failed.\n"; - - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string& line) -{ - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "import")) - { - if (kOutputAsBinary) - { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) - { - detail::print_error("Invalid import", "power-as"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) - { - if (j == ' ' || j == ',') - j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by i64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (CompilerKit::find_word(line, "export")) - { - if (kOutputAsBinary) - { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export") + 1); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) - { - detail::print_error("Symbol already defined.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm -{ - // \brief authorize a brief set of characters. - static inline bool is_not_alnum_space(char c) - { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); - } - - bool is_valid(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); - } -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - CompilerKit::find_word(line, kAssemblerPragmaSymStr) || - CompilerKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) - { - if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) - { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) - { - err_str = "Line contains non alphanumeric characters.\nHere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) - { - if (line.find(',') + 1 == line.size()) - { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } - else - { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) - { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) - { - if (ch != ' ' && ch != '\t') - { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) - { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto& opcodeAMD64 : kOpcodesAMD64) - { - if (CompilerKit::find_word(line, opcodeAMD64.fName)) - { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, - const std::string& file) -{ - if (CompilerKit::find_word(line, "export ")) - return true; - - struct RegMapAMD64 - { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector REGISTER_LIST{ - {.fName = "ax", .fModRM = 0x0}, - {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, - {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, - {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, - {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, - {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, - {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, - {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto& opcodeAMD64 : kOpcodesAMD64) - { - // strict check here - if (CompilerKit::find_word(line, opcodeAMD64.fName) && - detail::algorithm::is_valid(line)) - { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (name.find("mov") != std::string::npos) - { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) - { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector currentRegList; - - for (auto& reg : REGISTER_LIST) - { - std::vector regExt = {'e', 'r'}; - - for (auto& ext : regExt) - { - std::string registerName; - - if (bits > 16) - registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) - { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) - { - if (registerName[0] == 'r') - { - detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) - onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) - { - /// very tricky to understand. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') - { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } - else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) - { - if (!hasRBasedRegs && bits >= 32) - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x89); - } - else if (bits == 16) - { - if (hasRBasedRegs) - { - detail::print_error( - "Invalid combination of operands and registers.", "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) - { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - else - { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') - { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } - else if (name == "int" || name == "into" || name == "intd") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } - else if (name == "jmp" || name == "call") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) - { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } - else - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) - { - if (foundInstruction) - { - detail::print_error("Syntax error: " + line, "i64asm"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) - { - kRegisterBitWidth = 64U; - } - else if (line.find("bits 32") != std::string::npos) - { - kRegisterBitWidth = 32U; - } - else if (line.find("bits 16") != std::string::npos) - { - kRegisterBitWidth = 16U; - } - else if (line.find("org") != std::string::npos) - { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) - { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) - { - if (errno != 0) - { - continue; - } - else - { - if (kVerbose) - { - kStdOut << "i64asm: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) - { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) - { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) - { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += cAMD64IPAlignment; - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/link.cxx b/Sources/link.cxx deleted file mode 100644 index d59c982..0000000 --- a/Sources/link.cxx +++ /dev/null @@ -1,741 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// @file link.cxx -/// @author Amlal EL Mahrouss (amlel) -/// @brief ZKA Technologies Linker. - -/// Last Rev: Sat Feb 24 CET 2024 - -/// @note Do not look up for anything with .code64/.data64/.zero64! -/// It will be loaded when program will start up! - -#include - -//! Assembler Kit -#include - -//! Preferred Executable Format -#include -#include -#include -#include -#include - -//! Dist version -#include - -//! Advanced Executable Object Format -#include - -//! C++ I/O headers. -#include -#include - -#define kLinkerVersion "ZKA Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" - -#define StringCompare(DST, SRC) strcmp(DST, SRC) - -#define kPefNoCpu 0U -#define kPefNoSubCpu 0U - -#define kWhite "\e[0;97m" -#define kStdOut (std::cout << kWhite) - -#define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId 0x5046FF -#define kLinkerAbiContainer "Container:Abi:" - -enum -{ - eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ - eABINewOSKrnl = 0x5046, /* PF (NewOSKrnl) */ - eABIMTL = 0x4650, /* FP (MTL firmware) */ - eABIInvalid = 1, -}; - -static std::string kOutput = ""; -static Int32 kAbi = eABINewOSKrnl; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArchInvalid; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; -static Bool kVerbose = false; - -/* link is to be found, mld is to be found at runtime. */ -static const char* kLdDefineSymbol = ":UndefinedSymbol:"; -static const char* kLdDynamicSym = ":RuntimeSymbol:"; - -/* object code and list. */ -static std::vector kObjectList; -static std::vector kObjectBytes; - -#define kPrintF printf -#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) - -NDK_MODULE(NewOSLinker) -{ - bool is_executable = true; - - /** - * @brief parse flags and such. - * - */ - for (size_t i = 1; i < argc; ++i) - { - if (StringCompare(argv[i], "/help") == 0) - { - kLinkerSplash(); - kStdOut << "/version: Show linker version.\n"; - kStdOut << "/help: Show linker help.\n"; - kStdOut << "/verbose: Enable linker trace.\n"; - kStdOut << "/shared: Output as a shared PEF.\n"; - kStdOut << "/fat-bin: Output as a FAT PEF.\n"; - kStdOut << "/32x0: Output as a 32x0 PEF.\n"; - kStdOut << "/64x0: Output as a 64x0 PEF.\n"; - kStdOut << "/amd64: Output as a AMD64 PEF.\n"; - kStdOut << "/rv64: Output as a RISC-V PEF.\n"; - kStdOut << "/power64: Output as a POWER PEF.\n"; - kStdOut << "/arm64: Output as a ARM64 PEF.\n"; - kStdOut << "/output-file: Select the output file name.\n"; - - return 0; - } - else if (StringCompare(argv[i], "/version") == 0) - { - kLinkerSplash(); - return 0; - } - else if (StringCompare(argv[i], "/fat-bin") == 0) - { - kFatBinaryEnable = true; - - continue; - } - else if (StringCompare(argv[i], "/64x0") == 0) - { - kArch = CompilerKit::kPefArch64000; - - continue; - } - else if (StringCompare(argv[i], "/amd64") == 0) - { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } - else if (StringCompare(argv[i], "/32x0") == 0) - { - kArch = CompilerKit::kPefArch32000; - - continue; - } - else if (StringCompare(argv[i], "/power64") == 0) - { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } - else if (StringCompare(argv[i], "/arm64") == 0) - { - kArch = CompilerKit::kPefArchARM64; - - continue; - } - else if (StringCompare(argv[i], "/verbose") == 0) - { - kVerbose = true; - - continue; - } - else if (StringCompare(argv[i], "/shared") == 0) - { - if (kOutput.empty()) - { - continue; - } - - if (kOutput.find(kPefExt) != std::string::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } - else if (StringCompare(argv[i], "/output-file") == 0) - { - kOutput = argv[i + 1]; - ++i; - - continue; - } - else - { - if (argv[i][0] == '/') - { - kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return MPCC_EXEC_ERROR; - } - - kObjectList.emplace_back(argv[i]); - - continue; - } - } - - if (kOutput.empty()) - { - kStdOut << "link: no output filename set." << std::endl; - return MPCC_EXEC_ERROR; - } - - // sanity check. - if (kObjectList.empty()) - { - kStdOut << "link: no input files." << std::endl; - return MPCC_EXEC_ERROR; - } - else - { - namespace fs = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) - { - if (!fs::exists(obj)) - { - // if filesystem doesn't find file - // -> throw error. - kStdOut << "link: no such file: " << obj << std::endl; - return MPCC_EXEC_ERROR; - } - } - } - - // PEF expects a valid architecture when outputing a binary. - if (kArch == 0) - { - kStdOut << "link: no target architecture set, can't continue." << std::endl; - return MPCC_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = CompilerKit::kPefKindExec; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // ZKA Technologies Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - - std::ofstream outputFc(kOutput, std::ofstream::binary); - - if (outputFc.bad()) - { - if (kVerbose) - { - kStdOut << "link: error: " << strerror(errno) << "\n"; - } - - return MPCC_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector commandHdrsList; - CompilerKit::Utils::AEReadableProtocol readProto{}; - - for (const auto& i : kObjectList) - { - if (!std::filesystem::exists(i)) - continue; - - CompilerKit::AEHeader hdr{}; - - readProto.FP = std::ifstream(i, std::ifstream::binary); - readProto.FP >> hdr; - - auto ae_header = hdr; - - if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && - ae_header.fSize == sizeof(CompilerKit::AEHeader)) - { - if (ae_header.fArch != kArch) - { - if (kVerbose) - kStdOut << "link: info: is this a FAT binary? : "; - - if (!kFatBinaryEnable) - { - if (kVerbose) - kStdOut << "No.\n"; - - kStdOut << "link: error: object " << i - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - std::remove(kOutput.c_str()); - return MPCC_FAT_ERROR; - } - else - { - if (kVerbose) - { - kStdOut << "Yes.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= ae_header.fArch; - std::size_t cnt = ae_header.fCount; - - if (kVerbose) - kStdOut << "link: object header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - char_type* raw_ae_records = - new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; - memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto* ae_records = readProto.Read(raw_ae_records, cnt); - for (size_t ae_record_index = 0; ae_record_index < cnt; - ++ae_record_index) - { - CompilerKit::PEFCommandHeader command_header{0}; - size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; - - memcpy(command_header.Name, ae_records[ae_record_index].fName, - kPefNameLen); - - // check this header if it's any valid. - if (std::string(command_header.Name).find(".code64") == - std::string::npos && - std::string(command_header.Name).find(".data64") == - std::string::npos && - std::string(command_header.Name).find(".zero64") == - std::string::npos) - { - if (std::string(command_header.Name).find(kPefStart) == - std::string::npos && - *command_header.Name == 0) - { - if (std::string(command_header.Name).find(kLdDefineSymbol) != - std::string::npos) - { - goto ld_mark_header; - } - else - { - continue; - } - } - } - - if (std::string(command_header.Name).find(kPefStart) != - std::string::npos && - std::string(command_header.Name).find(".code64") != - std::string::npos) - { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offsetOfData; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; - command_header.Cpu = ae_header.fArch; - command_header.SubCpu = ae_header.fSubArch; - - if (kVerbose) - { - kStdOut << "link: object record: " - << ae_records[ae_record_index].fName << " was marked.\n"; - - kStdOut << "link: object record offset: " << command_header.Offset << "\n"; - } - - commandHdrsList.emplace_back(command_header); - } - - delete[] raw_ae_records; - - std::vector bytes; - bytes.resize(ae_header.fCodeSize); - - readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); - readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); - - for (auto& byte : bytes) - { - kObjectBytes.push_back(byte); - } - - readProto.FP.close(); - - continue; - } - - kStdOut << "link: not an object: " << i << std::endl; - std::remove(kOutput.c_str()); - - // don't continue, it is a fatal error. - return MPCC_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - outputFc << pef_container; - - if (kVerbose) - { - kStdOut << "link: wrote container header.\n"; - } - - outputFc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector not_found; - std::vector symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - for (auto& commandHdr : commandHdrsList) - { - // check if this symbol needs to be resolved. - if (std::string(commandHdr.Name).find(kLdDefineSymbol) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) - { - if (kVerbose) - kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; - - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it == not_found.end()) - { - not_found.emplace_back(commandHdr.Name); - } - } - - symbols.emplace_back(commandHdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); - ++not_found_idx) - { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdrsList[not_found_idx].Name)); - it != not_found.end()) - { - std::string symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) - continue; - - // erase the lookup prefix. - symbol_imp.erase( - 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != std::string::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto& commandHdr : commandHdrsList) - { - if (std::string(commandHdr.Name).find(symbol_imp) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDefineSymbol) == - std::string::npos) - { - std::string undefined_symbol = commandHdr.Name; - auto result_of_sym = - undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) - { - if (result_of_sym[i] != symbol_imp[i]) - goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) - kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) - { - if (kVerbose) - kStdOut - << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " - "against your compiler's runtime library.\n"; - - kStdOut << "link: undefined entrypoint " << kPefStart - << " for executable: " << kOutput << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader dateHeader{}; - - time_t timestamp = time(nullptr); - - std::string timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strcpy(dateHeader.Name, timeStampStr.c_str()); - - dateHeader.Flags = 0; - dateHeader.Kind = CompilerKit::kPefZero; - dateHeader.Offset = outputFc.tellp(); - dateHeader.Size = timeStampStr.size(); - - commandHdrsList.push_back(dateHeader); - - CompilerKit::PEFCommandHeader abiHeader{}; - - std::string abi = kLinkerAbiContainer; - - switch (kArch) - { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "MHRA"; - break; - } - default: { - abi += " IDK"; - break; - } - } - - memcpy(abiHeader.Name, abi.c_str(), abi.size()); - - abiHeader.Size = abi.size(); - abiHeader.Offset = outputFc.tellp(); - abiHeader.Flags = 0; - abiHeader.Kind = CompilerKit::kPefLinkerID; - - commandHdrsList.push_back(abiHeader); - - CompilerKit::PEFCommandHeader uuidHeader{}; - - std::random_device rd; - - auto seedData = std::array{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), - uuidStr.size()); - - uuidHeader.Size = 16; - uuidHeader.Offset = outputFc.tellp(); - uuidHeader.Flags = 0; - uuidHeader.Kind = CompilerKit::kPefZero; - - commandHdrsList.push_back(uuidHeader); - - // prepare a symbol vector. - std::vector undefSymbols; - std::vector duplSymbols; - std::vector resolveSymbols; - - constexpr Int32 cPaddingOffset = 16; - - size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; - commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) - { - if (std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) - { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - std::string symbolName = commandHdrsList[commandHeaderIndex].Name; - - if (!symbolName.empty()) - { - undefSymbols.emplace_back(symbolName); - } - - commandHdrsList[commandHeaderIndex].Offset += previousOffset; - previousOffset += commandHdrsList[commandHeaderIndex].Size; - - std::string name = commandHdrsList[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kPefStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != std::string::npos && - name.find(".code64") != std::string::npos) - { - pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; - auto tellCurPos = outputFc.tellp(); - - outputFc.seekp(0); - outputFc << pef_container; - - outputFc.seekp(tellCurPos); - } - - if (kVerbose) - { - kStdOut << "link: command header name: " << name << "\n"; - kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; - } - - outputFc << commandHdrsList[commandHeaderIndex]; - - for (size_t subCommandHeaderIndex = 0UL; - subCommandHeaderIndex < commandHdrsList.size(); - ++subCommandHeaderIndex) - { - if (subCommandHeaderIndex == commandHeaderIndex) - continue; - - if (std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) - { - if (kVerbose) - { - kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; - - if (commandHdr.Name == - std::string(commandHdrsList[commandHeaderIndex].Name)) - { - if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), - commandHdr.Name) == duplSymbols.cend()) - { - duplSymbols.emplace_back(commandHdr.Name); - } - - if (kVerbose) - kStdOut << "link: found duplicate symbol: " << commandHdr.Name - << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!duplSymbols.empty()) - { - for (auto& symbol : duplSymbols) - { - kStdOut << "link: multiple symbols of " << symbol << ".\n"; - } - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto byte : kObjectBytes) - { - outputFc << byte; - } - - if (kVerbose) - kStdOut << "link: wrote contents of: " << kOutput << "\n"; - - // step 3: check if we have those symbols - - std::vector unrefSyms; - - for (auto& commandHdr : commandHdrsList) - { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it != not_found.end()) - { - unrefSyms.emplace_back(commandHdr.Name); - } - } - - if (!unrefSyms.empty()) - { - for (auto& unreferenced_symbol : unrefSyms) - { - kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; - } - } - - if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || - !unrefSyms.empty()) - { - if (kVerbose) - kStdOut << "link: file: " << kOutput - << ", is corrupt, removing file...\n"; - - std::remove(kOutput.c_str()); - return MPCC_EXEC_ERROR; - } - - return 0; -} - -// Last rev 13-1-24 diff --git a/Sources/power-as.cxx b/Sources/power-as.cxx deleted file mode 100644 index 8a6b7ef..0000000 --- a/Sources/power-as.cxx +++ /dev/null @@ -1,976 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file power-as.cxx -/// @author Amlal EL Mahrouss -/// @brief POWER Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_PPC__ 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -constexpr auto cPowerIPAlignment = 0x4U; - -static CharType kOutputArch = CompilerKit::kPefArchPowerPC; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static bool kVerbose = false; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ power-as ] " << kWhite - << ((file == "power-as") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ power-as ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ power-as ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail - -/// Do not move it on top! it uses the assembler detail namespace! -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssemblerPowerPC) { - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '/') { - if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { - kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: " << kDistVersion << "\npower-as: " - "Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version,/v: print program version.\n"; - kStdOut << "/verbose: print verbose output.\n"; - kStdOut << "/binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "/binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "/verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "power-as: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "power-as: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "power-as: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "power-as"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "power-as: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "power-as: At least one record is needed to write an object " - "file.\npower-as: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) - kStdOut << "power-as: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) - kStdOut << "power-as: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAEInvalidOpcode; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "power-as: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "power-as: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "power-as: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "power-as: Exit failed.\n"; - - return MPCC_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the li - // that we need this symbol. - if (CompilerKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "power-as"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "power-as"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by power-as to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "power-as"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export")); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "li"}; - - // these don't. - std::vector filter_inst = {"blr", "bl", "sc"}; - - for (auto &opcodePPC : kOpcodesPowerPC) { - if (CompilerKit::find_word(line, opcodePPC.name)) { - for (auto &op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = - std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcodePPC.name)) { - if (!isspace( - line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { - err_str += "\nMissing space between "; - err_str += opcodePPC.name; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "power-as"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "power-as: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "power-as"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "power-as: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "power-as"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "power-as: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "power-as: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, - const std::string &file) { - if (CompilerKit::find_word(line, "export")) return true; - if (!detail::algorithm::is_valid(line)) return true; - - for (auto &opcodePPC : kOpcodesPowerPC) { - // strict check here - if (CompilerKit::find_word(line, opcodePPC.name)) { - std::string name(opcodePPC.name); - std::string jump_label, cpy_jump_label; - std::vector found_registers_index; - - // check funct7 type. - switch (opcodePPC.ops->type) { - default: { - NumberCast32 num(opcodePPC.opcode); - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - break; - } - case BADDR: - case PCREL: { - auto num = GetNumber32(line, name); - - kBytes.emplace_back(num.number[0]); - kBytes.emplace_back(num.number[1]); - kBytes.emplace_back(num.number[2]); - kBytes.emplace_back(0x48); - - break; - } - /// General purpose, float, vector operations. Everything that involve - /// registers. - case G0REG: - case FREG: - case VREG: - case GREG: { - // \brief how many registers we found. - std::size_t found_some_count = 0UL; - std::size_t register_count = 0UL; - std::string opcodeName = opcodePPC.name; - std::size_t register_sum = 0; - - NumberCast64 num(opcodePPC.opcode); - - for (size_t line_index = 0UL; line_index < line.size(); - line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && - isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) - reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (isdigit(line[line_index + 3]) && - isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - detail::print_error( - "invalid register index, r" + reg_str + - "\nnote: The POWER accepts registers from r0 to r32.", - file); - throw std::runtime_error("invalid_register_index"); - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - detail::print_error("invalid register index, r" + reg_str, - file); - throw std::runtime_error("invalid_register_index"); - } - - if (opcodeName == "li") { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - auto num = GetNumber32(line, reg_str); - - kBytes.push_back(num.number[0]); - kBytes.push_back(num.number[1]); - kBytes.push_back(numIndex); - kBytes.push_back(0x38); - - // check if bigger than two. - for (size_t i = 2; i < 4; i++) { - if (num.number[i] > 0) { - detail::print_warning("number overflow on li operation.", - file); - break; - } - } - - break; - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - if (register_sum == 0) { - for (size_t indexReg = 0UL; indexReg < reg_index; - ++indexReg) { - register_sum += 0x20; - } - } else { - register_sum += reg_index; - } - } - - if (opcodeName == "mr") { - switch (register_count) { - case 0: { - kBytes.push_back(0x78); - - char numIndex = 0x3; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x8; - } - - kBytes.push_back(numIndex); - - break; - } - case 1: { - char numIndex = 0x1; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - for (size_t i = 0; i != reg_index; i++) { - kBytes[kBytes.size() - 1] += 0x8; - } - - kBytes[kBytes.size() - 1] -= 0x8; - - kBytes.push_back(numIndex); - - if (reg_index >= 10 && reg_index < 20) - kBytes.push_back(0x7d); - else if (reg_index >= 20 && reg_index < 30) - kBytes.push_back(0x7e); - else if (reg_index >= 30) - kBytes.push_back(0x7f); - else - kBytes.push_back(0x7c); - - break; - } - default: - break; - } - - ++register_count; - ++found_some_count; - } - - if (opcodeName == "addi") { - if (found_some_count == 2 || found_some_count == 0) - kBytes.emplace_back(reg_index); - else if (found_some_count == 1) - kBytes.emplace_back(0x00); - - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("cmp") != std::string::npos) { - ++found_some_count; - - if (found_some_count > 3) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("mf") != std::string::npos || - opcodeName.find("mt") != std::string::npos) { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - num.number[2] += numIndex; - - ++found_some_count; - - if (found_some_count > 1) { - detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - - if (kVerbose) { - kStdOut << "power-as: Found register: " << register_syntax - << "\n"; - kStdOut << "power-as: Amount of registers in instruction: " - << found_some_count << "\n"; - } - - if (reg_index >= 10 && reg_index < 20) - num.number[3] = 0x7d; - else if (reg_index >= 20 && reg_index < 30) - num.number[3] = 0x7e; - else if (reg_index >= 30) - num.number[3] = 0x7f; - else - num.number[3] = 0x7c; - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - } - - found_registers_index.push_back(reg_index); - } - } - - if (opcodeName == "addi") { - kBytes.emplace_back(0x38); - } - - if (opcodeName.find("cmp") != std::string::npos) { - char rightReg = 0x0; - - for (size_t i = 0; i != found_registers_index[1]; i++) { - rightReg += 0x08; - } - - kBytes.emplace_back(0x00); - kBytes.emplace_back(rightReg); - kBytes.emplace_back(found_registers_index[0]); - kBytes.emplace_back(0x7c); - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - size_t offset = 0UL; - - if (line.find('+') != std::string::npos) { - auto number = GetNumber32(line.substr(line.find("+")), "+"); - offset = number.raw; - } - - kBytes.push_back(offset); - kBytes.push_back(0x00); - kBytes.push_back(register_sum); - - kBytes.emplace_back(0x90); - } - - if (opcodeName == "mr") { - if (register_count == 1) { - detail::print_error("Too few registers. -> " + line, file); - throw std::runtime_error("too_few_registers"); - } - } - - // we're not in immediate addressing, reg to reg. - if (opcodePPC.ops->type != GREG) { - // remember! register to register! - if (found_some_count == 1) { - detail::print_error( - "Unrecognized register found.\ntip: each power-as register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/power-cc.cxx b/Sources/power-cc.cxx deleted file mode 100644 index 4c07a04..0000000 --- a/Sources/power-cc.cxx +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kOk 0 - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cxx -/// @brief POWER C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCT OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector> fOffsets; - }; - - struct CompilerState final - { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) - file.erase(file.find(".pp"), 3); - - if (kState.fLastFile != file) - { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) - std::exit(3); - - ++kAcceptableErrors; - } - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public CompilerKit::CompilerBackend -{ -public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char* text, const char* file); - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override - { - return "POWER C"; - } -}; - -static CompilerBackendCLang* kCompilerBackend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace detail -{ - union number_cast final { - public: - number_cast(UInt64 _Raw) - : _Raw(_Raw) - { - } - - public: - char _Num[8]; - UInt64 _Raw; - }; - - union double_cast final { - public: - double_cast(float _Raw) - : _Raw(_Raw) - { - } - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; - }; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string& text, const char* file) -{ - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) - { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) - { - if (substr[y] == ' ') - { - while (match_type.find(' ') != std::string::npos) - { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) - { - if (clType.fName == match_type) - { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) - { - break; - } - - if (textBuffer.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) - { - if (textBuffer[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) - { - if (textBuffer[value_index] == ';') - break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("import") != std::string::npos) - value.erase(value.find("import"), strlen("import")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) - { - if (value.find(reg.fName) != std::string::npos) - { - found = true; - syntaxLeaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) - syntaxLeaf.fUserValue += "r0"; - } - - syntaxLeaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') - { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + - " \ndword export .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (textBuffer[text_index] == ';' && kInStruct) - continue; - - if (textBuffer.find("typedef ") != std::string::npos) - continue; - - if (textBuffer[text_index] == '=' && kInStruct) - { - detail::print_error( - "assignement of value inside a struct " + textBuffer, file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : textBuffer) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) - { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (textBuffer.find("*") != std::string::npos) - { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } - else - { - substr += "\tli "; - } - } - else if (textBuffer.find('=') != std::string::npos && !kInBraces) - { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) - { - if (textBuffer[text_index_2] == '\"') - break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') - { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - kCompilerVariables.push_back({.fName = substr}); - - if (textBuffer[text_index] == ';') - break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) - { - if (newSubstr[start] == ',') - break; - - if (newSubstr[start] == ' ') - continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntaxLeaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) - { - if (textBuffer[idx] == ',') - continue; - - if (textBuffer[idx] == ' ') - continue; - - if (textBuffer[idx] == ')') - break; - } - - for (char substr_first_index : textBuffer) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) - args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : textBuffer) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') - break; - - substr += _text_i; - } - - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - - syntaxLeaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') - { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) - { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') - { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) - kIfFound = false; - - if (kInStruct) - kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char* text, const char* file) -{ - std::string err_str; - std::string ln = text; - - if (ln.empty()) - { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (isalnum(ln[i])) - { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) - return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) - { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '\'') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } - else if (ln.find('"') != std::string::npos) - { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == '"') - { - if (ln[string_index + 1] != ';') - { - ln.erase(string_index, 1); - } - else - { - break; - } - } - } - } - else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) - { - std::vector forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) - { - if (ln.find(forbidden) != std::string::npos) - { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final - { - std::string fBegin; - std::string fEnd; - }; - - const std::vector variables_list = { - {.fBegin = "static ", .fEnd = "="}, - {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, - {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, - {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, - {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, - {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, - {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, - {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, - {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, - {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) - { - if (ln.find(variable.fBegin) != std::string::npos) - { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') - ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) - { - if (ln[string_index] == variable.fEnd[0]) - { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) - { - if (ln[index_keyword] == ' ') - { - continue; - } - - if (isdigit(ln[index_keyword])) - { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) - { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") - { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') - { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) - { - if (var.fValue.find(keyword) != std::string::npos) - { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) - { - if (fn.find(keyword[0]) != std::string::npos) - { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) - { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') - break; - - if (fn[where_begin] != keyword[keyword_begin]) - { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) - { - err_str.clear(); - goto cc_next; - } - else - { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) - return err_str; - - if (keyword.find(".") != std::string::npos) - return err_str; - - if (isalnum(keyword[0])) - err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (CompilerKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyMountpointCLang::Arch()) - return -1; - - if (kCompilerBackend == nullptr) - return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerBackend->Compile(line_src, src.data()); - } - else - { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) - return -1; - - std::vector keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("import ") != std::string::npos) - { - std::string range = "import "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_MODULE(NewOSCompilerCLangPowerPC) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) - { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) - { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) - { - if (kCompilerBackend) - std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) - { - if (kState.fVerbose) - { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/posix.make b/posix.make index 33d6dc3..832eb70 100644 --- a/posix.make +++ b/posix.make @@ -7,42 +7,42 @@ # ======================================================== # -COMMON_INC=-I./NDKKit -I./ -I./Sources/Detail +COMMON_INC=-I./NDKKit -I./ -I./NDKKit/Sources/Detail LINK_CC=clang++ -std=c++20 -LINK_SRC=Sources/link.cxx +LINK_SRC=NDKKit/Sources/link.cxx LINK_OUTPUT=Output/link LINK_ALT_OUTPUT=Output/64link LINK_ALT_3_OUTPUT=Output/i64link LINK_ALT_2_OUTPUT=Output/32link LINK_ALT_4_OUTPUT=Output/ppclink -PP_SRC=Sources/bpp.cxx +PP_SRC=NDKKit/Sources/bpp.cxx PP_OUTPUT=Output/bpp -SRC_COMMON=Sources/String.cxx Sources/AssemblyFactory.cxx +SRC_COMMON=NDKKit/Sources/String.cxx NDKKit/Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/cplusplus.cxx $(SRC_COMMON) +AMD64_CXX_SRC=NDKKit/Sources/cplusplus.cxx $(SRC_COMMON) AMD64_CXX_OUTPUT=Output/cplusplus # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cxx $(SRC_COMMON) +64X0_CC_SRC=NDKKit/Sources/64x0-cc.cxx $(SRC_COMMON) 64X0_CC_OUTPUT=Output/64x0-cc # C Compiler (Our own RISC) -PPC_CC_SRC=Sources/power-cc.cxx $(SRC_COMMON) +PPC_CC_SRC=NDKKit/Sources/power-cc.cxx $(SRC_COMMON) PPC_CC_OUTPUT=Output/power-cc # 64x0 Assembler (Our Own RISC) -ASM_SRC=Sources/64asm.cxx $(SRC_COMMON) +ASM_SRC=NDKKit/Sources/64asm.cxx $(SRC_COMMON) ASM_OUTPUT=Output/64asm # AMD64 Assembler (Intel CISC) -IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) +IASM_SRC=NDKKit/Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm # Power4 Assembler (IBM RISC) -PPCASM_SRC=Sources/power-as.cxx $(SRC_COMMON) +PPCASM_SRC=NDKKit/Sources/power-as.cxx $(SRC_COMMON) PPCASM_OUTPUT=Output/power-as .PHONY: all diff --git a/win64.make b/win64.make index fb0ae91..7fca096 100644 --- a/win64.make +++ b/win64.make @@ -7,41 +7,41 @@ # ======================================================== # -COMMON_INC=-I./NDKKit -I./ -I./Sources/Detail +COMMON_INC=-I./NDKKit -I./ -I./NDKKit/Sources/Detail LINK_CC=clang++ -std=c++20 -Xlinker -s -LINK_SRC=Sources/link.cxx +LINK_SRC=NDKKit/Sources/link.cxx LINK_OUTPUT=Output/link.exe LINK_ALT_OUTPUT=Output/64link.exe LINK_ALT_3_OUTPUT=Output/i64link.exe LINK_ALT_2_OUTPUT=Output/32link.exe -PP_SRC=Sources/bpp.cxx +PP_SRC=NDKKit/Sources/bpp.cxx PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cxx Sources/AssemblyFactory.cxx +SRC_COMMON=NDKKit/Sources/String.cxx NDKKit/Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/cplusplus.cxx $(SRC_COMMON) +AMD64_CXX_SRC=NDKKit/Sources/cplusplus.cxx $(SRC_COMMON) AMD64_CXX_OUTPUT=Output/cplusplus.exe # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cxx $(SRC_COMMON) +64X0_CC_SRC=NDKKit/Sources/64x0-cc.cxx $(SRC_COMMON) 64X0_CC_OUTPUT=Output/64x0-cc.exe # C Compiler -PPC_CC_SRC=Sources/power-cc.cxx $(SRC_COMMON) +PPC_CC_SRC=NDKKit/Sources/power-cc.cxx $(SRC_COMMON) PPC_CC_OUTPUT=Output/power-cc.exe # 64x0 Assembler -ASM_SRC=Sources/64asm.cxx $(SRC_COMMON) +ASM_SRC=NDKKit/Sources/64asm.cxx $(SRC_COMMON) ASM_OUTPUT=Output/64asm.exe # AMD64 Assembler -IASM_SRC=Sources/i64asm.cxx $(SRC_COMMON) +IASM_SRC=NDKKit/Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm.exe # POWER Assembler -PPCASM_SRC=Sources/power-as.cxx $(SRC_COMMON) +PPCASM_SRC=NDKKit/Sources/power-as.cxx $(SRC_COMMON) PPCASM_OUTPUT=Output/power-as.exe .PHONY: all -- cgit v1.2.3