summaryrefslogtreecommitdiffhomepage
path: root/Sources/cplusplus.cc
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-05-06 14:36:19 +0200
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-05-06 14:36:19 +0200
commite4ee6e2ab0559176ff021875111158869b827528 (patch)
tree870368df72158cbee78db7afca53b5ce0e421f1b /Sources/cplusplus.cc
parent8b4e2d599909952d805d05445d98b82383622e66 (diff)
MHR-21: Improve ParserKit, as well as C++ compiler for better parsing.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'Sources/cplusplus.cc')
-rw-r--r--Sources/cplusplus.cc428
1 files changed, 428 insertions, 0 deletions
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 <Headers/AsmKit/CPU/amd64.hpp>
+#include <Headers/ParserKit.hpp>
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<std::pair<Int32, std::string>> fOffsets;
+};
+
+struct CompilerState final {
+ std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ ParserKit::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> 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<ParserKit::CompilerKeyword> kKeywords;
+
+/////////////////////////////////////////
+
+// COMPILER PARSING UTILITIES/STATES.
+
+/////////////////////////////////////////
+
+static std::vector<std::string> 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<detail::CompilerType> kCompilerVariables;
+static std::vector<std::string> 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<std::pair<ParserKit::CompilerKeyword, std::size_t>> 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<const char*> exts = kAsmFileExts;
+ dest += exts[3];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(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