summaryrefslogtreecommitdiffhomepage
path: root/dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-05-23 03:48:06 +0200
committerAmlal El Mahrouss <amlal@nekernel.org>2025-05-23 03:48:06 +0200
commit2eed4954c762bb8050e40798c3d9f1d3998324d1 (patch)
tree8848d4345fca4d62c23d1e7136eeff2978c9e6c5 /dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc
parent8ad58a91a11380203c4a81fe4dc93e7734631b32 (diff)
feat!(LibCompiler): Codebase and diagram has been improved.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc')
-rw-r--r--dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc921
1 files changed, 921 insertions, 0 deletions
diff --git a/dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc b/dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc
new file mode 100644
index 0000000..c99508c
--- /dev/null
+++ b/dev/LibCompiler/src/Cl/CPlusPlusCompilerAMD64.cc
@@ -0,0 +1,921 @@
+/*
+ * ========================================================
+ *
+ * cxxdrv
+ * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/// BUGS: 1
+
+#define kPrintF printf
+
+#define kExitOK (EXIT_SUCCESS)
+#define kExitNO (EXIT_FAILURE)
+
+// extern_segment, @autodelete { ... }, fn foo() -> auto { ... }
+
+#include <LibCompiler/Backend/X64.h>
+#include <LibCompiler/Util/LCClUtils.h>
+#include <LibCompiler/Frontend.h>
+#include <LibCompiler/UUID.h>
+
+/* NeKernel C++ Compiler Driver */
+/* This is part of the LibCompiler. */
+/* (c) Amlal El Mahrouss */
+
+/// @author EL Mahrouss Amlal (amlal@nekernel.org)
+/// @file CPlusPlusCompilerAMD64.cxx
+/// @brief Optimized C++ Compiler Driver.
+/// @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 {
+std::filesystem::path expand_home(const std::filesystem::path& p) {
+ if (!p.empty() && p.string()[0] == '~') {
+ const char* home = std::getenv("HOME"); // For Unix-like systems
+
+ if (!home) {
+ home = std::getenv("USERPROFILE"); // For Windows
+ }
+
+ if (home) {
+ return std::filesystem::path(home) / p.relative_path().string().substr(1);
+ } else {
+ throw std::runtime_error("Home directory not found in environment variables");
+ }
+ }
+ return p;
+}
+
+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<std::pair<UInt32, std::string>> fOffsets;
+};
+
+struct CompilerState final {
+ std::vector<CompilerRegisterMap> fStackMapVector;
+ std::vector<CompilerStructMap> fStructMapVector;
+ std::string fOutputValue;
+ std::string fLastFile;
+ std::string fLastError;
+};
+} // namespace Detail
+
+static Detail::CompilerState kState;
+
+static Int32 kOnClassScope = 0;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// Target architecture.
+static int kMachine = LibCompiler::AssemblyFactory::kArchAMD64;
+
+/////////////////////////////////////////
+
+// ARGUMENTS REGISTERS (R8, R15)
+
+/////////////////////////////////////////
+
+static std::vector<LibCompiler::CompilerKeyword> kKeywords;
+
+/////////////////////////////////////////
+
+// COMPILER PARSING UTILITIES/STATES.
+
+/////////////////////////////////////////
+
+static LibCompiler::AssemblyFactory kFactory;
+static Boolean kInStruct = false;
+static Boolean kOnWhileLoop = false;
+static Boolean kOnForLoop = false;
+static Boolean kInBraces = false;
+static size_t kBracesCount = 0UL;
+
+/* @brief C++ compiler backend for the NeKernel C++ driver */
+class CompilerFrontendCPlusPlus final : public LibCompiler::CompilerFrontendInterface {
+ public:
+ explicit CompilerFrontendCPlusPlus() = default;
+ ~CompilerFrontendCPlusPlus() override = default;
+
+ LIBCOMPILER_COPY_DEFAULT(CompilerFrontendCPlusPlus);
+
+ Boolean Compile(const std::string text, std::string file) override;
+
+ const char* Language() override;
+};
+
+/// @internal compiler variables
+
+static CompilerFrontendCPlusPlus* kCompilerFrontend = nullptr;
+
+static std::vector<std::string> kRegisterMap;
+
+static std::vector<std::string> kRegisterList = {
+ "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<std::string> kRegisterConventionCallList = {
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+};
+
+static std::size_t kFunctionEmbedLevel = 0UL;
+
+/// detail namespaces
+
+const char* CompilerFrontendCPlusPlus::Language() {
+ return "AMD64 C++";
+}
+
+static std::uintptr_t kOrigin = 0x1000000;
+static std::vector<std::pair<std::string, std::uintptr_t>> kOriginMap;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @name Compile
+/// @brief Generate assembly from a C++ source.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+Boolean CompilerFrontendCPlusPlus::Compile(std::string text, std::string file) {
+ if (text.length() < 1) return false;
+
+ std::size_t index = 0UL;
+ std::vector<std::pair<LibCompiler::CompilerKeyword, std::size_t>> keywords_list;
+
+ for (auto& keyword : kKeywords) {
+ if (text.find(keyword.keyword_name) != std::string::npos) {
+ switch (keyword.keyword_kind) {
+ case LibCompiler::kKeywordKindCommentInline: {
+ break;
+ }
+ default:
+ break;
+ }
+
+ std::size_t pos = text.find(keyword.keyword_name);
+ if (pos == std::string::npos) continue;
+
+ // Safe guard: can't go before start of string
+ if (pos > 0 && text[pos - 1] == '+' &&
+ keyword.keyword_kind == LibCompiler::kKeywordKindVariableAssign)
+ continue;
+
+ if (pos > 0 && text[pos - 1] == '-' &&
+ keyword.keyword_kind == LibCompiler::kKeywordKindVariableAssign)
+ continue;
+
+ // Safe guard: don't go out of range
+ if ((pos + keyword.keyword_name.size()) < text.size() &&
+ text[pos + keyword.keyword_name.size()] == '=' &&
+ keyword.keyword_kind == LibCompiler::kKeywordKindVariableAssign)
+ continue;
+
+ keywords_list.emplace_back(std::make_pair(keyword, index));
+ ++index;
+ }
+ }
+
+ LibCompiler::SyntaxLeafList::SyntaxLeaf syntax_tree;
+
+ for (auto& keyword : keywords_list) {
+ if (text.find(keyword.first.keyword_name) == std::string::npos) continue;
+
+ switch (keyword.first.keyword_kind) {
+ case LibCompiler::KeywordKind::kKeywordKindClass: {
+ ++kOnClassScope;
+ break;
+ }
+ case LibCompiler::KeywordKind::kKeywordKindIf: {
+ std::size_t keywordPos = text.find(keyword.first.keyword_name);
+ std::size_t openParen = text.find("(", keywordPos);
+ std::size_t closeParen = text.find(")", openParen);
+
+ if (keywordPos == std::string::npos || openParen == std::string::npos ||
+ closeParen == std::string::npos || closeParen <= openParen) {
+ Detail::print_error("Malformed if expression: " + text, file);
+ return false;
+ }
+
+ auto expr = text.substr(openParen + 1, closeParen - openParen - 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;
+
+ if (i < 1) break;
+
+ 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;
+
+ if (!valueOfVar.empty()) {
+ for (auto pairRight : kRegisterMap) {
+ ++indexRight;
+
+ if (pairRight != valueOfVar) {
+ auto& valueOfVarOpposite = isdigit(left[0]) ? left : right;
+
+ syntax_tree.fUserValue +=
+ "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n";
+ syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," +
+ kRegisterList[indexRight + 1] + "\n";
+
+ goto done_iterarting_on_if;
+ }
+
+ auto& valueOfVarOpposite = isdigit(left[0]) ? left : right;
+
+ syntax_tree.fUserValue +=
+ "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n";
+ syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " +
+ kRegisterList[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_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n";
+ }
+
+ break;
+ }
+ case LibCompiler::KeywordKind::kKeywordKindFunctionStart: {
+ for (auto& ch : text) {
+ if (isdigit(ch)) {
+ goto dont_accept;
+ }
+ }
+
+ goto accept;
+
+ dont_accept:
+ return false;
+
+ accept:
+ std::string fnName = text;
+ size_t indexFnName = 0;
+
+ // this one is for the type.
+ for (auto& ch : text) {
+ ++indexFnName;
+
+ if (ch == '\t') break;
+ if (ch == ' ') break;
+ }
+
+ fnName = text.substr(indexFnName);
+
+ if (text.find("return ") != std::string::npos) {
+ text.erase(0, text.find("return "));
+ break;
+ }
+
+ if (text.ends_with(";") && text.find("return") == std::string::npos)
+ goto lc_write_assembly;
+ else if (text.size() <= indexFnName)
+ Detail::print_error("Invalid function name: " + fnName, file);
+
+ indexFnName = 0;
+
+ for (auto& ch : fnName) {
+ if (ch == ' ' || ch == '\t') {
+ if (fnName[indexFnName - 1] != ')')
+ Detail::print_error("Invalid function name: " + fnName, file);
+ }
+
+ ++indexFnName;
+ }
+
+ if (fnName.find("(") != LibCompiler::STLString::npos) {
+ fnName.erase(fnName.find("("));
+ }
+
+ syntax_tree.fUserValue = "public_segment .code64 __LIBCOMPILER_" + fnName + "\n";
+ ++kFunctionEmbedLevel;
+
+ kOriginMap.push_back({"__LIBCOMPILER_" + fnName, kOrigin});
+
+ break;
+
+ lc_write_assembly:
+ auto it = std::find_if(kOriginMap.begin(), kOriginMap.end(),
+ [&fnName](std::pair<std::string, std::uintptr_t> pair) -> bool {
+ return fnName == pair.first;
+ });
+
+ if (it != kOriginMap.end()) {
+ std::stringstream ss;
+ ss << std::hex << it->second;
+
+ syntax_tree.fUserValue = "jmp " + ss.str() + "\n";
+ kOrigin += 1UL;
+ }
+ }
+ case LibCompiler::KeywordKind::kKeywordKindFunctionEnd: {
+ if (kOnClassScope) --kOnClassScope;
+
+ if (text.ends_with(";")) break;
+
+ --kFunctionEmbedLevel;
+
+ if (kRegisterMap.size() > kRegisterList.size()) {
+ --kFunctionEmbedLevel;
+ }
+
+ if (kFunctionEmbedLevel < 1) kRegisterMap.clear();
+
+ break;
+ }
+ case LibCompiler::KeywordKind::kKeywordKindEndInstr:
+ case LibCompiler::KeywordKind::kKeywordKindVariableInc:
+ case LibCompiler::KeywordKind::kKeywordKindVariableDec:
+ case LibCompiler::KeywordKind::kKeywordKindVariableAssign: {
+ std::string valueOfVar = "";
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) {
+ valueOfVar = text.substr(text.find("+=") + 2);
+ } else if (keyword.first.keyword_kind ==
+ LibCompiler::KeywordKind::kKeywordKindVariableDec) {
+ valueOfVar = text.substr(text.find("-=") + 2);
+ } else if (keyword.first.keyword_kind ==
+ LibCompiler::KeywordKind::kKeywordKindVariableAssign) {
+ valueOfVar = text.substr(text.find("=") + 1);
+ } else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) {
+ break;
+ }
+
+ while (valueOfVar.find(";") != std::string::npos &&
+ keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindEndInstr) {
+ valueOfVar.erase(valueOfVar.find(";"));
+ }
+
+ std::string varName = text;
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) {
+ varName.erase(varName.find("+="));
+ } else if (keyword.first.keyword_kind ==
+ LibCompiler::KeywordKind::kKeywordKindVariableDec) {
+ varName.erase(varName.find("-="));
+ } else if (keyword.first.keyword_kind ==
+ LibCompiler::KeywordKind::kKeywordKindVariableAssign) {
+ varName.erase(varName.find("="));
+ } else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) {
+ varName.erase(varName.find(";"));
+ }
+
+ static Boolean typeFound = false;
+
+ for (auto& keyword : kKeywords) {
+ if (keyword.keyword_kind == LibCompiler::kKeywordKindType) {
+ 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 &&
+ keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableInc &&
+ keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableDec) {
+ if (kRegisterMap.size() > kRegisterList.size()) {
+ ++kFunctionEmbedLevel;
+ }
+
+ 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 kTrueVal = "true";
+ constexpr auto kFalseVal = "false";
+
+ if (valueOfVar == kTrueVal) {
+ valueOfVar = "1";
+ } else if (valueOfVar == kFalseVal) {
+ valueOfVar = "0";
+ }
+
+ std::size_t indexRight = 0UL;
+
+ for (auto pairRight : kRegisterMap) {
+ ++indexRight;
+
+ if (pairRight != valueOfVar) {
+ if (valueOfVar[0] == '\"') {
+ syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName +
+ ": db " + valueOfVar + ", 0\n\n";
+ syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " +
+ "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n";
+ kOrigin += 1UL;
+ } else {
+ syntax_tree.fUserValue =
+ instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n";
+ kOrigin += 1UL;
+ }
+
+ goto done;
+ }
+ }
+
+ if (((int) indexRight - 1) < 0) {
+ if (valueOfVar[0] == '\"') {
+ syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName +
+ ": db " + valueOfVar + ", 0\n";
+ syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " +
+ "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n";
+ kOrigin += 1UL;
+ } else {
+ syntax_tree.fUserValue =
+ instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n";
+ kOrigin += 1UL;
+ }
+
+ goto done;
+ }
+
+ if (valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && !isdigit(valueOfVar[0])) {
+ for (auto pair : kRegisterMap) {
+ if (pair == valueOfVar) goto done;
+ }
+
+ Detail::print_error("Variable not declared: " + varName, file);
+ return false;
+ }
+
+ done:
+ for (auto& keyword : kKeywords) {
+ if (keyword.keyword_kind == LibCompiler::kKeywordKindType &&
+ varName.find(keyword.keyword_name) != std::string::npos) {
+ varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size());
+ break;
+ }
+ }
+
+ kRegisterMap.push_back(varName);
+
+ break;
+ }
+
+ if (kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindType ||
+ kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindTypePtr) {
+ syntax_tree.fUserValue = "\n";
+ continue;
+ }
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) {
+ syntax_tree.fUserValue = "\n";
+ continue;
+ }
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) {
+ instr = "add ";
+ } else if (keyword.first.keyword_kind ==
+ LibCompiler::KeywordKind::kKeywordKindVariableDec) {
+ 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 kTrueVal = "true";
+ constexpr auto kFalseVal = "false";
+
+ /// interpet boolean values, since we're on C++
+
+ if (valueOfVar == kTrueVal) {
+ valueOfVar = "1";
+ } else if (valueOfVar == kFalseVal) {
+ 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 + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n";
+ kOrigin += 1UL;
+ continue;
+ }
+
+ syntax_tree.fUserValue =
+ instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n";
+ kOrigin += 1UL;
+ break;
+ }
+
+ break;
+ }
+
+ if (syntax_tree.fUserValue.empty()) {
+ Detail::print_error("Variable not declared: " + varName, file);
+ }
+
+ break;
+ }
+ case LibCompiler::KeywordKind::kKeywordKindReturn: {
+ try {
+ 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, " + kRegisterList[indxReg - 1] + "\nret\n";
+ kOrigin += 1UL;
+
+ break;
+ }
+ } else {
+ syntax_tree.fUserValue = "mov rax, " + subText + "\nret\n";
+ kOrigin += 1UL;
+
+ break;
+ }
+ } else {
+ syntax_tree.fUserValue = "__LIBCOMPILER_LOCAL_RETURN_STRING: db " + subText +
+ ", 0\nmov rcx, __LIBCOMPILER_LOCAL_RETURN_STRING\n";
+ syntax_tree.fUserValue += "mov rax, rcx\nret\n";
+ kOrigin += 1UL;
+
+ break;
+ }
+
+ if (syntax_tree.fUserValue.empty()) {
+ if (subText.find("(") != std::string::npos) {
+ subText.erase(subText.find("("));
+
+ auto it =
+ std::find_if(kOriginMap.begin(), kOriginMap.end(),
+ [&subText](std::pair<std::string, std::uintptr_t> pair) -> bool {
+ return pair.first.find(subText) != std::string::npos;
+ });
+
+ if (it == kOriginMap.end())
+ Detail::print_error("Invalid return value: " + subText, file);
+
+ std::stringstream ss;
+ ss << it->second;
+
+ syntax_tree.fUserValue = "jmp " + ss.str() + "\nret\n";
+ kOrigin += 1UL;
+ break;
+ }
+ }
+
+ break;
+ } catch (...) {
+ syntax_tree.fUserValue = "ret\n";
+ kOrigin += 1UL;
+ }
+ }
+ default: {
+ continue;
+ }
+ }
+ }
+
+ kState.fOutputValue = syntax_tree.fUserValue;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief C++ assembler class.
+ */
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class AssemblyCPlusPlusInterface final LC_ASSEMBLY_INTERFACE {
+ public:
+ explicit AssemblyCPlusPlusInterface() = default;
+ ~AssemblyCPlusPlusInterface() override = default;
+
+ LIBCOMPILER_COPY_DEFAULT(AssemblyCPlusPlusInterface);
+
+ UInt32 Arch() noexcept override { return LibCompiler::AssemblyFactory::kArchAMD64; }
+
+ Int32 CompileToFormat(std::string src, Int32 arch) override {
+ if (kCompilerFrontend == nullptr) return kExitNO;
+
+ std::string dest = src;
+ dest += ".pp.masm";
+
+ std::ofstream out_fp(dest);
+
+ std::ifstream src_fp = std::ifstream(src);
+
+ std::string line_source;
+
+ while (std::getline(src_fp, line_source)) {
+ if (kVerbose) {
+ kStdOut << line_source << std::endl;
+ kStdOut << line_source.length() << " bytes\n";
+ }
+
+ kCompilerFrontend->Compile(line_source, src);
+
+ out_fp << kState.fOutputValue;
+ kState.fOutputValue.clear();
+ }
+
+ if (kVerbose) {
+ kStdOut << "Done compiling " << src << " to " << dest << "\n";
+ }
+
+ return kExitOK;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define kExtListCxx \
+ { ".cpp", ".cxx", ".cc", ".c++", ".cp" }
+
+LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) {
+ Boolean skip = false;
+
+ kKeywords.push_back({.keyword_name = "if", .keyword_kind = LibCompiler::kKeywordKindIf});
+ kKeywords.push_back({.keyword_name = "else", .keyword_kind = LibCompiler::kKeywordKindElse});
+ kKeywords.push_back({.keyword_name = "else if", .keyword_kind = LibCompiler::kKeywordKindElseIf});
+
+ kKeywords.push_back({.keyword_name = "class", .keyword_kind = LibCompiler::kKeywordKindClass});
+ kKeywords.push_back({.keyword_name = "struct", .keyword_kind = LibCompiler::kKeywordKindClass});
+ kKeywords.push_back(
+ {.keyword_name = "namespace", .keyword_kind = LibCompiler::kKeywordKindNamespace});
+ kKeywords.push_back(
+ {.keyword_name = "typedef", .keyword_kind = LibCompiler::kKeywordKindTypedef});
+ kKeywords.push_back({.keyword_name = "using", .keyword_kind = LibCompiler::kKeywordKindTypedef});
+ kKeywords.push_back({.keyword_name = "{", .keyword_kind = LibCompiler::kKeywordKindBodyStart});
+ kKeywords.push_back({.keyword_name = "}", .keyword_kind = LibCompiler::kKeywordKindBodyEnd});
+ kKeywords.push_back({.keyword_name = "auto", .keyword_kind = LibCompiler::kKeywordKindVariable});
+ kKeywords.push_back({.keyword_name = "int", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "bool", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "short", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "char", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "long", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "float", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "double", .keyword_kind = LibCompiler::kKeywordKindType});
+ kKeywords.push_back({.keyword_name = "void", .keyword_kind = LibCompiler::kKeywordKindType});
+
+ kKeywords.push_back(
+ {.keyword_name = "auto*", .keyword_kind = LibCompiler::kKeywordKindVariablePtr});
+ kKeywords.push_back({.keyword_name = "int*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back(
+ {.keyword_name = "unsigned*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "short*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "char*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "long*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "float*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back(
+ {.keyword_name = "double*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "void*", .keyword_kind = LibCompiler::kKeywordKindTypePtr});
+
+ kKeywords.push_back(
+ {.keyword_name = "(", .keyword_kind = LibCompiler::kKeywordKindFunctionStart});
+ kKeywords.push_back({.keyword_name = ")", .keyword_kind = LibCompiler::kKeywordKindFunctionEnd});
+ kKeywords.push_back(
+ {.keyword_name = "=", .keyword_kind = LibCompiler::kKeywordKindVariableAssign});
+ kKeywords.push_back({.keyword_name = "+=", .keyword_kind = LibCompiler::kKeywordKindVariableInc});
+ kKeywords.push_back({.keyword_name = "-=", .keyword_kind = LibCompiler::kKeywordKindVariableDec});
+ kKeywords.push_back({.keyword_name = "const", .keyword_kind = LibCompiler::kKeywordKindConstant});
+ kKeywords.push_back({.keyword_name = "*", .keyword_kind = LibCompiler::kKeywordKindPtr});
+ kKeywords.push_back({.keyword_name = "->", .keyword_kind = LibCompiler::kKeywordKindPtrAccess});
+ kKeywords.push_back({.keyword_name = ".", .keyword_kind = LibCompiler::kKeywordKindAccess});
+ kKeywords.push_back({.keyword_name = ",", .keyword_kind = LibCompiler::kKeywordKindArgSeparator});
+ kKeywords.push_back({.keyword_name = ";", .keyword_kind = LibCompiler::kKeywordKindEndInstr});
+ kKeywords.push_back({.keyword_name = ":", .keyword_kind = LibCompiler::kKeywordKindSpecifier});
+ kKeywords.push_back(
+ {.keyword_name = "public:", .keyword_kind = LibCompiler::kKeywordKindSpecifier});
+ kKeywords.push_back(
+ {.keyword_name = "private:", .keyword_kind = LibCompiler::kKeywordKindSpecifier});
+ kKeywords.push_back(
+ {.keyword_name = "protected:", .keyword_kind = LibCompiler::kKeywordKindSpecifier});
+ kKeywords.push_back(
+ {.keyword_name = "final", .keyword_kind = LibCompiler::kKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "return", .keyword_kind = LibCompiler::kKeywordKindReturn});
+ kKeywords.push_back(
+ {.keyword_name = "/*", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineStart});
+ kKeywords.push_back(
+ {.keyword_name = "*/", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineEnd});
+ kKeywords.push_back(
+ {.keyword_name = "//", .keyword_kind = LibCompiler::kKeywordKindCommentInline});
+ kKeywords.push_back({.keyword_name = "==", .keyword_kind = LibCompiler::kKeywordKindEq});
+ kKeywords.push_back({.keyword_name = "!=", .keyword_kind = LibCompiler::kKeywordKindNotEq});
+ kKeywords.push_back({.keyword_name = ">=", .keyword_kind = LibCompiler::kKeywordKindGreaterEq});
+ kKeywords.push_back({.keyword_name = "<=", .keyword_kind = LibCompiler::kKeywordKindLessEq});
+
+ kErrorLimit = 100;
+
+ kCompilerFrontend = new CompilerFrontendCPlusPlus();
+ kFactory.Mount(new AssemblyCPlusPlusInterface());
+
+ ::signal(SIGSEGV, Detail::drv_segfault_handler);
+
+ for (auto index = 1UL; index < argc; ++index) {
+ if (argv[index][0] == '-') {
+ if (skip) {
+ skip = false;
+ continue;
+ }
+
+ if (strcmp(argv[index], "-cxx-verbose") == 0) {
+ kVerbose = true;
+
+ continue;
+ }
+
+ if (strcmp(argv[index], "-cxx-dialect") == 0) {
+ if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n";
+
+ return LIBCOMPILER_SUCCESS;
+ }
+
+ if (strcmp(argv[index], "-cxx-max-err") == 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, "cxxdrv");
+
+ continue;
+ }
+
+ std::string argv_i = argv[index];
+
+ std::vector<std::string> exts = kExtListCxx;
+ BOOL found = false;
+
+ for (std::string ext : exts) {
+ if (argv_i.ends_with(ext)) {
+ found = true;
+
+ if (kFactory.Compile(argv_i, kMachine) != kExitOK) {
+ return LIBCOMPILER_INVALID_DATA;
+ }
+ }
+ }
+
+ if (!found) {
+ if (kVerbose) {
+ Detail::print_error(argv_i + " is not a valid C++ source.", "cxxdrv");
+ }
+
+ return LIBCOMPILER_INVALID_DATA;
+ }
+ }
+
+ kFactory.Unmount();
+
+ delete kCompilerFrontend;
+ kCompilerFrontend = nullptr;
+
+ kRegisterMap.clear();
+ kOriginMap.clear();
+
+ return LIBCOMPILER_SUCCESS;
+}
+
+//
+// Last rev 8-1-24
+//