diff options
| author | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-01-03 23:40:16 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal.elmahrouss@icloud.com> | 2024-01-03 23:40:16 +0100 |
| commit | b03f3d83efcbc012c4153da14eaf158bb50031d2 (patch) | |
| tree | dc004f8d0ef866c77fff7aa4ec271363b5417f9d /CompilerDriver/ccplus.cc | |
| parent | 05c51485d56b14f7cd3c05afebd920157d7a0b8b (diff) | |
tools: incremental changes, support for a C compiler will soon be here.
alongside the 32x0.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'CompilerDriver/ccplus.cc')
| -rw-r--r-- | CompilerDriver/ccplus.cc | 640 |
1 files changed, 640 insertions, 0 deletions
diff --git a/CompilerDriver/ccplus.cc b/CompilerDriver/ccplus.cc new file mode 100644 index 0000000..f9f94e4 --- /dev/null +++ b/CompilerDriver/ccplus.cc @@ -0,0 +1,640 @@ +/* + * ======================================================== + * + * ccplus + * Copyright Western Company, all rights reserved. + * + * ======================================================== + */ + +#include <cstdio> +#include <vector> +#include <string> +#include <fstream> +#include <iostream> +#include <stack> +#include <utility> +#include <uuid/uuid.h> +#include <C++Kit/AsmKit/Arch/64k.hpp> +#include <C++Kit/ParserKit.hpp> + +#define kOk 0 + +/* Western Company C driver */ +/* This is part of MP-UX C SDK. */ +/* (c) Western Company */ + +///////////////////// + +// 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 + { + std::string fName; + std::string fRegister; + }; + + struct CompilerState + { + std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + ParserKit::SyntaxLeafList* fSyntaxTree{ nullptr }; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool kVerbose; + }; +} + +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; + }; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 1; +static size_t kUsableLimit = 14; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; +static std::vector<std::string> kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector<std::string> kFileList; +static CxxKit::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 Western Company C */ +class CompilerBackendClang final : public ParserKit::CompilerBackend +{ +public: + explicit CompilerBackendClang() = default; + ~CompilerBackendClang() override = default; + + CXXKIT_COPY_DEFAULT(CompilerBackendClang); + + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override { return "Optimized 64x0 C++"; } + +}; + +static CompilerBackendClang* kCompilerBackend = nullptr; +static std::vector<detail::CompilerType> kCompilerVariables; +static std::vector<std::string> kCompilerFunctions; + +namespace detail +{ + union number_cast + { + number_cast(UInt64 raw) + : raw(raw) + {} + + char number[8]; + UInt64 raw; + + }; + + struct ast_interface + { + explicit ast_interface(std::string& value) + : mValue(value) + { + this->_Compile(); + } + + ~ast_interface() = default; + + CXXKIT_COPY_DEFAULT(ast_interface); + + private: + std::string mProcessed; + std::string mValue; + + void _Compile() noexcept + { + if (mValue.empty()) + { + return; + } + + + } + + }; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C source. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendClang::Compile(const std::string& text, const char* file) +{ + if (text.empty()) + return false; + + // if (expr) + // int name = expr; + // expr; + + std::size_t index = 0UL; + + auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); + + syntax_tree.fUserData = text; + kState.fSyntaxTree->fLeafList.push_back(syntax_tree); + + std::string text_cpy = text; + + std::vector<std::pair<std::string, std::size_t>> keywords_list; + + for (auto& keyword : kKeywords) + { + while (text_cpy.find(keyword) != std::string::npos) + { + keywords_list.push_back(std::make_pair(keyword, index)); + ++index; + + text_cpy.erase(text_cpy.find(keyword), keyword.size()); + } + } + + // TODO: sort keywords + + for (auto& keyword : keywords_list) + { + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.push_back(syntax_tree); + + std::cout << keyword.first << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointClang final : public CxxKit::AssemblyMountpoint +{ +public: + explicit AssemblyMountpointClang() = default; + ~AssemblyMountpointClang() override = default; + + CXXKIT_COPY_DEFAULT(AssemblyMountpointClang); + + [[maybe_unused]] static Int32 Arch() noexcept { return CxxKit::AssemblyFactory::kArchRISCV; } + + Int32 CompileToFormat(CxxKit::StringView& 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.CData(); + 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. */ + dest += kAsmFileExt64x0; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = CxxKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) << "# Language: MP-UX Assembly\n"; + (*kState.fOutputAssembly) << "# Build Date: " << fmt << "\n\n"; + + ParserKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string source; + + while (std::getline(src_fp, source)) + { + kCompilerBackend->Compile(source.c_str(), src.CData()); + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector<std::string> lines; + + struct scope_type + { + std::vector<std::string> vals; + int reg_cnt; + int id; + + bool operator==(const scope_type& typ) { return typ.id == id; } + }; + + std::vector<scope_type> scope; + bool found_type = false; + bool is_pointer = false; + bool found_expr = false; + bool found_func = false; + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + if (leaf.fUserData == "{") + { + scope.push_back({}); + } + + if (leaf.fUserData == "{") + { + scope.pop_back(); + } + + if (leaf.fUserData == "int" || + leaf.fUserData == "long" || + leaf.fUserData == "unsigned" || + leaf.fUserData == "short" || + leaf.fUserData == "char" || + leaf.fUserData == "struct" || + leaf.fUserData == "class") + { + found_type = true; + } + + if (leaf.fUserData == "(") + { + if (found_type) + { + found_expr = true; + found_type = false; + is_pointer = false; + } + } + + if (leaf.fUserData == ")") + { + if (found_expr) + { + found_expr = false; + is_pointer = false; + } + } + + if (leaf.fUserData == ",") + { + if (is_pointer) + { + is_pointer = false; + } + } + + if (leaf.fUserData == "*") + { + if (found_type && !found_expr) + is_pointer = true; + } + + if (leaf.fUserData == "=") + { + auto& front = scope.front(); + + if (found_type) + { + std::string reg = "r"; + reg += std::to_string(front.reg_cnt); + ++front.reg_cnt; + + leaf.fUserValue = !is_pointer ? "ldw %s, %s1\n" : "lda %s, %s1\n"; + + for (auto& ln : lines) + { + if (ln.find(leaf.fUserData) != std::string::npos && + ln.find(";") != std::string::npos) + { + auto val = ln.substr(ln.find(leaf.fUserData) + leaf.fUserData.size()); + val.erase(val.find(";"), 1); + + leaf.fUserValue.replace(leaf.fUserValue.find("%s1"), strlen("%s1"), val); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find("%s"), strlen("%s"), reg); + } + + is_pointer = false; + found_type = false; + } + + if (leaf.fUserData == "return") + { + leaf.fUserValue = "ldw r19, %s\njlr"; + + if (!lines.empty()) + { + for (auto& ln : lines) + { + if (ln.find(leaf.fUserData) != std::string::npos && + ln.find(";") != std::string::npos) + { + auto val = ln.substr(ln.find(leaf.fUserData) + leaf.fUserData.size()); + val.erase(val.find(";"), 1); + + leaf.fUserValue.replace(leaf.fUserValue.find("%s"), strlen("%s"), val); + } + } + } + else + { + leaf.fUserValue.replace(leaf.fUserValue.find("%s"), strlen("%s"), "0"); + } + + continue; + } + + lines.push_back(leaf.fUserData); + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } + +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kPrintF printf +#define kSplashCxx() kPrintF(kWhite "%s\n", "ccplus, v1.14, (c) Western Company.") + +static void cxx_print_help() +{ + kSplashCxx(); + kPrintF(kWhite "--asm={MACHINE}: %s\n", "Compile with a specific syntax. (64x0, 32x0)"); + kPrintF(kWhite "--compiler={COMPILER}: %s\n", "Select compiler engine (builtin -> vanhalen++)."); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".cc" + +int main(int argc, char** argv) +{ + kKeywords.push_back("auto"); + kKeywords.push_back("else"); + kKeywords.push_back("break"); + kKeywords.push_back("switch"); + kKeywords.push_back("enum"); + kKeywords.push_back("register"); + kKeywords.push_back("do"); + kKeywords.push_back("return"); + kKeywords.push_back("if"); + kKeywords.push_back("default"); + kKeywords.push_back("struct"); + kKeywords.push_back("_Packed"); + kKeywords.push_back("extern"); + kKeywords.push_back("volatile"); + kKeywords.push_back("static"); + kKeywords.push_back("for"); + kKeywords.push_back("class"); + kKeywords.push_back("{"); + kKeywords.push_back("}"); + kKeywords.push_back("("); + kKeywords.push_back(")"); + kKeywords.push_back("char"); + kKeywords.push_back("int"); + kKeywords.push_back("short"); + kKeywords.push_back("long"); + kKeywords.push_back("float"); + kKeywords.push_back("double"); + kKeywords.push_back("unsigned"); + kKeywords.push_back("__export__"); + kKeywords.push_back("__packed__"); + kKeywords.push_back("namespace"); + kKeywords.push_back("while"); + kKeywords.push_back("sizeof"); + kKeywords.push_back("private"); + kKeywords.push_back("->"); + kKeywords.push_back("."); + kKeywords.push_back("::"); + kKeywords.push_back("*"); + kKeywords.push_back("+"); + kKeywords.push_back("-"); + kKeywords.push_back("/"); + kKeywords.push_back("="); + kKeywords.push_back("=="); + kKeywords.push_back("!="); + kKeywords.push_back(">="); + kKeywords.push_back("<="); + kKeywords.push_back(">"); + kKeywords.push_back("<"); + kKeywords.push_back(":"); + kKeywords.push_back(","); + kKeywords.push_back(";"); + kKeywords.push_back("public"); + kKeywords.push_back("protected"); + + bool skip = false; + + 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.kVerbose = 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], "--asm=masm") == 0) + { + delete kFactory.Unmount(); + + kFactory.Mount(new AssemblyMountpointClang()); + kMachine = CxxKit::AssemblyFactory::kArchRISCV; + + continue; + } + + if (strcmp(argv[index], "--compiler=vanhalen") == 0) + { + if (!kCompilerBackend) + kCompilerBackend = new CompilerBackendClang(); + + continue; + } + + 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, "ccplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + CxxKit::StringView srcFile = CxxKit::StringBuilder::Construct(argv[index]); + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.kVerbose) + { + std::cerr << argv[index] << " is not a valid C source.\n"; + } + + return -1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} |
