From 1c8c5cff67b20d86c442b0917d6c1fc6407140df Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 30 Jul 2025 08:50:15 +0100 Subject: feat! Breaking API changes of NeCTI's LibCompiler and LibDebugger. what: - They've now become CompilerKit and DebuggerKit. - Expanding XCoff for NeBoot PowerPC backend. Signed-off-by: Amlal El Mahrouss --- dev/CompilerKit/src/Backend/Assembler32x0.cc | 39 + dev/CompilerKit/src/Backend/Assembler64x0.cc | 874 +++++++++++++ dev/CompilerKit/src/Backend/AssemblerAMD64.cc | 1206 ++++++++++++++++++ dev/CompilerKit/src/Backend/AssemblerARM64.cc | 587 +++++++++ dev/CompilerKit/src/Backend/AssemblerPowerPC.cc | 911 ++++++++++++++ dev/CompilerKit/src/BasicString.cc | 207 ++++ dev/CompilerKit/src/CodeGen.cc | 52 + dev/CompilerKit/src/Frontend.cc | 51 + dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 1286 +++++++++++++++++++ dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 1284 +++++++++++++++++++ dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 1303 ++++++++++++++++++++ .../src/Frontend/CPlusPlusCompilerAMD64.cc | 892 ++++++++++++++ dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 672 ++++++++++ .../src/Macro/CPlusPlusCompilerPreProcessor.cc | 893 ++++++++++++++ 14 files changed, 10257 insertions(+) create mode 100644 dev/CompilerKit/src/Backend/Assembler32x0.cc create mode 100644 dev/CompilerKit/src/Backend/Assembler64x0.cc create mode 100644 dev/CompilerKit/src/Backend/AssemblerAMD64.cc create mode 100644 dev/CompilerKit/src/Backend/AssemblerARM64.cc create mode 100644 dev/CompilerKit/src/Backend/AssemblerPowerPC.cc create mode 100644 dev/CompilerKit/src/BasicString.cc create mode 100644 dev/CompilerKit/src/CodeGen.cc create mode 100644 dev/CompilerKit/src/Frontend.cc create mode 100644 dev/CompilerKit/src/Frontend/CCompiler64x0.cc create mode 100644 dev/CompilerKit/src/Frontend/CCompilerARM64.cc create mode 100644 dev/CompilerKit/src/Frontend/CCompilerPower64.cc create mode 100644 dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc create mode 100644 dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc create mode 100644 dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc new file mode 100644 index 0000000..e298d2d --- /dev/null +++ b/dev/CompilerKit/src/Backend/Assembler32x0.cc @@ -0,0 +1,39 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file 32asm.cxx +// @author EL Mahrouss Amlal +// @brief 32x0 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __ASM_NEED_32x0__ +#define __ASM_NEED_32x0__ 1 +#endif + +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 32x0 Assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(NEAssemblerMain32000) { + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + return EXIT_SUCCESS; +} diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc new file mode 100644 index 0000000..32b199d --- /dev/null +++ b/dev/CompilerKit/src/Backend/Assembler64x0.cc @@ -0,0 +1,874 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +/// bugs: 0 + +///////////////////////////////////////////////////////////////////////////////////////// + +// @file Assembler64x0.cxx +// @author EL Mahrouss Amlal +// @brief 64x000 Assembler. + +// REMINDER: when dealing with an undefined symbol use (string +// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __ASM_NEED_64x0__ +#define __ASM_NEED_64x0__ 1 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +static char kOutputArch = CompilerKit::kPefArch64000; + +constexpr auto k64x0IPAlignment = 0x1U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +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); + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief 64x0 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(AssemblerMain64x0) { + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-64x0-ver") == 0 || strcmp(argv[i], "-64x0-v") == 0) { + kStdOut + << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) " + "Amlal El Mahrouss\n"; + return 0; + } else if (strcmp(argv[i], "-64x0-h") == 0) { + kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: 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], "-64x0-binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "-64x0-verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "Assembler64x0: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "Assembler64x0: 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 << "Assembler64x0: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, 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, "CompilerKit"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "Assembler64x0: 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 << "Assembler64x0: At least one record is needed to write an object " + "file.\nAssembler64x0: Make one using `public_segment .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 << "Assembler64x0: 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 << "Assembler64x0: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAENullType; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAENullType, 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 << "Assembler64x0: 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 << "Assembler64x0: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "Assembler64x0: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "Assembler64x0: Exit failed.\n"; + + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string line) { + // extern_segment is the opposite of public_segment, it signals to the ld + // that we need this symbol. + if (CompilerKit::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment")); + + /// sanity check to avoid stupid linker errors. + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "power-as"); + throw std::runtime_error("invalid_extern_segment"); + } + + 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, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // public_segment is a special keyword used by Assembler64x0 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, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_public_segment_bin"); + } + + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); + + 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, kAENullType, 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_64x0(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, std::string file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "extern_segment") || + CompilerKit::find_word(line, "public_segment") || 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_64x0(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!Detail::algorithm::is_valid_64x0(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, "CompilerKit"); + 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 << "Assembler64x0: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "Assembler64x0: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "Assembler64x0: 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 << "Assembler64x0: 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, std::string file) { + if (CompilerKit::find_word(line, "public_segment ")) return true; + + for (auto& opcode64x0 : kOpcodes64x0) { + // strict check here + if (CompilerKit::find_word(line, opcode64x0.fName) && Detail::algorithm::is_valid_64x0(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 << "Assembler64x0: Register found: " << register_syntax << "\n"; + kStdOut << "Assembler64x0: 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 Assembler64x0 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("extern_segment ") != std::string::npos) { + Detail::print_error("invalid usage extern_segment 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("extern_segment") != std::string::npos) { + cpy_jump_label.erase(cpy_jump_label.find("extern_segment"), strlen("extern_segment")); + + if (name == "sta") { + Detail::print_error("extern_segment is not allowed on a sta operation.", file); + throw std::runtime_error("extern_segment_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 << "Assembler64x0: 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 += k64x0IPAlignment; + + break; + } + } + + return true; +} + +// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc new file mode 100644 index 0000000..0446a10 --- /dev/null +++ b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc @@ -0,0 +1,1206 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file AssemblerAMD64.cc +/// @author EL Mahrouss Amlal +/// @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... + +///////////////////////////////////////////////////////////////////////////////////////// + +#include "CompilerKit/Defines.h" +#ifndef __ASM_NEED_AMD64__ +#define __ASM_NEED_AMD64__ 1 +#endif + +#define kAssemblerPragmaSymStr "#" +#define kAssemblerPragmaSym '#' + +#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" + +static char kOutputArch = CompilerKit::kPefArchAMD64; + +constexpr auto kIPAlignement = 0x1U; + +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 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:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string line); + +#include + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief AMD64 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(AssemblerMainAMD64) { + //////////////// CPU OPCODES BEGIN //////////////// + + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + + 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], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) { + kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: " + "v1.10\nAssemblerAMD64: Copyright " + "(c) Amlal El Mahrouss\n"; + return 0; + } else if (strcmp(argv[i], "--amd64:h") == 0) { + kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: Copyright (c) 2024 " + "Amlal El Mahrouss\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], "--amd64:binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "--amd64:verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "AssemblerAMD64: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "AssemblerAMD64: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + std::string asm_input(argv[i]); + + for (auto& ext : kAsmFileExts) { + if (object_output.ends_with(ext)) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + break; + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + kStdOut << "AssemblerAMD64: Assembling: " << argv[i] << "\n"; + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "AssemblerAMD64: error: " << strerror(errno) << "\n"; + } + + return 1; + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + if (kVerbose) { + kStdOut << "Compiling: " + asm_input << "\n"; + kStdOut << "From: " + line << "\n"; + } + + 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, "CompilerKit"); + } + + try { + std::filesystem::remove(object_output); + } catch (...) { + } + + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: At least one record is needed to write an object " + "file.\nAssemblerAMD64: Make one using `public_segment .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 << "AssemblerAMD64: 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 << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAENullType; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAENullType, 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "AssemblerAMD64: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "AssemblerAMD64: Exit failed.\n"; + + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string line) { + // extern_segment is the opposite of public_segment, it signals to the ld + // that we need this symbol. + if (CompilerKit::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "power-as"); + throw std::runtime_error("invalid_extern_segment"); + } + + 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(kPefCode64) != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } else if (name.find(kPefData64) != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } else if (name.find(kPefZero64) != 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, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // public_segment is a special keyword used by AssemblerAMD64 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, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_public_segment_bin"); + } + + auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 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.", "CompilerKit"); + throw std::runtime_error("invalid_public_segment_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, kAENullType, 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_valid(char c) { + if ((isalpha(c) || isdigit(c)) || + ((c == ' ') || (c == '\t') || (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '*') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || (c == '_') || + (c == ':') || (c == '@') || (c == '.') || (c == '#') || (c == ';'))) + return false; + + return true; +} + +bool is_valid_amd64(std::string str) { + return std::find_if(str.begin(), str.end(), is_not_valid) == str.end(); +} +} // namespace Detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderAMD64::CheckLine(std::string line, std::string file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "extern_segment") || + CompilerKit::find_word(line, "public_segment") || + 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_amd64(line)) { + err_str = "Line contains non valid 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, "CompilerKit"); + 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 << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = + CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = + CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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 << "AssemblerAMD64: 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, "CompilerKit"); + 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 << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = + CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = + CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: 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, "CompilerKit"); + 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 << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = + CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = + CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: 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 << "AssemblerAMD64: 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, std::string file) { + if (CompilerKit::find_word(line, "public_segment ")) return true; + + struct RegMapAMD64 { + CompilerKit::STLString fName; + i64_byte_t fModRM; + }; + + std::vector kRegisterList{ + {.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}, + }; + + BOOL foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) { + // strict check here + if (CompilerKit::find_word(line, opcodeAMD64.fName) && + Detail::algorithm::is_valid_amd64(line)) { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (line.find(name) != std::string::npos) { + if (name == "mov" || name == "xor") { + 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: missing right operand.", "CompilerKit"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector currentRegList; + + for (auto& reg : kRegisterList) { + 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 (name == "mov") { + if (bits == 64 || bits == 32) { + if (!hasRBasedRegs && bits >= 32) { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + if (!onlyOneReg) kAppBytes.emplace_back(0x89); + } else if (bits == 16) { + if (hasRBasedRegs) { + Detail::print_error("Invalid combination of operands and registers.", + "CompilerKit"); + throw std::runtime_error("comb_op_reg"); + } else { + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + } + } else { + if (!hasRBasedRegs && bits >= 32) { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x31); + } + + if (onlyOneReg) { + auto num = GetNumber32(line, ","); + + for (auto& num_idx : num.number) { + if (num_idx == 0) num_idx = 0xFF; + } + + auto modrm = (0x3 << 6 | currentRegList[0].fModRM); + + kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number. + kAppBytes.emplace_back(modrm); + + if (name != "xor") { + kAppBytes.emplace_back(num.number[0]); + kAppBytes.emplace_back(num.number[1]); + kAppBytes.emplace_back(num.number[2]); + kAppBytes.emplace_back(num.number[3]); + } + + break; + } + + if (currentRegList[1].fName[0] == 'r' && currentRegList[0].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); + 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.", "CompilerKit"); + 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.", "CompilerKit"); + 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.", "CompilerKit"); + 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.", "CompilerKit"); + 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.", "CompilerKit"); + 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; + } + } + + 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 if (name == "syscall") { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + kAppBytes.emplace_back(0x05); + + break; + } else { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) { + if (foundInstruction) { + Detail::print_error("Syntax error: " + line, file); + 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 << "AssemblerAMD64: 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 += kIPAlignement; + + return true; +} + +// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc new file mode 100644 index 0000000..d290e24 --- /dev/null +++ b/dev/CompilerKit/src/Backend/AssemblerARM64.cc @@ -0,0 +1,587 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file AssemblerARM64.cxx +/// @author EL Mahrouss Amlal +/// @brief 'ACORN' Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that li will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __ASM_NEED_ARM64__ +#define __ASM_NEED_ARM64__ 1 +#endif + +#include +#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" + +constexpr auto cPowerIPAlignment = 0x1U; + +static Char kOutputArch = CompilerKit::kPefArchARM64; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +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); + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief POWER assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(AssemblerMainARM64) { + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { + kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: " << kDistVersion + << "\nAssemblerPower: " + "Copyright (c) " + "Amlal El Mahrouss\n"; + return 0; + } else if (strcmp(argv[i], "--h") == 0) { + kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " + "Amlal El Mahrouss\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 << "AssemblerPower: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "AssemblerPower: 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 << "AssemblerPower: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderARM64 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, "CompilerKit"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerARM64: 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 << "AssemblerARM64: At least one record is needed to write an object " + "file.\nAssemblerARM64: Make one using `public_segment .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 << "AssemblerARM64: 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 << "AssemblerARM64: Wrote symbol " << sym << " to file...\n"; + + undefined_sym.fKind = kAENullType; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; + + ++record_count; + + memset(undefined_sym.fPad, kAENullType, 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 << "AssemblerARM64: 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 << "AssemblerARM64: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "AssemblerARM64: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n"; + + return LIBCOMPILER_EXEC_ERROR; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string line) { + // extern_segment is the opposite of public_segment, it signals to the li + // that we need this symbol. + if (CompilerKit::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment"); + } + + 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, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // public_segment is a special keyword used by Assembler 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, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_public_segment_bin"); + } + + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); + + 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, kAENullType, 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_arm64(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::EncoderARM64::CheckLine(std::string line, std::string file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "extern_segment") || + CompilerKit::find_word(line, "public_segment") || 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_arm64(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!Detail::algorithm::is_valid_arm64(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; + } + } + } + + return err_str; +} + +bool CompilerKit::EncoderARM64::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, "CompilerKit"); + 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 << "AssemblerARM64: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerARM64: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerARM64: 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 << "AssemblerARM64: 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::EncoderARM64::WriteLine(std::string line, std::string file) { + if (CompilerKit::find_word(line, "public_segment")) return false; + + if (!Detail::algorithm::is_valid_arm64(line)) return false; + + return true; +} + +// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc new file mode 100644 index 0000000..a04a52b --- /dev/null +++ b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc @@ -0,0 +1,911 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file AssemblerPower.cxx +/// @author EL Mahrouss Amlal +/// @brief POWER Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that li will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __ASM_NEED_PPC__ +#define __ASM_NEED_PPC__ 1 +#endif + +#include +#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" + +constexpr auto cPowerIPAlignment = 0x4U; + +static Char kOutputArch = CompilerKit::kPefArchPowerPC; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginLabel; + +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); + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @brief POWER assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(AssemblerMainPower64) { + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { + kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion + << "\nAssemblerPower: " + "Copyright (c) " + "Amlal El Mahrouss\n"; + return 0; + } else if (strcmp(argv[i], "--h") == 0) { + kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " + "Amlal El Mahrouss\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 << "AssemblerPower: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "AssemblerPower: 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 << "AssemblerPower: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, 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, "CompilerKit"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerPower: 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 << "AssemblerPower: At least one record is needed to write an object " + "file.\nAssemblerPower: Make one using `public_segment .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 << "AssemblerPower: 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 << "AssemblerPower: Wrote symbol " << sym << " to file...\n"; + + undefined_sym.fKind = kAENullType; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; + + ++record_count; + + memset(undefined_sym.fPad, kAENullType, 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 << "AssemblerPower: 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 << "AssemblerPower: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) kStdOut << "AssemblerPower: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n"; + + return LIBCOMPILER_EXEC_ERROR; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string line) { + // extern_segment is the opposite of public_segment, it signals to the li + // that we need this symbol. + if (CompilerKit::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "CompilerKit"); + throw std::runtime_error("invalid_extern_segment"); + } + + 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, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // public_segment is a special keyword used by AssemblerPower 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, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); + throw std::runtime_error("invalid_public_segment_bin"); + } + + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); + + 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, kAENullType, 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_power64(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, std::string file) { + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "extern_segment") || + CompilerKit::find_word(line, "public_segment") || 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_power64(line)) { + err_str = "Line contains non alphanumeric characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!Detail::algorithm::is_valid_power64(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& opcode_risc : kOpcodesPowerPC) { + if (CompilerKit::find_word(line, opcode_risc.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(), opcode_risc.name); + it == filter_inst.cend()) { + if (CompilerKit::find_word(line, opcode_risc.name)) { + if (!isspace(line[line.find(opcode_risc.name) + strlen(opcode_risc.name)])) { + err_str += "\nMissing space between "; + err_str += opcode_risc.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, "CompilerKit"); + 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 << "AssemblerPower: 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, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerPower: 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, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerPower: 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 << "AssemblerPower: 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, std::string file) { + if (CompilerKit::find_word(line, "public_segment")) return false; + if (!Detail::algorithm::is_valid_power64(line)) return false; + + for (auto& opcode_risc : kOpcodesPowerPC) { + // strict check here + if (CompilerKit::find_word(line, opcode_risc.name)) { + std::string name(opcode_risc.name); + std::string jump_label, cpy_jump_label; + std::vector found_registers_index; + + // check funct7 type. + switch (opcode_risc.ops->type) { + default: { + NumberCast32 num(opcode_risc.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 = opcode_risc.name; + std::size_t register_sum = 0; + + NumberCast64 num(opcode_risc.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 << "AssemblerPower: Found register: " << register_syntax << "\n"; + kStdOut << "AssemblerPower: 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 (opcode_risc.ops->type != GREG) { + // remember! register to register! + if (found_some_count == 1) { + Detail::print_error( + "Unrecognized register found.\ntip: each AssemblerPower 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/dev/CompilerKit/src/BasicString.cc b/dev/CompilerKit/src/BasicString.cc new file mode 100644 index 0000000..ca257c0 --- /dev/null +++ b/dev/CompilerKit/src/BasicString.cc @@ -0,0 +1,207 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +/** + * @file BasicString.cc + * @author Amlal (amlal@el-mahrouss-logic.com) + * @brief C++ string manipulation API. + * @version 0.2 + * @date 2024-01-23 + * + * @copyright Copyright (c) Amlal El Mahrouss + * + */ + +#include + +namespace CompilerKit { +Char* BasicString::Data() { + return m_Data; +} + +const Char* BasicString::CData() const { + return m_Data; +} + +SizeType BasicString::Length() const { + return strlen(m_Data); +} + +bool BasicString::operator==(const BasicString& 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 BasicString::operator==(const Char* 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 BasicString::operator!=(const BasicString& 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 BasicString::operator!=(const Char* 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; +} + +BasicString StringBuilder::Construct(const Char* data) { + if (!data || *data == 0) return BasicString(0); + + BasicString 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); + + Char result[sizeof(int64_t)]; + + if (!to_str(result, sizeof(int64_t), 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 = 0; y_idx < res_len; ++y_idx) { + ret[y_idx] = result[result_cnt]; + ++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; +} + +BasicString& BasicString::operator+=(const Char* rhs) { + if (strlen(rhs) > this->m_Sz) { + throw std::runtime_error("out_of_bounds: BasicString"); + } + + memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); + this->m_Cur += strlen(rhs); + + return *this; +} + +BasicString& BasicString::operator+=(const BasicString& rhs) { + if (rhs.m_Cur > this->m_Sz) { + throw std::runtime_error("out_of_bounds: BasicString"); + } + + 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/dev/CompilerKit/src/CodeGen.cc b/dev/CompilerKit/src/CodeGen.cc new file mode 100644 index 0000000..e59001d --- /dev/null +++ b/dev/CompilerKit/src/CodeGen.cc @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +#include +#include + +/** + * @file CodeGen.cc + * @author Amlal El Mahrouss (amlal@nekernel.org) + * @brief CodeGen API of NeCTI + * @version 0.0.2 + * + * @copyright Copyright (c) 2024-2025 Amlal El Mahrouss + * + */ + +namespace CompilerKit { +///! @brief Compile for specific format (ELF, PEF, ZBIN) +Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { + if (sourceFile.length() < 1) return LIBCOMPILER_UNIMPLEMENTED; + + if (!fMounted) return LIBCOMPILER_UNIMPLEMENTED; + if (arch != fMounted->Arch()) return LIBCOMPILER_INVALID_ARCH; + + try { + return this->fMounted->CompileToFormat(sourceFile, arch); + } catch (std::exception& e) { + return LIBCOMPILER_EXEC_ERROR; + } +} + +///! @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 (fMounted) { + fMounted = nullptr; + } + + return mount_prev; +} +} // namespace CompilerKit diff --git a/dev/CompilerKit/src/Frontend.cc b/dev/CompilerKit/src/Frontend.cc new file mode 100644 index 0000000..37b36f7 --- /dev/null +++ b/dev/CompilerKit/src/Frontend.cc @@ -0,0 +1,51 @@ +/* ------------------------------------------- + + Copyright (C) 2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +#include + +namespace CompilerKit { +/// 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. +BOOL find_word(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::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. +SizeType find_word_range(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::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 STLString::npos; +} +} // namespace CompilerKit \ No newline at end of file diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc new file mode 100644 index 0000000..ae2939b --- /dev/null +++ b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc @@ -0,0 +1,1286 @@ +/* + * ======================================================== + * + * cc + * Copyright (C) 2024-2025 Amlal El Mahrouss, 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 CompilerKit. */ +/* (c) Amlal El Mahrouss */ + +/// @author EL Mahrouss Amlal (amlel) +/// @file 64x0-cc.cxx +/// @brief 64x0 C Compiler. + +/// TODO: support structures, else if, else, . and -> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kExitOK (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 Register map structure, used to keep track of each variable's registers. +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 std::string kIfFunction = ""; + +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; + +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 CompilerFrontend64x0 final : public CompilerKit::CompilerFrontendInterface { + public: + explicit CompilerFrontend64x0() = default; + ~CompilerFrontend64x0() override = default; + + LIBCOMPILER_COPY_DEFAULT(CompilerFrontend64x0); + + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + + const char* Language() override { return "64k C"; } +}; + +static CompilerFrontend64x0* kCompilerFrontend = 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. + +///////////////////////////////////////////////////////////////////////////////////////// + +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::string text_, std::string file) { + std::string text = 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 < text.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 = text.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 (text.find('(') != std::string::npos) { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (text[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 < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[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 += " extern_segment"; + 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 (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.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 = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; + syntaxLeaf.fUserValue += kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword public_segment .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 (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value in struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + 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 (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } else { + substr += "\tldw "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[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 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; + + if (text[text_index_2] == ';') { + break; + } + + if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { + if (first_encountered != 2) { + if (text[text_index] != '=' && + substr.find("public_segment .data64") == std::string::npos && !kInStruct) + substr += "public_segment .data64 "; + } + + ++first_encountered; + + continue; + } + + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } + + substr += ","; + continue; + } + + substr += text[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"), "extern_segment "); + + if (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .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 (text[text_index] == '=') break; + } + + // function handler. + + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; + + if (text[idx] == ' ') continue; + + if (text[idx] == ')') break; + } + + for (char substr_first_index : text) { + 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 : text) { + 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 += "public_segment .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(text); + } + + if (text[text_index] == '-' && text[text_index + 1] == '-') { + text = text.replace(text.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < text.size(); ++_text_i) { + if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "sub "; + syntaxLeaf.fUserValue += text; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (text[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 syntaxLeaf; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerFrontend64x0::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 extern_segments 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 LC_ASSEMBLY_INTERFACE { + public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + + UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArch64x0; } + + Int32 CompileToFormat(std::string src, Int32 arch) override { + if (kCompilerFrontend == 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 = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->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("extern_segment " + needle) != std::string::npos) { + std::string range = "extern_segment " + needle; + leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + 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 kExitOK; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) + +static void cc_print_help() { + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +LIBCOMPILER_MODULE(CompilerCLang64x0) { + ::signal(SIGSEGV, Detail::drvi_crash_handler); + + 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; + kCompilerFrontend = new CompilerFrontend64x0(); + + 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 kExitOK; + } + + 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 kExitOK; + } + + if (strcmp(argv[index], "--dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + 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) != kExitOK) return 1; + } + + return kExitOK; +} + +// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc new file mode 100644 index 0000000..764bec2 --- /dev/null +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -0,0 +1,1284 @@ +/* + * ======================================================== + * + * cc + * Copyright (C) 2024-2025 Amlal El Mahrouss, 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 CompilerKit. */ +/* (c) Amlal El Mahrouss */ + +/// @author EL Mahrouss Amlal (amlel) +/// @file ARM64-cc.cxx +/// @brief ARM64 C Compiler. + +/// TODO: support structures, else if, else, . and -> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kExitOK (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 Register map structure, used to keep track of each variable's registers. +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 std::string kIfFunction = ""; + +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; + +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 = 8; +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 CompilerFrontendARM64 final : public CompilerKit::CompilerFrontendInterface { + public: + explicit CompilerFrontendARM64() = default; + ~CompilerFrontendARM64() override = default; + + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendARM64); + + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + + const char* Language() override { return "64k C"; } +}; + +static CompilerFrontendARM64* kCompilerFrontend = 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. + +///////////////////////////////////////////////////////////////////////////////////////// + +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::string text, std::string file) { + 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 < text.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 = text.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 (text.find('(') != std::string::npos) { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (text[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 < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[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 += " extern_segment"; + 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 (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.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 = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; + syntaxLeaf.fUserValue += kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword public_segment .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 (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value in struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + 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 (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } else { + substr += "\tldw "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[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 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; + + if (text[text_index_2] == ';') { + break; + } + + if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { + if (first_encountered != 2) { + if (text[text_index] != '=' && + substr.find("public_segment .data64") == std::string::npos && !kInStruct) + substr += "public_segment .data64 "; + } + + ++first_encountered; + + continue; + } + + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } + + substr += ","; + continue; + } + + substr += text[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"), "extern_segment "); + + if (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .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 (text[text_index] == '=') break; + } + + // function handler. + + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; + + if (text[idx] == ' ') continue; + + if (text[idx] == ')') break; + } + + for (char substr_first_index : text) { + 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 : text) { + 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 += "public_segment .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(text); + } + + if (text[text_index] == '-' && text[text_index + 1] == '-') { + text = text.replace(text.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < text.size(); ++_text_i) { + if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "sub "; + syntaxLeaf.fUserValue += text; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (text[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 syntaxLeaf; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerFrontendARM64::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 extern_segments 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 LC_ASSEMBLY_INTERFACE { + public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + + UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAARCH64; } + + Int32 CompileToFormat(std::string src, Int32 arch) override { + if (kCompilerFrontend == 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: ARM64 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 = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->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("extern_segment " + needle) != std::string::npos) { + std::string range = "extern_segment " + needle; + leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + 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 kExitOK; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) + +static void cc_print_help() { + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kCExtension ".c" + +LIBCOMPILER_MODULE(CompilerCLangARM64) { + ::signal(SIGSEGV, Detail::drvi_crash_handler); + + 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::kArchAARCH64; + kCompilerFrontend = new CompilerFrontendARM64(); + + 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 kExitOK; + } + + 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 kExitOK; + } + + if (strcmp(argv[index], "--dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + 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], kCExtension) == nullptr) { + if (kState.fVerbose) { + Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; + } + + return kExitOK; +} + +// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc new file mode 100644 index 0000000..aaa2308 --- /dev/null +++ b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc @@ -0,0 +1,1303 @@ +/* + * ======================================================== + * + * CompilerPower64 + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define kExitOK 0 + +/// @author EL Mahrouss Amlal (amlal@nekernel.org) +/// @file cc.cxx +/// @brief POWER64 C Compiler. + +///////////////////// + +/// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +/// INTERNAL STRUCTURES 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 std::string kIfFunction = ""; + +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; + +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 CompilerFrontendPower64 final : public CompilerKit::CompilerFrontendInterface { + public: + explicit CompilerFrontendPower64() = default; + ~CompilerFrontendPower64() override = default; + + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendPower64); + + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + + const char* Language() override { return "POWER C"; } +}; + +static CompilerFrontendPower64* kCompilerFrontend = 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. + +///////////////////////////////////////////////////////////////////////////////////////// + +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::string text_, std::string file) { + std::string text = 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 < text.size(); ++text_index) { + auto syntax_leaf = 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 = text.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 (text.find('(') != std::string::npos) { + syntax_leaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } + + // return keyword handler + if (text[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 < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[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 += " extern_segment"; + value += tmp; + } + + syntax_leaf.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("extern_segment") != std::string::npos) + value.erase(value.find("extern_segment"), strlen("extern_segment")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) { + if (value.find(reg.fName) != std::string::npos) { + found = true; + syntax_leaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) syntax_leaf.fUserValue += "r0"; + } + + syntax_leaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + break; + } + } + + if (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.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 = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntax_leaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntax_leaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction + + " \ndword public_segment .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value inside a struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + 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 (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } else { + substr += "\tli "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[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 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; + + if (text[text_index_2] == ';') { + break; + } + + if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { + if (first_encountered != 2) { + if (text[text_index] != '=' && + substr.find("public_segment .data64") == std::string::npos && !kInStruct) + substr += "public_segment .data64 "; + } + + ++first_encountered; + + continue; + } + + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } + + substr += ","; + continue; + } + + substr += text[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"), "extern_segment "); + + if (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .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 (text[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}); + + syntax_leaf.fUserValue += "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } + + // function handler. + + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; + + if (text[idx] == ' ') continue; + + if (text[idx] == ')') break; + } + + for (char substr_first_index : text) { + 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 : text) { + if (_text_i == '\t' || _text_i == ' ') { + if (!type_crossed) { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') break; + + substr += _text_i; + } + + if (kInBraces) { + syntax_leaf.fUserValue = args; + syntax_leaf.fUserValue += substr; + + syntax_leaf.fUserValue += "\n\tblr\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + fnFound = true; + } else { + syntax_leaf.fUserValue.clear(); + + syntax_leaf.fUserValue += "public_segment .code64 "; + + syntax_leaf.fUserValue += substr; + syntax_leaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(text); + } + + if (text[text_index] == '-' && text[text_index + 1] == '-') { + text = text.replace(text.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < text.size(); ++_text_i) { + if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); + } + + syntax_leaf.fUserValue += "dec "; + syntax_leaf.fUserValue += text; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + break; + } + + if (text[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(syntax_leaf); + } + + syntax_leaf.fUserValue.clear(); + } + + auto syntax_leaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + syntax_leaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + return syntax_leaf; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerFrontendPower64::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 extern_segments 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 LC_ASSEMBLY_INTERFACE { + public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyMountpointCLang); + + UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchPowerPC; } + + Int32 CompileToFormat(std::string src, Int32 arch) override { + if (kCompilerFrontend == 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 = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->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("extern_segment ") != std::string::npos) { + std::string range = "extern_segment "; + 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 kExitOK; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include + +#define kPrintF printf +#define kSplashCxx() kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) + +static void cc_print_help() { + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +LIBCOMPILER_MODULE(CompilerCLangPowerPC) { + ::signal(SIGSEGV, Detail::drvi_crash_handler); + + 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; + kCompilerFrontend = new CompilerFrontendPower64(); + + 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 kExitOK; + } + + 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 kExitOK; + } + + if (strcmp(argv[index], "-dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + 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) != kExitOK) return 1; + } + + return kExitOK; +} + +// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc new file mode 100644 index 0000000..c38378a --- /dev/null +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -0,0 +1,892 @@ +/* + * ======================================================== + * + * C++ Compiler Driver + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 + +#define kPrintF printf + +#define kExitOK (EXIT_SUCCESS) +#define kExitNO (EXIT_FAILURE) + +#include +#include +#include +#include +#include + +/* NeKernel C++ Compiler Driver */ +/* This is part of the CompilerKit. */ +/* (c) Amlal El Mahrouss 2024-2025 */ + +/// @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 { + CompilerKit::STLString fName; + CompilerKit::STLString fReg; +}; + +/// \brief Offset based struct/class +struct CompilerStructMap final { + CompilerKit::STLString fName; + CompilerKit::STLString fReg; + std::vector> fOffsets; +}; + +/// \brief Compiler state structure. +struct CompilerState final { + std::vector fStackMapVector; + std::vector fStructMapVector; + CompilerKit::STLString fLastFile; + CompilerKit::STLString fLastError; +}; +} // namespace Detail + +static Detail::CompilerState kState; + +static Int32 kOnClassScope = 0; + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static Int32 kMachine = CompilerKit::AssemblyFactory::kArchAMD64; + +///////////////////////////////////////// + +// ARGUMENTS REGISTERS (R8, R15) + +///////////////////////////////////////// + +static std::vector kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static CompilerKit::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 CompilerFrontendCPlusPlusAMD64 final LC_COMPILER_FRONTEND { + public: + explicit CompilerFrontendCPlusPlusAMD64() = default; + ~CompilerFrontendCPlusPlusAMD64() override = default; + + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendCPlusPlusAMD64); + + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(const CompilerKit::STLString text, + CompilerKit::STLString file) override; + + const char* Language() override; +}; + +/// @internal compiler variables + +static CompilerFrontendCPlusPlusAMD64* kCompilerFrontend = nullptr; + +static std::vector kRegisterMap; + +static std::vector 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 kRegisterConventionCallList = { + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", +}; + +static std::size_t kFunctionEmbedLevel = 0UL; + +/// detail namespaces + +const char* CompilerFrontendCPlusPlusAMD64::Language() { + return "AMD64 C++"; +} + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector> kOriginMap; + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @name Compile +/// @brief Generate assembly from a C++ source. + +///////////////////////////////////////////////////////////////////////////////////////// + +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( + CompilerKit::STLString text, CompilerKit::STLString file) { + CompilerKit::SyntaxLeafList::SyntaxLeaf syntax_tree; + + if (text.length() < 1) return syntax_tree; + + std::size_t index = 0UL; + std::vector> keywords_list; + + for (auto& keyword : kKeywords) { + if (text.find(keyword.keyword_name) != std::string::npos) { + switch (keyword.keyword_kind) { + case CompilerKit::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 == CompilerKit::kKeywordKindVariableAssign) + continue; + + if (pos > 0 && text[pos - 1] == '-' && + keyword.keyword_kind == CompilerKit::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 == CompilerKit::kKeywordKindVariableAssign) + continue; + + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + } + } + + for (auto& keyword : keywords_list) { + if (text.find(keyword.first.keyword_name) == CompilerKit::STLString::npos) continue; + + switch (keyword.first.keyword_kind) { + case CompilerKit::KeywordKind::kKeywordKindClass: { + ++kOnClassScope; + break; + } + case CompilerKit::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 == CompilerKit::STLString::npos || + openParen == CompilerKit::STLString::npos || + closeParen == CompilerKit::STLString::npos || closeParen <= openParen) { + Detail::print_error("Malformed if expression: " + text, file); + break; + } + + auto expr = text.substr(openParen + 1, closeParen - openParen - 1); + + if (expr.find(">=") != CompilerKit::STLString::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; + + CompilerKit::STLString instr = "mov "; + + if (pairRight != valueOfVar) { + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += + instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + + kRegisterList[indexRight + 1] + "\n"; + + goto lc_done_iterarting_on_if; + } + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += + instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + + kRegisterList[indexRight + 1] + "\n"; + + break; + } + } + } + + lc_done_iterarting_on_if: + + CompilerKit::STLString symbol_name_fn = text; + + symbol_name_fn.erase(symbol_name_fn.find(keyword.first.keyword_name)); + + for (auto& ch : symbol_name_fn) { + if (ch == ' ') ch = '_'; + } + + syntax_tree.fUserValue += + "jge __OFFSET_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n"; + } + + break; + } + case CompilerKit::KeywordKind::kKeywordKindFunctionStart: { + for (auto& ch : text) { + if (isdigit(ch)) { + goto dont_accept; + } + } + + goto accept; + + dont_accept: + break; + + accept: + CompilerKit::STLString symbol_name_fn = text; + size_t indexFnName = 0; + + // this one is for the type. + for (auto& ch : text) { + ++indexFnName; + + if (ch == '\t') break; + if (ch == ' ') break; + } + + symbol_name_fn = text.substr(indexFnName); + + if (text.find("return ") != CompilerKit::STLString::npos) { + text.erase(0, text.find("return ")); + break; + } + + if (text.ends_with(";") && text.find("return") == CompilerKit::STLString::npos) + goto lc_write_assembly; + else if (text.size() <= indexFnName) + Detail::print_error("Invalid function name: " + symbol_name_fn, file); + + indexFnName = 0; + + for (auto& ch : symbol_name_fn) { + if (ch == ' ' || ch == '\t') { + if (symbol_name_fn[indexFnName - 1] != ')') + Detail::print_error("Invalid function name: " + symbol_name_fn, file); + } + + ++indexFnName; + } + + if (symbol_name_fn.find("(") != CompilerKit::STLString::npos) { + symbol_name_fn.erase(symbol_name_fn.find("(")); + } + + syntax_tree.fUserValue = "public_segment .code64 __LIBCOMPILER_" + symbol_name_fn + "\n"; + ++kFunctionEmbedLevel; + + kOriginMap.push_back({"__LIBCOMPILER_" + symbol_name_fn, kOrigin}); + + break; + + lc_write_assembly: + auto it = + std::find_if(kOriginMap.begin(), kOriginMap.end(), + [&symbol_name_fn](std::pair pair) -> bool { + return symbol_name_fn == pair.first; + }); + + if (it != kOriginMap.end()) { + std::stringstream ss; + ss << std::hex << it->second; + + syntax_tree.fUserValue = "jmp " + ss.str() + "\n"; + kOrigin += 1UL; + } + } + case CompilerKit::KeywordKind::kKeywordKindFunctionEnd: { + if (kOnClassScope) --kOnClassScope; + + if (text.ends_with(";")) break; + + --kFunctionEmbedLevel; + + if (kRegisterMap.size() > kRegisterList.size()) { + --kFunctionEmbedLevel; + } + + if (kFunctionEmbedLevel < 1) kRegisterMap.clear(); + + break; + } + case CompilerKit::KeywordKind::kKeywordKindEndInstr: + case CompilerKit::KeywordKind::kKeywordKindVariableInc: + case CompilerKit::KeywordKind::kKeywordKindVariableDec: + case CompilerKit::KeywordKind::kKeywordKindVariableAssign: { + CompilerKit::STLString valueOfVar = ""; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { + valueOfVar = text.substr(text.find("+=") + 2); + } else if (keyword.first.keyword_kind == + CompilerKit::KeywordKind::kKeywordKindVariableDec) { + valueOfVar = text.substr(text.find("-=") + 2); + } else if (keyword.first.keyword_kind == + CompilerKit::KeywordKind::kKeywordKindVariableAssign) { + valueOfVar = text.substr(text.find("=") + 1); + } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { + break; + } + + while (valueOfVar.find(";") != CompilerKit::STLString::npos && + keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindEndInstr) { + valueOfVar.erase(valueOfVar.find(";")); + } + + CompilerKit::STLString varName = text; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { + varName.erase(varName.find("+=")); + } else if (keyword.first.keyword_kind == + CompilerKit::KeywordKind::kKeywordKindVariableDec) { + varName.erase(varName.find("-=")); + } else if (keyword.first.keyword_kind == + CompilerKit::KeywordKind::kKeywordKindVariableAssign) { + varName.erase(varName.find("=")); + } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { + varName.erase(varName.find(";")); + } + + static Boolean typeFound = false; + + for (auto& keyword : kKeywords) { + if (keyword.keyword_kind == CompilerKit::kKeywordKindType) { + if (text.find(keyword.keyword_name) != CompilerKit::STLString::npos) { + if (text[text.find(keyword.keyword_name)] == ' ') { + typeFound = false; + continue; + } + + typeFound = true; + } + } + } + + CompilerKit::STLString instr = "mov "; + + std::vector newVars; + + if (typeFound && + keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableInc && + keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableDec) { + if (kRegisterMap.size() > kRegisterList.size()) { + ++kFunctionEmbedLevel; + } + + while (varName.find(" ") != CompilerKit::STLString::npos) { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != CompilerKit::STLString::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); + break; + } + + done: + for (auto& keyword : kKeywords) { + if (keyword.keyword_kind == CompilerKit::kKeywordKindType && + varName.find(keyword.keyword_name) != CompilerKit::STLString::npos) { + varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); + break; + } + } + + newVars.push_back(varName); + + break; + } + + kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); + + if (keyword.second > 0 && + kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindTypePtr) { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { + instr = "add "; + } else if (keyword.first.keyword_kind == + CompilerKit::KeywordKind::kKeywordKindVariableDec) { + instr = "sub "; + } + + CompilerKit::STLString varErrCpy = varName; + + while (varName.find(" ") != CompilerKit::STLString::npos) { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != CompilerKit::STLString::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(" ") != CompilerKit::STLString::npos) { + valueOfVar.erase(valueOfVar.find(" "), 1); + } + + while (valueOfVar.find("\t") != CompilerKit::STLString::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; + } + + newVars.push_back(varName); + break; + } + + if (syntax_tree.fUserValue.empty()) { + Detail::print_error("Variable not declared: " + varName, file); + } + + kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); + + break; + } + case CompilerKit::KeywordKind::kKeywordKindReturn: { + try { + auto pos = text.find("return") + strlen("return") + 1; + CompilerKit::STLString 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("(") != CompilerKit::STLString::npos) { + subText.erase(subText.find("(")); + + auto it = std::find_if( + kOriginMap.begin(), kOriginMap.end(), + [&subText](std::pair pair) -> bool { + return pair.first.find(subText) != CompilerKit::STLString::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; + } + } + } + + return syntax_tree; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C++ assembler class. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCPlusPlusInterfaceAMD64 final LC_ASSEMBLY_INTERFACE { + public: + explicit AssemblyCPlusPlusInterfaceAMD64() = default; + ~AssemblyCPlusPlusInterfaceAMD64() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyCPlusPlusInterfaceAMD64); + + UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAMD64; } + + Int32 CompileToFormat(CompilerKit::STLString src, Int32 arch) override { + if (kCompilerFrontend == nullptr) return kExitNO; + + CompilerKit::STLString dest = src; + dest += ".pp.masm"; + + std::ofstream out_fp(dest); + std::ifstream src_fp = std::ifstream(src + ".pp"); + + CompilerKit::STLString line_source; + + out_fp << "#bits 64\n"; + out_fp << "#org " << kOrigin << "\n\n"; + + while (std::getline(src_fp, line_source)) { + out_fp << kCompilerFrontend->Compile(line_source, src).fUserValue; + } + + return kExitOK; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExtListCxx \ + { ".cpp", ".cxx", ".cc", ".c++", ".cp" } + +LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { + Boolean skip = false; + + kKeywords.emplace_back("if", CompilerKit::kKeywordKindIf); + kKeywords.emplace_back("else", CompilerKit::kKeywordKindElse); + kKeywords.emplace_back("else if", CompilerKit::kKeywordKindElseIf); + + kKeywords.emplace_back("class", CompilerKit::kKeywordKindClass); + kKeywords.emplace_back("struct", CompilerKit::kKeywordKindClass); + kKeywords.emplace_back("namespace", CompilerKit::kKeywordKindNamespace); + kKeywords.emplace_back("typedef", CompilerKit::kKeywordKindTypedef); + kKeywords.emplace_back("using", CompilerKit::kKeywordKindTypedef); + kKeywords.emplace_back("{", CompilerKit::kKeywordKindBodyStart); + kKeywords.emplace_back("}", CompilerKit::kKeywordKindBodyEnd); + kKeywords.emplace_back("auto", CompilerKit::kKeywordKindVariable); + kKeywords.emplace_back("int", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("bool", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("unsigned", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("short", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("char", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("long", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("float", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("double", CompilerKit::kKeywordKindType); + kKeywords.emplace_back("void", CompilerKit::kKeywordKindType); + + kKeywords.emplace_back("auto*", CompilerKit::kKeywordKindVariablePtr); + kKeywords.emplace_back("int*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("bool*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("unsigned*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("short*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("char*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("long*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("float*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("double*", CompilerKit::kKeywordKindTypePtr); + kKeywords.emplace_back("void*", CompilerKit::kKeywordKindTypePtr); + + kKeywords.emplace_back("(", CompilerKit::kKeywordKindFunctionStart); + kKeywords.emplace_back(")", CompilerKit::kKeywordKindFunctionEnd); + kKeywords.emplace_back("=", CompilerKit::kKeywordKindVariableAssign); + kKeywords.emplace_back("+=", CompilerKit::kKeywordKindVariableInc); + kKeywords.emplace_back("-=", CompilerKit::kKeywordKindVariableDec); + kKeywords.emplace_back("const", CompilerKit::kKeywordKindConstant); + kKeywords.emplace_back("*", CompilerKit::kKeywordKindPtr); + kKeywords.emplace_back("->", CompilerKit::kKeywordKindPtrAccess); + kKeywords.emplace_back(".", CompilerKit::kKeywordKindAccess); + kKeywords.emplace_back(",", CompilerKit::kKeywordKindArgSeparator); + kKeywords.emplace_back(";", CompilerKit::kKeywordKindEndInstr); + kKeywords.emplace_back(":", CompilerKit::kKeywordKindSpecifier); + kKeywords.emplace_back("public:", CompilerKit::kKeywordKindSpecifier); + kKeywords.emplace_back("private:", CompilerKit::kKeywordKindSpecifier); + kKeywords.emplace_back("protected:", CompilerKit::kKeywordKindSpecifier); + kKeywords.emplace_back("final", CompilerKit::kKeywordKindSpecifier); + kKeywords.emplace_back("return", CompilerKit::kKeywordKindReturn); + kKeywords.emplace_back("/*", CompilerKit::kKeywordKindCommentMultiLineStart); + kKeywords.emplace_back("*/", CompilerKit::kKeywordKindCommentMultiLineEnd); + kKeywords.emplace_back("//", CompilerKit::kKeywordKindCommentInline); + kKeywords.emplace_back("==", CompilerKit::kKeywordKindEq); + kKeywords.emplace_back("!=", CompilerKit::kKeywordKindNotEq); + kKeywords.emplace_back(">=", CompilerKit::kKeywordKindGreaterEq); + kKeywords.emplace_back("<=", CompilerKit::kKeywordKindLessEq); + + kErrorLimit = 0; + + kCompilerFrontend = new CompilerFrontendCPlusPlusAMD64(); + kFactory.Mount(new AssemblyCPlusPlusInterfaceAMD64()); + + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + + for (auto index = 1UL; index < argc; ++index) { + if (!argv[index]) break; + + 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; + } + + CompilerKit::STLString err = "Unknown option: "; + err += argv[index]; + + Detail::print_error(err, "cxxdrv"); + + continue; + } + + CompilerKit::STLString argv_i = argv[index]; + + std::vector exts = kExtListCxx; + + for (CompilerKit::STLString ext : exts) { + if (argv_i.ends_with(ext)) { + if (kFactory.Compile(argv_i, kMachine) != kExitOK) { + return LIBCOMPILER_INVALID_DATA; + } + + break; + } + } + } + + kFactory.Unmount(); + + return LIBCOMPILER_SUCCESS; +} + +// +// Last rev 23-5-25 +// diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc new file mode 100644 index 0000000..3fde11b --- /dev/null +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -0,0 +1,672 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved + + @file DynamicLinker64PEF.cc + @brief: C++ 64-Bit PEF Linker for NeKernel.org + +------------------------------------------- */ + +/// @author EL Mahrouss Amlal (amlal@nekernel.org) +/// @brief NeKernel.org 64-bit PEF Linker. +/// Last Rev: Sat Apr 19 CET 2025 +/// @note Do not look up for anything with .code64/.data64/.zero64! +/// It will be loaded when the program loader will start the image. + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define kLinkerVersionStr \ + "NeKernel.org 64-Bit Linker (Preferred Executable Format) %s, (c) Amlal El Mahrouss " \ + "2024-2025 " \ + "all rights reserved.\n" + +#define MemoryCopy(DST, SRC, SZ) memcpy(DST, SRC, SZ) +#define StringCompare(DST, SRC) strcmp(DST, SRC) + +#define kPefNoCpu (0U) +#define kPefNoSubCpu (0U) + +#define kLinkerDefaultOrigin kPefBaseOrigin +#define kLinkerId (0x5046FF) +#define kLinkerAbiContainer "__PEFContainer:ABI:" + +#define kPrintF printf +#define kLinkerSplash() kConsoleOut << std::printf(kLinkerVersionStr, kDistVersion) + +/// @brief PEF stack size symbol. +#define kLinkerStackSizeSymbol "__PEFSizeOfReserveStack" + +#define kConsoleOut \ + (std::cout << "\e[0;31m" \ + << "ld64: " \ + << "\e[0;97m") + +enum { + kABITypeNull = 0, + kABITypeStart = 0x1010, /* The start of ABI list. */ + kABITypeNE = 0x5046, /* PF (NeKernel.org's PEF ABI) */ + kABITypeInvalid = 0xFFFF, +}; + +static CompilerKit::STLString kOutput = "a" kPefExt; +static Int32 kAbi = kABITypeNE; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = CompilerKit::kPefArchInvalid; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; + +/* ld64 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; + +/// @brief NE 64-bit Linker. +/// @note This linker is made for PEF executable, thus NE based OSes. +LIBCOMPILER_MODULE(DynamicLinker64PEF) { + bool is_executable = true; + + ::signal(SIGSEGV, Detail::drvi_crash_handler); + + /** + * @brief parse flags and trigger options. + */ + for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) { + if (StringCompare(argv[linker_arg], "-help") == 0) { + kLinkerSplash(); + + kConsoleOut << "-version: Show linker version.\n"; + kConsoleOut << "-help: Show linker help.\n"; + kConsoleOut << "-verbose: Enable linker trace.\n"; + kConsoleOut << "-dylib: Output as a Dynamic PEF.\n"; + kConsoleOut << "-fat: Output as a FAT PEF.\n"; + kConsoleOut << "-32k: Output as a 32x0 PEF.\n"; + kConsoleOut << "-64k: Output as a 64x0 PEF.\n"; + kConsoleOut << "-amd64: Output as a AMD64 PEF.\n"; + kConsoleOut << "-rv64: Output as a RISC-V PEF.\n"; + kConsoleOut << "-power64: Output as a POWER PEF.\n"; + kConsoleOut << "-arm64: Output as a ARM64 PEF.\n"; + kConsoleOut << "-output: Select the output file name.\n"; + + return LIBCOMPILER_SUCCESS; + } else if (StringCompare(argv[linker_arg], "-version") == 0) { + kLinkerSplash(); + + return LIBCOMPILER_SUCCESS; + } else if (StringCompare(argv[linker_arg], "-fat") == 0) { + kFatBinaryEnable = true; + + continue; + } else if (StringCompare(argv[linker_arg], "-64k") == 0) { + kArch = CompilerKit::kPefArch64000; + + continue; + } else if (StringCompare(argv[linker_arg], "-amd64") == 0) { + kArch = CompilerKit::kPefArchAMD64; + + continue; + } else if (StringCompare(argv[linker_arg], "-32k") == 0) { + kArch = CompilerKit::kPefArch32000; + + continue; + } else if (StringCompare(argv[linker_arg], "-power64") == 0) { + kArch = CompilerKit::kPefArchPowerPC; + + continue; + } else if (StringCompare(argv[linker_arg], "-riscv64") == 0) { + kArch = CompilerKit::kPefArchRISCV; + + continue; + } else if (StringCompare(argv[linker_arg], "-arm64") == 0) { + kArch = CompilerKit::kPefArchARM64; + + continue; + } else if (StringCompare(argv[linker_arg], "-verbose") == 0) { + kVerbose = true; + + continue; + } else if (StringCompare(argv[linker_arg], "-dylib") == 0) { + if (kOutput.empty()) { + continue; + } + + if (kOutput.find(kPefExt) != CompilerKit::STLString::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } else if (StringCompare(argv[linker_arg], "-output") == 0) { + if ((linker_arg + 1) > argc) continue; + + kOutput = argv[linker_arg + 1]; + ++linker_arg; + + continue; + } else { + if (argv[linker_arg][0] == '-') { + kConsoleOut << "unknown flag: " << argv[linker_arg] << "\n"; + return EXIT_FAILURE; + } + + kObjectList.emplace_back(argv[linker_arg]); + + continue; + } + } + + if (kOutput.empty()) { + kConsoleOut << "no output filename set." << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } else if (kObjectList.empty()) { + kConsoleOut << "no input files." << std::endl; + return LIBCOMPILER_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. + kConsoleOut << "no such file: " << obj << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } + } + } + + // PEF expects a valid target architecture when outputing a binary. + if (kArch == CompilerKit::kPefArchInvalid) { + kConsoleOut << "no target architecture set, can't continue." << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } + + CompilerKit::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = is_executable ? CompilerKit::kPefKindExec : CompilerKit::kPefKindDylib; + pef_container.SubCpu = kSubArch; + 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]; + 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); + pef_container.Checksum = 0UL; + + std::ofstream output_fc(kOutput, std::ofstream::binary); + + if (output_fc.bad()) { + if (kVerbose) { + kConsoleOut << "error: " << strerror(errno) << "\n"; + } + + return LIBCOMPILER_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector command_headers; + CompilerKit::Utils::AEReadableProtocol reader_protocol{}; + + for (const auto& objectFile : kObjectList) { + if (!std::filesystem::exists(objectFile)) continue; + + CompilerKit::AEHeader hdr{}; + + reader_protocol._Fp = std::ifstream(objectFile, std::ifstream::binary); + reader_protocol._Fp >> hdr; + + if (hdr.fMagic[0] == kAEMag0 && hdr.fMagic[1] == kAEMag1 && + hdr.fSize == sizeof(CompilerKit::AEHeader)) { + if (hdr.fArch != kArch) { + if (kVerbose) kConsoleOut << "is this a FAT binary? : "; + + if (!kFatBinaryEnable) { + if (kVerbose) kConsoleOut << "not a FAT binary.\n"; + + kConsoleOut << "object " << objectFile + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + return LIBCOMPILER_FAT_ERROR; + } else { + if (kVerbose) { + kConsoleOut << "Architecture matches what we expect.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= hdr.fArch; + std::size_t cnt = hdr.fCount; + + if (kVerbose) kConsoleOut << "header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + + if (!raw_ae_records) { + if (kVerbose) kConsoleOut << "allocation failed for records of count: " << cnt << "\n"; + } + + std::memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); + + auto* ae_records = reader_protocol.Read(raw_ae_records, cnt); + + size_t org = kLinkerDefaultOrigin; + + for (size_t ae_record_index = 0; ae_record_index < cnt; ++ae_record_index) { + CompilerKit::PEFCommandHeader command_header{0}; + std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; + + MemoryCopy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); + + CompilerKit::STLString cmd_hdr_name(command_header.Name); + + // check this header if it's any valid. + if (cmd_hdr_name.find(kPefCode64) == CompilerKit::STLString::npos && + cmd_hdr_name.find(kPefData64) == CompilerKit::STLString::npos && + cmd_hdr_name.find(kPefZero64) == CompilerKit::STLString::npos) { + if (cmd_hdr_name.find(kPefStart) == CompilerKit::STLString::npos && + *command_header.Name == 0) { + if (cmd_hdr_name.find(kLdDefineSymbol) != CompilerKit::STLString::npos) { + goto ld_mark_header; + } else { + continue; + } + } + } + + if (cmd_hdr_name.find(kPefStart) != CompilerKit::STLString::npos && + cmd_hdr_name.find(kPefCode64) != CompilerKit::STLString::npos) { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offset_of_obj; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = hdr.fArch; + command_header.VMAddress = org; /// TODO: + command_header.SubCpu = hdr.fSubArch; + + org += command_header.Size; + + if (kVerbose) { + kConsoleOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; + + kConsoleOut << "Offset: " << command_header.Offset << "\n"; + } + + command_headers.emplace_back(command_header); + } + + delete[] raw_ae_records; + raw_ae_records = nullptr; + + std::vector bytes; + bytes.resize(hdr.fCodeSize); + + reader_protocol._Fp.seekg(std::streamsize(hdr.fStartCode)); + reader_protocol._Fp.read(bytes.data(), std::streamsize(hdr.fCodeSize)); + + kObjectBytes.push_back({.mBlob = bytes, .mOffset = hdr.fStartCode}); + + // Blob was written, close fp. + + reader_protocol._Fp.close(); + + continue; + } + + kConsoleOut << "not an object container: " << objectFile << std::endl; + + // don't continue, it is a fatal error. + return LIBCOMPILER_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + output_fc << pef_container; + + if (kVerbose) { + kConsoleOut << "wrote container to: " << output_fc.tellp() << ".\n"; + } + + output_fc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector not_found; + std::vector symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& command_hdr : command_headers) { + // check if this symbol needs to be resolved. + if (CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) != + CompilerKit::STLString::npos && + CompilerKit::STLString(command_hdr.Name).find(kLdDynamicSym) == + CompilerKit::STLString::npos) { + if (kVerbose) kConsoleOut << "Found undefined symbol: " << command_hdr.Name << "\n"; + + if (auto it = std::find(not_found.begin(), not_found.end(), + CompilerKit::STLString(command_hdr.Name)); + it == not_found.end()) { + not_found.emplace_back(command_hdr.Name); + } + } + + symbols.emplace_back(command_hdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < command_headers.size(); ++not_found_idx) { + if (const auto it = std::find(not_found.begin(), not_found.end(), + CompilerKit::STLString(command_headers[not_found_idx].Name)); + it != not_found.end()) { + CompilerKit::STLString symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == CompilerKit::STLString::npos) continue; + + // erase the lookup prefix. + symbol_imp.erase(0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != CompilerKit::STLString::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& command_hdr : command_headers) { + if (CompilerKit::STLString(command_hdr.Name).find(symbol_imp) != + CompilerKit::STLString::npos && + CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) == + CompilerKit::STLString::npos) { + CompilerKit::STLString undefined_symbol = command_hdr.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) kConsoleOut << "Found symbol: " << command_hdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) { + if (kVerbose) + kConsoleOut << "Undefined entrypoint: " << kPefStart + << ", you may have forget to link " + "against the C++ runtime library.\n"; + + kConsoleOut << "Undefined entrypoint " << kPefStart << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + CompilerKit::PEFCommandHeader date_cmd_hdr{}; + + time_t timestamp = time(nullptr); + + CompilerKit::STLString timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size()); + + date_cmd_hdr.Flags = 0; + date_cmd_hdr.Kind = CompilerKit::kPefZero; + date_cmd_hdr.Offset = output_fc.tellp(); + date_cmd_hdr.Size = timeStampStr.size(); + + command_headers.push_back(date_cmd_hdr); + + CompilerKit::PEFCommandHeader abi_cmd_hdr{}; + + CompilerKit::STLString abi = kLinkerAbiContainer; + + switch (kArch) { + case CompilerKit::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case CompilerKit::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case CompilerKit::kPefArch32000: + case CompilerKit::kPefArch64000: { + abi += "_NEP"; + break; + } + default: { + abi += "_IDK"; + break; + } + } + + MemoryCopy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); + + abi_cmd_hdr.Size = abi.size(); + abi_cmd_hdr.Offset = output_fc.tellp(); + abi_cmd_hdr.Flags = 0; + abi_cmd_hdr.Kind = CompilerKit::kPefLinkerID; + + command_headers.push_back(abi_cmd_hdr); + + CompilerKit::PEFCommandHeader stack_cmd_hdr{0}; + + stack_cmd_hdr.Cpu = kArch; + stack_cmd_hdr.Flags = 0; + stack_cmd_hdr.Size = sizeof(uintptr_t); + stack_cmd_hdr.Offset = 0; + + MemoryCopy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); + + command_headers.push_back(stack_cmd_hdr); + + CompilerKit::PEFCommandHeader uuid_cmd_hdr{}; + + 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); + + MemoryCopy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + MemoryCopy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); + + uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name); + uuid_cmd_hdr.Offset = output_fc.tellp(); + uuid_cmd_hdr.Flags = CompilerKit::kPefLinkerID; + uuid_cmd_hdr.Kind = CompilerKit::kPefZero; + + command_headers.push_back(uuid_cmd_hdr); + + // prepare a symbol vector. + std::vector undef_symbols; + std::vector dupl_symbols; + std::vector resolve_symbols; + + constexpr Int32 kPaddingOffset = 16; + + size_t previous_offset = + (command_headers.size() * sizeof(CompilerKit::PEFCommandHeader)) + kPaddingOffset; + + CompilerKit::PEFCommandHeader end_exec_hdr; + + end_exec_hdr.Offset = output_fc.tellp(); + end_exec_hdr.Flags = CompilerKit::kPefLinkerID; + end_exec_hdr.Kind = CompilerKit::kPefZero; + + MemoryCopy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); + + end_exec_hdr.Size = strlen(end_exec_hdr.Name); + + command_headers.push_back(end_exec_hdr); + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; commandHeaderIndex < command_headers.size(); + ++commandHeaderIndex) { + if (CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDefineSymbol) != + CompilerKit::STLString::npos && + CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDynamicSym) == + CompilerKit::STLString::npos) { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + CompilerKit::STLString symbol_name = command_headers[commandHeaderIndex].Name; + + if (!symbol_name.empty()) { + undef_symbols.emplace_back(symbol_name); + } + + command_headers[commandHeaderIndex].Offset += previous_offset; + previous_offset += command_headers[commandHeaderIndex].Size; + + CompilerKit::STLString name = command_headers[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) != CompilerKit::STLString::npos && + name.find(kPefCode64) != CompilerKit::STLString::npos) { + pef_container.Start = command_headers[commandHeaderIndex].Offset; + auto tellCurPos = output_fc.tellp(); + + output_fc.seekp(0); + output_fc << pef_container; + + output_fc.seekp(tellCurPos); + } + + if (kVerbose) { + kConsoleOut << "Command name: " << name << "\n"; + kConsoleOut << "VMAddress of command content: " << command_headers[commandHeaderIndex].Offset + << "\n"; + } + + output_fc << command_headers[commandHeaderIndex]; + + for (size_t sub_command_header_index = 0UL; sub_command_header_index < command_headers.size(); + ++sub_command_header_index) { + if (sub_command_header_index == commandHeaderIndex) continue; + + if (CompilerKit::STLString(command_headers[sub_command_header_index].Name) + .find(kLdDefineSymbol) != CompilerKit::STLString::npos && + CompilerKit::STLString(command_headers[sub_command_header_index].Name) + .find(kLdDynamicSym) == CompilerKit::STLString::npos) { + if (kVerbose) { + kConsoleOut << "Ignoring :UndefinedSymbol: headers...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& command_hdr = command_headers[sub_command_header_index]; + + if (command_hdr.Name == CompilerKit::STLString(command_headers[commandHeaderIndex].Name)) { + if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(), command_hdr.Name) == + dupl_symbols.cend()) { + dupl_symbols.emplace_back(command_hdr.Name); + } + + if (kVerbose) kConsoleOut << "Found duplicate symbols of: " << command_hdr.Name << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!dupl_symbols.empty()) { + for (auto& symbol : dupl_symbols) { + kConsoleOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; + } + + return LIBCOMPILER_EXEC_ERROR; + } + + // step 2.5: write program bytes. + + for (auto& struct_of_blob : kObjectBytes) { + output_fc.write(struct_of_blob.mBlob.data(), struct_of_blob.mBlob.size()); + } + + if (kVerbose) { + kConsoleOut << "Wrote contents of: " << kOutput << "\n"; + } + + // step 3: check if we have those symbols + + std::vector unreferenced_symbols; + + for (auto& command_hdr : command_headers) { + if (auto it = + std::find(not_found.begin(), not_found.end(), CompilerKit::STLString(command_hdr.Name)); + it != not_found.end()) { + unreferenced_symbols.emplace_back(command_hdr.Name); + } + } + + if (!unreferenced_symbols.empty()) { + for (auto& unreferenced_symbol : unreferenced_symbols) { + kConsoleOut << "Undefined symbol " << unreferenced_symbol << "\n"; + } + + return LIBCOMPILER_EXEC_ERROR; + } + + if ((!kStartFound || kDuplicateSymbols) && + (std::filesystem::exists(kOutput) || !unreferenced_symbols.empty())) { + if (kVerbose) { + kConsoleOut << "File: " << kOutput << ", is corrupt, removing file...\n"; + } + + return LIBCOMPILER_EXEC_ERROR; + } + + return LIBCOMPILER_SUCCESS; +} + +// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc new file mode 100644 index 0000000..12a69c8 --- /dev/null +++ b/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc @@ -0,0 +1,893 @@ +/* + * ======================================================== + * + * C++ Preprocessor Driver + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define kMacroPrefix '#' + +/// @author EL Mahrouss Amlal (amlel) +/// @file bpp.cxx +/// @brief Preprocessor. + +typedef Int32 (*bpp_parser_fn_t)(CompilerKit::STLString& line, std::ifstream& hdr_file, + std::ofstream& pp_out); + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Preprocessor internal types. + +///////////////////////////////////////////////////////////////////////////////////////// + +namespace Detail { +enum { + kInvalid = 0, + kEqual = 100, + kGreaterEqThan, + kLesserEqThan, + kGreaterThan, + kLesserThan, + kNotEqual, + kCount = 6, +}; + +struct bpp_macro_condition final { + int32_t fType; + CompilerKit::STLString fTypeName; + + void Print() { + std::cout << "type: " << fType << "\n"; + std::cout << "type_name: " << fTypeName << "\n"; + } +}; + +struct bpp_macro final { + std::vector fArgs; + CompilerKit::STLString fName; + CompilerKit::STLString fValue; + + void Print() { + std::cout << "name: " << fName << "\n"; + std::cout << "value: " << fValue << "\n"; + + for (auto& arg : fArgs) { + std::cout << "arg: " << arg << "\n"; + } + } +}; +} // namespace Detail + +static std::vector kFiles; +static std::vector kMacros; +static std::vector kIncludes; + +static CompilerKit::STLString kWorkingDir = ""; + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_if_condition +// @brief parse #if condition + +///////////////////////////////////////////////////////////////////////////////////////// + +int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, + bool& inactive_code, bool& defined, + CompilerKit::STLString& macro_str) { + if (cond.fType == Detail::kEqual) { + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { + if (macro.fValue == "0") { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + } else if (cond.fType == Detail::kNotEqual) { + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fName) != CompilerKit::STLString::npos) { + if (substr_macro.find(macro.fValue) != CompilerKit::STLString::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()); + + CompilerKit::STLString number; + + for (auto& macro_num : kMacros) { + if (substr_macro.find(macro_num.fName) != CompilerKit::STLString::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 == Detail::kGreaterThan) { + if (lhs < rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::kGreaterEqThan) { + if (lhs <= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::kLesserEqThan) { + if (lhs >= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::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) { + CompilerKit::STLString hdr_line; + CompilerKit::STLString line_after_include; + + bool inactive_code = false; + bool defined = false; + + try { + while (std::getline(hdr_file, hdr_line)) { + if (inactive_code) { + if (hdr_line.find("#endif") == CompilerKit::STLString::npos) { + continue; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("#endif") != CompilerKit::STLString::npos) { + inactive_code = false; + } + } + + if (hdr_line.find("*/") != CompilerKit::STLString::npos) { + hdr_line.erase(hdr_line.find("*/"), strlen("*/")); + } + + if (hdr_line.find("/*") != CompilerKit::STLString::npos) { + inactive_code = true; + + // get rid of comment. + hdr_line.erase(hdr_line.find("/*")); + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != CompilerKit::STLString::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)) { + if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != + CompilerKit::STLString::npos) { + if (!macro.fArgs.empty()) { + CompilerKit::STLString symbol_val = macro.fValue; + std::vector args; + + size_t x_arg_indx = 0; + + CompilerKit::STLString line_after_define = hdr_line; + CompilerKit::STLString str_arg; + + if (line_after_define.find("(") != CompilerKit::STLString::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ' ' || subc == '\t') continue; + + if (subc == ',' || subc == ')') { + if (str_arg.empty()) continue; + + args.push_back(str_arg); + + str_arg.clear(); + + continue; + } + + str_arg.push_back(subc); + } + } + + for (auto arg : macro.fArgs) { + if (symbol_val.find(macro.fArgs[x_arg_indx]) != CompilerKit::STLString::npos) { + symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), + macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); + ++x_arg_indx; + } else { + throw std::runtime_error("cppdrv: Internal error."); + } + } + + auto len = macro.fName.size(); + len += symbol_val.size(); + len += 2; // ( and ) + + hdr_line.erase(hdr_line.find(")"), 1); + + hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), + len, symbol_val); + } else { + auto value = macro.fValue; + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), value); + } + } + } + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("define ") != CompilerKit::STLString::npos) { + auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); + + CompilerKit::STLString macro_value; + CompilerKit::STLString 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; + } + + CompilerKit::STLString str; + + if (line_after_define.find("(") != CompilerKit::STLString::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ',' || subc == ')') { + if (str.empty()) continue; + + args.push_back(str); + + str.clear(); + + continue; + } + + str.push_back(subc); + } + } + + Detail::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; + } + + pp_out << hdr_line << std::endl; + + continue; + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifndef") != CompilerKit::STLString::npos) { + auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { + found = true; + break; + } + } + + if (found) { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("else") != CompilerKit::STLString::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") != CompilerKit::STLString::npos) { + auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { + defined = true; + inactive_code = false; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("if") != CompilerKit::STLString::npos) { + inactive_code = true; + + std::vector bpp_macro_condition_list = { + { + .fType = Detail::kEqual, + .fTypeName = "==", + }, + { + .fType = Detail::kNotEqual, + .fTypeName = "!=", + }, + { + .fType = Detail::kLesserThan, + .fTypeName = "<", + }, + { + .fType = Detail::kGreaterThan, + .fTypeName = ">", + }, + { + .fType = Detail::kLesserEqThan, + .fTypeName = "<=", + }, + { + .fType = Detail::kGreaterEqThan, + .fTypeName = ">=", + }, + }; + + int32_t good_to_go = 0; + + for (auto& macro_condition : bpp_macro_condition_list) { + if (hdr_line.find(macro_condition.fTypeName) != CompilerKit::STLString::npos) { + for (auto& found_macro : kMacros) { + if (hdr_line.find(found_macro.fName) != CompilerKit::STLString::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); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (macro_ref.fName.find(macro) != CompilerKit::STLString::npos && + macro_ref.fValue == "1") { + inactive_code = false; + defined = true; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("warning") != CompilerKit::STLString::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); + CompilerKit::STLString message; + + for (auto& ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + std::cout << "warn: " << message << std::endl; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("error") != CompilerKit::STLString::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); + CompilerKit::STLString 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("include ") != CompilerKit::STLString::npos) { + line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); + + kIncludeFile: + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); + + if (it != kAllIncludes.cend()) { + continue; + } + + CompilerKit::STLString 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 == '\"') { + not_local = false; + enable = true; + continue; + } + + if (enable) { + path += ch; + } + } + + if (not_local) { + bool open = false; + + if (path.ends_with('>')) { + path.erase(path.find('>')); + } + + if (path.ends_with('"')) { + path.erase(path.find('"')); + } + + for (auto& include : kIncludes) { + CompilerKit::STLString 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("cppdrv: no such include file: " + path); + } + } else { + std::ifstream header(path); + + if (!header.is_open()) throw std::runtime_error("cppdrv: no such include file: " + path); + + bpp_parse_file(header, pp_out); + } + } else { + std::cerr << ("cppdrv: unknown pre-processor directive, " + hdr_line) << "\n"; + continue; + } + } + } catch (std::out_of_range& oor) { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief main entrypoint of app. + +///////////////////////////////////////////////////////////////////////////////////////// + +LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { + try { + bool skip = false; + bool double_skip = false; + + Detail::bpp_macro macro_1; + + macro_1.fName = "__true"; + macro_1.fValue = "1"; + + kMacros.push_back(macro_1); + + Detail::bpp_macro macro_unreachable; + + macro_unreachable.fName = "__unreachable"; + macro_unreachable.fValue = "__libcompiler_unreachable"; + + kMacros.push_back(macro_unreachable); + + Detail::bpp_macro macro_unused; + + macro_unreachable.fName = "__unused"; + macro_unreachable.fValue = "__libcompiler_unused"; + + kMacros.push_back(macro_unused); + + Detail::bpp_macro macro_0; + + macro_0.fName = "__false"; + macro_0.fValue = "0"; + + kMacros.push_back(macro_0); + + Detail::bpp_macro macro_zka; + + macro_zka.fName = "__LIBCOMPILER__"; + macro_zka.fValue = "1"; + + kMacros.push_back(macro_zka); + + Detail::bpp_macro macro_cxx; + + macro_cxx.fName = "__cplusplus"; + macro_cxx.fValue = "202302L"; + + kMacros.push_back(macro_cxx); + + Detail::bpp_macro macro_size_t; + macro_size_t.fName = "__SIZE_TYPE__"; + macro_size_t.fValue = "unsigned long long int"; + + kMacros.push_back(macro_size_t); + + macro_size_t.fName = "__UINT32_TYPE__"; + macro_size_t.fValue = "unsigned int"; + + kMacros.push_back(macro_size_t); + + macro_size_t.fName = "__UINTPTR_TYPE__"; + macro_size_t.fValue = "unsigned long long int"; + + kMacros.push_back(macro_size_t); + + 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], "-cpp-ver") == 0) { + printf("%s\n", + "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " + "reserved."); + + return LIBCOMPILER_SUCCESS; + } + + if (strcmp(argv[index], "-cpp-help") == 0) { + printf("%s\n", + "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " + "reserved."); + printf("%s\n", "-cpp-working-dir : set directory to working path."); + printf("%s\n", "-cpp-include-dir : add directory to include path."); + printf("%s\n", "-cpp-def : define a macro."); + printf("%s\n", "-cpp-ver: print the version."); + printf("%s\n", "-cpp-help: show help (this current command)."); + + return LIBCOMPILER_SUCCESS; + } + + if (strcmp(argv[index], "-cpp-include-dir") == 0) { + CompilerKit::STLString inc = argv[index + 1]; + + skip = true; + + kIncludes.push_back(inc); + } + + if (strcmp(argv[index], "-cpp-working-dir") == 0) { + CompilerKit::STLString inc = argv[index + 1]; + skip = true; + kWorkingDir = inc; + } + + if (strcmp(argv[index], "-cpp-def") == 0 && argv[index + 1] != nullptr && + argv[index + 2] != nullptr) { + CompilerKit::STLString macro_key = argv[index + 1]; + + CompilerKit::STLString 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 += "\""; + + Detail::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 LIBCOMPILER_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 LIBCOMPILER_SUCCESS; + } catch (const std::runtime_error& e) { + std::cout << e.what() << '\n'; + } + + return LIBCOMPILER_EXEC_ERROR; +} + +// Last rev 8-1-24 -- cgit v1.2.3 From 215425527dcbba9beff6ee2b2d862edb2cf2e7e9 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Thu, 31 Jul 2025 00:32:56 +0100 Subject: feat: fix contact email in `BasicString.cc` Signed-off-by: Amlal El Mahrouss --- dev/CompilerKit/AE.h | 4 ++-- dev/CompilerKit/src/BasicString.cc | 2 +- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 3 ++- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 14 +++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/AE.h b/dev/CompilerKit/AE.h index 3194417..1115e0a 100644 --- a/dev/CompilerKit/AE.h +++ b/dev/CompilerKit/AE.h @@ -91,7 +91,7 @@ namespace CompilerKit::Utils { */ class AEReadableProtocol final { public: - std::ifstream _Fp; + std::ifstream file_pointer_; public: explicit AEReadableProtocol() = default; @@ -123,7 +123,7 @@ class AEReadableProtocol final { */ template TypeClass* Read_(char* raw, std::size_t sz) { - _Fp.read(raw, std::streamsize(sz)); + file_pointer_.read(raw, std::streamsize(sz)); return reinterpret_cast(raw); } }; diff --git a/dev/CompilerKit/src/BasicString.cc b/dev/CompilerKit/src/BasicString.cc index ca257c0..b9aaa3f 100644 --- a/dev/CompilerKit/src/BasicString.cc +++ b/dev/CompilerKit/src/BasicString.cc @@ -9,7 +9,7 @@ /** * @file BasicString.cc - * @author Amlal (amlal@el-mahrouss-logic.com) + * @author Amlal (amlal@nekernel.org) * @brief C++ string manipulation API. * @version 0.2 * @date 2024-01-23 diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc index 764bec2..0cd08d0 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -1,7 +1,7 @@ /* * ======================================================== * - * cc + * CCompilerARM64 * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. * * ======================================================== @@ -14,6 +14,7 @@ #include #include #include + #include #include #include diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 3fde11b..b2906a6 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -3,7 +3,7 @@ Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved @file DynamicLinker64PEF.cc - @brief: C++ 64-Bit PEF Linker for NeKernel.org + @brief: C++ 64-Bit PEF Linker for NeKernel.org's NeKernel ------------------------------------------- */ @@ -24,7 +24,7 @@ #include #define kLinkerVersionStr \ - "NeKernel.org 64-Bit Linker (Preferred Executable Format) %s, (c) Amlal El Mahrouss " \ + "NeKernel.org 64-Bit Linker (Preferred Executable Format) %s, (c) Amlal El Mahrouss, and NeKernel Contributors " \ "2024-2025 " \ "all rights reserved.\n" @@ -234,8 +234,8 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { CompilerKit::AEHeader hdr{}; - reader_protocol._Fp = std::ifstream(objectFile, std::ifstream::binary); - reader_protocol._Fp >> hdr; + reader_protocol.file_pointer_ = std::ifstream(objectFile, std::ifstream::binary); + reader_protocol.file_pointer_ >> hdr; if (hdr.fMagic[0] == kAEMag0 && hdr.fMagic[1] == kAEMag1 && hdr.fSize == sizeof(CompilerKit::AEHeader)) { @@ -330,14 +330,14 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { std::vector bytes; bytes.resize(hdr.fCodeSize); - reader_protocol._Fp.seekg(std::streamsize(hdr.fStartCode)); - reader_protocol._Fp.read(bytes.data(), std::streamsize(hdr.fCodeSize)); + reader_protocol.file_pointer_.seekg(std::streamsize(hdr.fStartCode)); + reader_protocol.file_pointer_.read(bytes.data(), std::streamsize(hdr.fCodeSize)); kObjectBytes.push_back({.mBlob = bytes, .mOffset = hdr.fStartCode}); // Blob was written, close fp. - reader_protocol._Fp.close(); + reader_protocol.file_pointer_.close(); continue; } -- cgit v1.2.3 From 71f3aa93062d7eef5a3e4d4aea81e9b6dc77d427 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Mon, 4 Aug 2025 14:51:09 +0100 Subject: assember: fix: remove redundant include. Signed-off-by: Amlal El Mahrouss --- dev/CompilerKit/src/Backend/AssemblerAMD64.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc index 0446a10..6542d6e 100644 --- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc @@ -21,7 +21,6 @@ ///////////////////////////////////////////////////////////////////////////////////////// -#include "CompilerKit/Defines.h" #ifndef __ASM_NEED_AMD64__ #define __ASM_NEED_AMD64__ 1 #endif -- cgit v1.2.3 From b0c5f2a2683657182f5ce3dc3bcbf252164b0077 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 5 Aug 2025 09:47:53 +0100 Subject: feat! compiler_kit & debugger_kit: breaking changes, big name refactors on the source code have been done. Signed-off-by: Amlal El Mahrouss --- dev/CompilerKit/AE.h | 2 +- dev/CompilerKit/BasicString.h | 2 +- dev/CompilerKit/CodeGen.h | 16 ++++++------- dev/CompilerKit/Defines.h | 16 ++++++------- dev/CompilerKit/ErrorID.h | 20 ++++++++-------- dev/CompilerKit/ErrorOr.h | 2 +- dev/CompilerKit/Frontend.h | 2 +- dev/CompilerKit/Macros.h | 14 +++++------ dev/CompilerKit/Ref.h | 2 +- dev/CompilerKit/lc-osx-san.json | 2 +- dev/CompilerKit/lc-osx.json | 2 +- dev/CompilerKit/lc-posix.json | 2 +- dev/CompilerKit/src/Backend/Assembler32x0.cc | 2 +- dev/CompilerKit/src/Backend/Assembler64x0.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerAMD64.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerARM64.cc | 4 ++-- dev/CompilerKit/src/Backend/AssemblerPowerPC.cc | 4 ++-- dev/CompilerKit/src/CodeGen.cc | 8 +++---- dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 8 +++---- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 8 +++---- dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 8 +++---- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 28 +++++++++++----------- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 28 +++++++++++----------- .../src/Macro/CPlusPlusCompilerPreProcessor.cc | 14 +++++------ dev/CompilerKit/utils/CompilerUtils.h | 4 ++-- dev/DebuggerKit/ld-nekernel.json | 2 +- dev/DebuggerKit/ld-osx.json | 2 +- dev/DebuggerKit/src/NeKernelContractCLI.cc | 2 +- dev/DebuggerKit/src/POSIXMachContractCLI.cc | 2 +- dev/LibC++/__power64.inc | 2 +- dev/LibC++/defines.h | 8 +++---- dev/LibC++/filesystem.h | 6 ++--- tools/cppdrv.cc | 4 ++-- tools/pef-amd64-cxxdrv.cc | 2 +- tools/pef-arm64-cdrv.cc | 2 +- 35 files changed, 117 insertions(+), 117 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/AE.h b/dev/CompilerKit/AE.h index 1115e0a..6561baf 100644 --- a/dev/CompilerKit/AE.h +++ b/dev/CompilerKit/AE.h @@ -97,7 +97,7 @@ class AEReadableProtocol final { explicit AEReadableProtocol() = default; ~AEReadableProtocol() = default; - LIBCOMPILER_COPY_DELETE(AEReadableProtocol); + NECTI_COPY_DELETE(AEReadableProtocol); /** * @brief Read AE Record headers. diff --git a/dev/CompilerKit/BasicString.h b/dev/CompilerKit/BasicString.h index a1ada68..c4cb55a 100644 --- a/dev/CompilerKit/BasicString.h +++ b/dev/CompilerKit/BasicString.h @@ -39,7 +39,7 @@ class BasicString final { } } - LIBCOMPILER_COPY_DEFAULT(BasicString); + NECTI_COPY_DEFAULT(BasicString); Char* Data(); const Char* CData() const; diff --git a/dev/CompilerKit/CodeGen.h b/dev/CompilerKit/CodeGen.h index 9a3077b..1439c27 100644 --- a/dev/CompilerKit/CodeGen.h +++ b/dev/CompilerKit/CodeGen.h @@ -23,7 +23,7 @@ class AssemblyFactory final { explicit AssemblyFactory() = default; ~AssemblyFactory() = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyFactory); + NECTI_COPY_DEFAULT(AssemblyFactory); public: enum { @@ -54,7 +54,7 @@ class AssemblyInterface { explicit AssemblyInterface() = default; virtual ~AssemblyInterface() = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyInterface); + NECTI_COPY_DEFAULT(AssemblyInterface); virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } @@ -113,7 +113,7 @@ class EncoderInterface { explicit EncoderInterface() = default; virtual ~EncoderInterface() = default; - LIBCOMPILER_COPY_DEFAULT(EncoderInterface); + NECTI_COPY_DEFAULT(EncoderInterface); virtual std::string CheckLine(std::string line, std::string file) = 0; virtual bool WriteLine(std::string line, std::string file) = 0; @@ -127,7 +127,7 @@ class EncoderAMD64 final : public EncoderInterface { explicit EncoderAMD64() = default; ~EncoderAMD64() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderAMD64); + NECTI_COPY_DEFAULT(EncoderAMD64); virtual std::string CheckLine(std::string line, std::string file) override; virtual bool WriteLine(std::string line, std::string file) override; @@ -147,7 +147,7 @@ class EncoderARM64 final : public EncoderInterface { explicit EncoderARM64() = default; ~EncoderARM64() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderARM64); + NECTI_COPY_DEFAULT(EncoderARM64); virtual std::string CheckLine(std::string line, std::string file) override; virtual bool WriteLine(std::string line, std::string file) override; @@ -163,7 +163,7 @@ class Encoder64x0 final : public EncoderInterface { explicit Encoder64x0() = default; ~Encoder64x0() override = default; - LIBCOMPILER_COPY_DEFAULT(Encoder64x0); + NECTI_COPY_DEFAULT(Encoder64x0); virtual std::string CheckLine(std::string line, std::string file) override; virtual bool WriteLine(std::string line, std::string file) override; @@ -179,7 +179,7 @@ class Encoder32x0 final : public EncoderInterface { explicit Encoder32x0() = default; ~Encoder32x0() override = default; - LIBCOMPILER_COPY_DEFAULT(Encoder32x0); + NECTI_COPY_DEFAULT(Encoder32x0); virtual std::string CheckLine(std::string line, std::string file) override; virtual bool WriteLine(std::string line, std::string file) override; @@ -195,7 +195,7 @@ class EncoderPowerPC final : public EncoderInterface { explicit EncoderPowerPC() = default; ~EncoderPowerPC() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderPowerPC); + NECTI_COPY_DEFAULT(EncoderPowerPC); virtual std::string CheckLine(std::string line, std::string file) override; virtual bool WriteLine(std::string line, std::string file) override; diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h index c3d40ac..e3203ba 100644 --- a/dev/CompilerKit/Defines.h +++ b/dev/CompilerKit/Defines.h @@ -4,8 +4,8 @@ ------------------------------------------- */ -#ifndef __LIBCOMPILER_DEFINES_H__ -#define __LIBCOMPILER_DEFINES_H__ +#ifndef __NECTI_DEFINES_H__ +#define __NECTI_DEFINES_H__ #ifndef Yes #define Yes true @@ -81,19 +81,19 @@ #define rt_copy_memory(dst, src, len) memcpy(dst, src, len) #endif -#define LIBCOMPILER_COPY_DELETE(KLASS) \ +#define NECTI_COPY_DELETE(KLASS) \ KLASS& operator=(const KLASS&) = delete; \ KLASS(const KLASS&) = delete; -#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ +#define NECTI_COPY_DEFAULT(KLASS) \ KLASS& operator=(const KLASS&) = default; \ KLASS(const KLASS&) = default; -#define LIBCOMPILER_MOVE_DELETE(KLASS) \ +#define NECTI_MOVE_DELETE(KLASS) \ KLASS& operator=(KLASS&&) = delete; \ KLASS(KLASS&&) = delete; -#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ +#define NECTI_MOVE_DEFAULT(KLASS) \ KLASS& operator=(KLASS&&) = default; \ KLASS(KLASS&&) = default; @@ -162,10 +162,10 @@ typedef char char_type; #define kAsmFileExtsMax (7U) -#define LIBCOMPILER_MODULE(name) extern "C" int name(int argc, char** argv) +#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) #ifdef MSVC #pragma scalar_storage_order big - endian #endif // ifdef MSVC -#endif /* ifndef __LIBCOMPILER_DEFINES_H__ */ +#endif /* ifndef __NECTI_DEFINES_H__ */ diff --git a/dev/CompilerKit/ErrorID.h b/dev/CompilerKit/ErrorID.h index 22ca242..5b8d1e8 100644 --- a/dev/CompilerKit/ErrorID.h +++ b/dev/CompilerKit/ErrorID.h @@ -11,13 +11,13 @@ #include -#define LIBCOMPILER_SUCCESS 0 -#define LIBCOMPILER_EXEC_ERROR -30 -#define LIBCOMPILER_FILE_NOT_FOUND -31 -#define LIBCOMPILER_DIR_NOT_FOUND -32 -#define LIBCOMPILER_FILE_EXISTS -33 -#define LIBCOMPILER_TOO_LONG -34 -#define LIBCOMPILER_INVALID_DATA -35 -#define LIBCOMPILER_UNIMPLEMENTED -36 -#define LIBCOMPILER_FAT_ERROR -37 -#define LIBCOMPILER_INVALID_ARCH -38 +#define NECTI_SUCCESS 0 +#define NECTI_EXEC_ERROR -30 +#define NECTI_FILE_NOT_FOUND -31 +#define NECTI_DIR_NOT_FOUND -32 +#define NECTI_FILE_EXISTS -33 +#define NECTI_TOO_LONG -34 +#define NECTI_INVALID_DATA -35 +#define NECTI_UNIMPLEMENTED -36 +#define NECTI_FAT_ERROR -37 +#define NECTI_INVALID_ARCH -38 diff --git a/dev/CompilerKit/ErrorOr.h b/dev/CompilerKit/ErrorOr.h index 700da23..218bec5 100644 --- a/dev/CompilerKit/ErrorOr.h +++ b/dev/CompilerKit/ErrorOr.h @@ -36,7 +36,7 @@ class ErrorOr final { Int32 Error() { return mId; } - BOOL HasError() { return mId != LIBCOMPILER_SUCCESS; } + BOOL HasError() { return mId != NECTI_SUCCESS; } operator bool() { return mRef; } diff --git a/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h index 8af3066..168aa63 100644 --- a/dev/CompilerKit/Frontend.h +++ b/dev/CompilerKit/Frontend.h @@ -103,7 +103,7 @@ class CompilerFrontendInterface { explicit CompilerFrontendInterface() = default; virtual ~CompilerFrontendInterface() = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendInterface); + NECTI_COPY_DEFAULT(CompilerFrontendInterface); // NOTE: cast this to your user defined ast. typedef void* AstType; diff --git a/dev/CompilerKit/Macros.h b/dev/CompilerKit/Macros.h index 844bc23..ee42be5 100644 --- a/dev/CompilerKit/Macros.h +++ b/dev/CompilerKit/Macros.h @@ -9,25 +9,25 @@ #ifndef _MACROS_H_ #define _MACROS_H_ -#define LIBCOMPILER_COPY_DELETE(KLASS) \ +#define NECTI_COPY_DELETE(KLASS) \ KLASS& operator=(const KLASS&) = delete; \ KLASS(const KLASS&) = delete; -#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ +#define NECTI_COPY_DEFAULT(KLASS) \ KLASS& operator=(const KLASS&) = default; \ KLASS(const KLASS&) = default; -#define LIBCOMPILER_MOVE_DELETE(KLASS) \ +#define NECTI_MOVE_DELETE(KLASS) \ KLASS& operator=(KLASS&&) = delete; \ KLASS(KLASS&&) = delete; -#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ +#define NECTI_MOVE_DEFAULT(KLASS) \ KLASS& operator=(KLASS&&) = default; \ KLASS(KLASS&&) = default; /// @note xxxx is the error placeholder, in hexadecimal. -#define LIBCOMPILER_ERROR_PREFIX_CXX "CXXxxxx" -#define LIBCOMPILER_ERROR_PREFIX_CL "CLxxxx" -#define LIBCOMPILER_ERROR_PREFIX_ASM "ASMxxxx" +#define NECTI_ERROR_PREFIX_CXX "CXXxxxx" +#define NECTI_ERROR_PREFIX_CL "CLxxxx" +#define NECTI_ERROR_PREFIX_ASM "ASMxxxx" #endif /* ifndef _MACROS_H_ */ diff --git a/dev/CompilerKit/Ref.h b/dev/CompilerKit/Ref.h index a3640ac..bd432e0 100644 --- a/dev/CompilerKit/Ref.h +++ b/dev/CompilerKit/Ref.h @@ -27,7 +27,7 @@ class Ref final { } } - LIBCOMPILER_COPY_DEFAULT(Ref); + NECTI_COPY_DEFAULT(Ref); public: explicit Ref(T* cls, const Bool& strong = false) : m_Class(cls), m_Strong(strong) {} diff --git a/dev/CompilerKit/lc-osx-san.json b/dev/CompilerKit/lc-osx-san.json index 244936d..5ec4209 100644 --- a/dev/CompilerKit/lc-osx-san.json +++ b/dev/CompilerKit/lc-osx-san.json @@ -22,7 +22,7 @@ "-fsanitize=undefined" ], "cpp_macros": [ - "__LIBCOMPILER__=202505", + "__NECTI__=202505", "LC_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] diff --git a/dev/CompilerKit/lc-osx.json b/dev/CompilerKit/lc-osx.json index 3116045..e434ee8 100644 --- a/dev/CompilerKit/lc-osx.json +++ b/dev/CompilerKit/lc-osx.json @@ -17,7 +17,7 @@ "-shared" ], "cpp_macros": [ - "__LIBCOMPILER__=202505", + "__NECTI__=202505", "LC_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] diff --git a/dev/CompilerKit/lc-posix.json b/dev/CompilerKit/lc-posix.json index 6e824d4..e8668b9 100644 --- a/dev/CompilerKit/lc-posix.json +++ b/dev/CompilerKit/lc-posix.json @@ -17,7 +17,7 @@ "-shared" ], "cpp_macros": [ - "__LIBCOMPILER__=202505", + "__NECTI__=202505", "LC_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc index e298d2d..bc52d25 100644 --- a/dev/CompilerKit/src/Backend/Assembler32x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler32x0.cc @@ -33,7 +33,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(NEAssemblerMain32000) { +NECTI_MODULE(NEAssemblerMain32000) { CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); return EXIT_SUCCESS; } diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc index 32b199d..511c64d 100644 --- a/dev/CompilerKit/src/Backend/Assembler64x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler64x0.cc @@ -67,7 +67,7 @@ static bool asm_read_attributes(std::string line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMain64x0) { +NECTI_MODULE(AssemblerMain64x0) { CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); for (size_t i = 1; i < argc; ++i) { diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc index 6542d6e..b085773 100644 --- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc @@ -84,7 +84,7 @@ static bool asm_read_attributes(std::string line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainAMD64) { +NECTI_MODULE(AssemblerMainAMD64) { //////////////// CPU OPCODES BEGIN //////////////// CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc index d290e24..6890b2c 100644 --- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerARM64.cc @@ -72,7 +72,7 @@ static bool asm_read_attributes(std::string line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainARM64) { +NECTI_MODULE(AssemblerMainARM64) { CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); for (size_t i = 1; i < argc; ++i) { @@ -258,7 +258,7 @@ asm_fail_exit: if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n"; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc index a04a52b..b02a112 100644 --- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc +++ b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc @@ -72,7 +72,7 @@ static bool asm_read_attributes(std::string line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainPower64) { +NECTI_MODULE(AssemblerMainPower64) { CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); for (size_t i = 1; i < argc; ++i) { @@ -258,7 +258,7 @@ asm_fail_exit: if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n"; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/dev/CompilerKit/src/CodeGen.cc b/dev/CompilerKit/src/CodeGen.cc index e59001d..693d7a5 100644 --- a/dev/CompilerKit/src/CodeGen.cc +++ b/dev/CompilerKit/src/CodeGen.cc @@ -20,15 +20,15 @@ namespace CompilerKit { ///! @brief Compile for specific format (ELF, PEF, ZBIN) Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { - if (sourceFile.length() < 1) return LIBCOMPILER_UNIMPLEMENTED; + if (sourceFile.length() < 1) return NECTI_UNIMPLEMENTED; - if (!fMounted) return LIBCOMPILER_UNIMPLEMENTED; - if (arch != fMounted->Arch()) return LIBCOMPILER_INVALID_ARCH; + if (!fMounted) return NECTI_UNIMPLEMENTED; + if (arch != fMounted->Arch()) return NECTI_INVALID_ARCH; try { return this->fMounted->CompileToFormat(sourceFile, arch); } catch (std::exception& e) { - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } } diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc index ae2939b..c7ac387 100644 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc @@ -139,7 +139,7 @@ class CompilerFrontend64x0 final : public CompilerKit::CompilerFrontendInterface explicit CompilerFrontend64x0() = default; ~CompilerFrontend64x0() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontend64x0); + NECTI_COPY_DEFAULT(CompilerFrontend64x0); std::string Check(const char* text, const char* file); CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; @@ -324,7 +324,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::strin if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction = "__NECTI_IF_PROC_"; kIfFunction += std::to_string(time_off._Raw); syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; @@ -1049,7 +1049,7 @@ class AssemblyCCInterface final LC_ASSEMBLY_INTERFACE { explicit AssemblyCCInterface() = default; ~AssemblyCCInterface() override = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + NECTI_COPY_DEFAULT(AssemblyCCInterface); UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArch64x0; } @@ -1197,7 +1197,7 @@ static void cc_print_help() { #define kExt ".c" -LIBCOMPILER_MODULE(CompilerCLang64x0) { +NECTI_MODULE(CompilerCLang64x0) { ::signal(SIGSEGV, Detail::drvi_crash_handler); kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc index 0cd08d0..dd230c5 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -140,7 +140,7 @@ class CompilerFrontendARM64 final : public CompilerKit::CompilerFrontendInterfac explicit CompilerFrontendARM64() = default; ~CompilerFrontendARM64() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendARM64); + NECTI_COPY_DEFAULT(CompilerFrontendARM64); std::string Check(const char* text, const char* file); CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; @@ -323,7 +323,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::stri if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction = "__NECTI_IF_PROC_"; kIfFunction += std::to_string(time_off._Raw); syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; @@ -1048,7 +1048,7 @@ class AssemblyCCInterface final LC_ASSEMBLY_INTERFACE { explicit AssemblyCCInterface() = default; ~AssemblyCCInterface() override = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + NECTI_COPY_DEFAULT(AssemblyCCInterface); UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAARCH64; } @@ -1196,7 +1196,7 @@ static void cc_print_help() { #define kCExtension ".c" -LIBCOMPILER_MODULE(CompilerCLangARM64) { +NECTI_MODULE(CompilerCLangARM64) { ::signal(SIGSEGV, Detail::drvi_crash_handler); kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc index aaa2308..0ffbef0 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc @@ -130,7 +130,7 @@ class CompilerFrontendPower64 final : public CompilerKit::CompilerFrontendInterf explicit CompilerFrontendPower64() = default; ~CompilerFrontendPower64() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendPower64); + NECTI_COPY_DEFAULT(CompilerFrontendPower64); std::string Check(const char* text, const char* file); CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; @@ -330,7 +330,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::st if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction = "__NECTI_IF_PROC_"; kIfFunction += std::to_string(time_off._Raw); syntax_leaf.fUserValue = @@ -1067,7 +1067,7 @@ class AssemblyMountpointCLang final LC_ASSEMBLY_INTERFACE { explicit AssemblyMountpointCLang() = default; ~AssemblyMountpointCLang() override = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyMountpointCLang); + NECTI_COPY_DEFAULT(AssemblyMountpointCLang); UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchPowerPC; } @@ -1214,7 +1214,7 @@ static void cc_print_help() { #define kExt ".c" -LIBCOMPILER_MODULE(CompilerCLangPowerPC) { +NECTI_MODULE(CompilerCLangPowerPC) { ::signal(SIGSEGV, Detail::drvi_crash_handler); kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index c38378a..5a0fc02 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -122,7 +122,7 @@ class CompilerFrontendCPlusPlusAMD64 final LC_COMPILER_FRONTEND { explicit CompilerFrontendCPlusPlusAMD64() = default; ~CompilerFrontendCPlusPlusAMD64() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendCPlusPlusAMD64); + NECTI_COPY_DEFAULT(CompilerFrontendCPlusPlusAMD64); CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(const CompilerKit::STLString text, CompilerKit::STLString file) override; @@ -362,10 +362,10 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( symbol_name_fn.erase(symbol_name_fn.find("(")); } - syntax_tree.fUserValue = "public_segment .code64 __LIBCOMPILER_" + symbol_name_fn + "\n"; + syntax_tree.fUserValue = "public_segment .code64 __NECTI_" + symbol_name_fn + "\n"; ++kFunctionEmbedLevel; - kOriginMap.push_back({"__LIBCOMPILER_" + symbol_name_fn, kOrigin}); + kOriginMap.push_back({"__NECTI_" + symbol_name_fn, kOrigin}); break; @@ -492,10 +492,10 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (pairRight != valueOfVar) { if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + + syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n\n"; syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + - "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; + "__NECTI_LOCAL_VAR_" + varName + "\n"; kOrigin += 1UL; } else { syntax_tree.fUserValue = @@ -509,10 +509,10 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (((int) indexRight - 1) < 0) { if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + + syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n"; syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + - "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; + "__NECTI_LOCAL_VAR_" + varName + "\n"; kOrigin += 1UL; } else { syntax_tree.fUserValue = @@ -665,8 +665,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( break; } } else { - syntax_tree.fUserValue = "__LIBCOMPILER_LOCAL_RETURN_STRING: db " + subText + - ", 0\nmov rcx, __LIBCOMPILER_LOCAL_RETURN_STRING\n"; + syntax_tree.fUserValue = "__NECTI_LOCAL_RETURN_STRING: db " + subText + + ", 0\nmov rcx, __NECTI_LOCAL_RETURN_STRING\n"; syntax_tree.fUserValue += "mov rax, rcx\nret\n"; kOrigin += 1UL; @@ -723,7 +723,7 @@ class AssemblyCPlusPlusInterfaceAMD64 final LC_ASSEMBLY_INTERFACE { explicit AssemblyCPlusPlusInterfaceAMD64() = default; ~AssemblyCPlusPlusInterfaceAMD64() override = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyCPlusPlusInterfaceAMD64); + NECTI_COPY_DEFAULT(AssemblyCPlusPlusInterfaceAMD64); UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAMD64; } @@ -756,7 +756,7 @@ class AssemblyCPlusPlusInterfaceAMD64 final LC_ASSEMBLY_INTERFACE { #define kExtListCxx \ { ".cpp", ".cxx", ".cc", ".c++", ".cp" } -LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { +NECTI_MODULE(CompilerCPlusPlusAMD64) { Boolean skip = false; kKeywords.emplace_back("if", CompilerKit::kKeywordKindIf); @@ -842,7 +842,7 @@ LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { if (strcmp(argv[index], "-cxx-dialect") == 0) { if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } if (strcmp(argv[index], "-cxx-max-err") == 0) { @@ -874,7 +874,7 @@ LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { for (CompilerKit::STLString ext : exts) { if (argv_i.ends_with(ext)) { if (kFactory.Compile(argv_i, kMachine) != kExitOK) { - return LIBCOMPILER_INVALID_DATA; + return NECTI_INVALID_DATA; } break; @@ -884,7 +884,7 @@ LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { kFactory.Unmount(); - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } // diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index b2906a6..0aa2b78 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -74,7 +74,7 @@ static std::vector kObjectBytes; /// @brief NE 64-bit Linker. /// @note This linker is made for PEF executable, thus NE based OSes. -LIBCOMPILER_MODULE(DynamicLinker64PEF) { +NECTI_MODULE(DynamicLinker64PEF) { bool is_executable = true; ::signal(SIGSEGV, Detail::drvi_crash_handler); @@ -99,11 +99,11 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "-arm64: Output as a ARM64 PEF.\n"; kConsoleOut << "-output: Select the output file name.\n"; - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } else if (StringCompare(argv[linker_arg], "-version") == 0) { kLinkerSplash(); - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } else if (StringCompare(argv[linker_arg], "-fat") == 0) { kFatBinaryEnable = true; @@ -170,10 +170,10 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { if (kOutput.empty()) { kConsoleOut << "no output filename set." << std::endl; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } else if (kObjectList.empty()) { kConsoleOut << "no input files." << std::endl; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } else { namespace FS = std::filesystem; @@ -183,7 +183,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { // if filesystem doesn't find file // -> throw error. kConsoleOut << "no such file: " << obj << std::endl; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } } } @@ -191,7 +191,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { // PEF expects a valid target architecture when outputing a binary. if (kArch == CompilerKit::kPefArchInvalid) { kConsoleOut << "no target architecture set, can't continue." << std::endl; - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } CompilerKit::PEFContainer pef_container{}; @@ -221,7 +221,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "error: " << strerror(errno) << "\n"; } - return LIBCOMPILER_FILE_NOT_FOUND; + return NECTI_FILE_NOT_FOUND; } //! Read AE to convert as PEF. @@ -250,7 +250,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { "treated as a FAT binary." << std::endl; - return LIBCOMPILER_FAT_ERROR; + return NECTI_FAT_ERROR; } else { if (kVerbose) { kConsoleOut << "Architecture matches what we expect.\n"; @@ -345,7 +345,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "not an object container: " << objectFile << std::endl; // don't continue, it is a fatal error. - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } pef_container.Cpu = archs; @@ -624,7 +624,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; } - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } // step 2.5: write program bytes. @@ -654,7 +654,7 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "Undefined symbol " << unreferenced_symbol << "\n"; } - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } if ((!kStartFound || kDuplicateSymbols) && @@ -663,10 +663,10 @@ LIBCOMPILER_MODULE(DynamicLinker64PEF) { kConsoleOut << "File: " << kOutput << ", is corrupt, removing file...\n"; } - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } // Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc index 12a69c8..9845967 100644 --- a/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc +++ b/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc @@ -725,7 +725,7 @@ void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) { ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { +NECTI_MODULE(CPlusPlusPreprocessorMain) { try { bool skip = false; bool double_skip = false; @@ -760,7 +760,7 @@ LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { Detail::bpp_macro macro_zka; - macro_zka.fName = "__LIBCOMPILER__"; + macro_zka.fName = "__NECTI__"; macro_zka.fValue = "1"; kMacros.push_back(macro_zka); @@ -806,7 +806,7 @@ LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " "reserved."); - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } if (strcmp(argv[index], "-cpp-help") == 0) { @@ -819,7 +819,7 @@ LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { printf("%s\n", "-cpp-ver: print the version."); printf("%s\n", "-cpp-help: show help (this current command)."); - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } if (strcmp(argv[index], "-cpp-include-dir") == 0) { @@ -871,7 +871,7 @@ LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { kFiles.emplace_back(argv[index]); } - if (kFiles.empty()) return LIBCOMPILER_EXEC_ERROR; + if (kFiles.empty()) return NECTI_EXEC_ERROR; for (auto& file : kFiles) { if (!std::filesystem::exists(file)) continue; @@ -882,12 +882,12 @@ LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { bpp_parse_file(file_descriptor, file_descriptor_pp); } - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } catch (const std::runtime_error& e) { std::cout << e.what() << '\n'; } - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } // Last rev 8-1-24 diff --git a/dev/CompilerKit/utils/CompilerUtils.h b/dev/CompilerKit/utils/CompilerUtils.h index da35b2b..bf48b79 100644 --- a/dev/CompilerKit/utils/CompilerUtils.h +++ b/dev/CompilerKit/utils/CompilerUtils.h @@ -46,7 +46,7 @@ inline void print_error(std::string reason, std::string file) noexcept { kStdErr << reason << kBlank << std::endl; - if (kAcceptableErrors > kErrorLimit) std::exit(LIBCOMPILER_EXEC_ERROR); + if (kAcceptableErrors > kErrorLimit) std::exit(NECTI_EXEC_ERROR); ++kAcceptableErrors; } @@ -111,6 +111,6 @@ inline void drvi_crash_handler(std::int32_t id) { std::cout << std::endl; - std::exit(LIBCOMPILER_EXEC_ERROR); + std::exit(NECTI_EXEC_ERROR); } } // namespace Detail diff --git a/dev/DebuggerKit/ld-nekernel.json b/dev/DebuggerKit/ld-nekernel.json index d2aeb24..be55d51 100644 --- a/dev/DebuggerKit/ld-nekernel.json +++ b/dev/DebuggerKit/ld-nekernel.json @@ -9,7 +9,7 @@ "output_name": "/usr/local/lib/libDebuggerKit.dylib", "compiler_flags": ["-fPIC", "-shared"], "cpp_macros": [ - "__LIBCOMPILER__=202505", + "__NECTI__=202505", "LC_USE_STRUCTS=1", "LD_NEKERNEL_DEBUGGER", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" diff --git a/dev/DebuggerKit/ld-osx.json b/dev/DebuggerKit/ld-osx.json index 26922f4..a7c5fac 100644 --- a/dev/DebuggerKit/ld-osx.json +++ b/dev/DebuggerKit/ld-osx.json @@ -9,7 +9,7 @@ "output_name": "/usr/local/lib/libDebuggerKit.dylib", "compiler_flags": ["-fPIC", "-shared"], "cpp_macros": [ - "__LIBCOMPILER__=202505", + "__NECTI__=202505", "LC_USE_STRUCTS=1", "DEBUGGERKIT_POSIX", "LD_MACH_DEBUGGER", diff --git a/dev/DebuggerKit/src/NeKernelContractCLI.cc b/dev/DebuggerKit/src/NeKernelContractCLI.cc index 9d078c8..49cf6c8 100644 --- a/dev/DebuggerKit/src/NeKernelContractCLI.cc +++ b/dev/DebuggerKit/src/NeKernelContractCLI.cc @@ -28,7 +28,7 @@ static void dbgi_ctrlc_handler(std::int32_t _) { kKeepRunning = false; } -LIBCOMPILER_MODULE(DebuggerNeKernel) { +NECTI_MODULE(DebuggerNeKernel) { pfd::notify("Debugger Event", "NeKernel Debugger\n(C) 2025 Amlal El Mahrouss and NeKernel.org contributors, all rights reserved."); diff --git a/dev/DebuggerKit/src/POSIXMachContractCLI.cc b/dev/DebuggerKit/src/POSIXMachContractCLI.cc index 11c05f8..80825c3 100644 --- a/dev/DebuggerKit/src/POSIXMachContractCLI.cc +++ b/dev/DebuggerKit/src/POSIXMachContractCLI.cc @@ -26,7 +26,7 @@ static void dbgi_ctrlc_handler(std::int32_t _) { kKeepRunning = false; } -LIBCOMPILER_MODULE(DebuggerMachPOSIX) { +NECTI_MODULE(DebuggerMachPOSIX) { pfd::notify("Debugger Event", "Userland Debugger\n(C) 2025 Amlal El Mahrouss, all rights reserved."); diff --git a/dev/LibC++/__power64.inc b/dev/LibC++/__power64.inc index b09bdcc..c06863a 100644 --- a/dev/LibC++/__power64.inc +++ b/dev/LibC++/__power64.inc @@ -2,7 +2,7 @@ # Language: CompilerKit POWER Assembly support for GNU. # Build Date: 2024-6-4 -#ifdef __LIBCOMPILER__ +#ifdef __NECTI__ #ifdef __ASSEMBLER__ diff --git a/dev/LibC++/defines.h b/dev/LibC++/defines.h index 493ed0c..2fedac5 100644 --- a/dev/LibC++/defines.h +++ b/dev/LibC++/defines.h @@ -4,8 +4,8 @@ ------------------------------------------- */ -#ifndef __LIBCOMPILER_DEFINES_H__ -#define __LIBCOMPILER_DEFINES_H__ +#ifndef __NECTI_DEFINES_H__ +#define __NECTI_DEFINES_H__ extern "C" { #include @@ -34,7 +34,7 @@ typedef char* caddr_t; #ifdef __GNUC__ #include -#elif defined(__LIBCOMPILER__) +#elif defined(__NECTI__) #define __alloca(sz) __lc_alloca(sz) #endif @@ -85,4 +85,4 @@ typedef union double_cast { #endif // ifndef __GNUC__ -#endif /* __LIBCOMPILER_DEFINES_H__ */ +#endif /* __NECTI_DEFINES_H__ */ diff --git a/dev/LibC++/filesystem.h b/dev/LibC++/filesystem.h index 254bfab..1095da1 100644 --- a/dev/LibC++/filesystem.h +++ b/dev/LibC++/filesystem.h @@ -4,8 +4,8 @@ ------------------------------------------- */ -#ifndef __LIBCOMPILER_FS_H__ -#define __LIBCOMPILER_FS_H__ +#ifndef __NECTI_FS_H__ +#define __NECTI_FS_H__ namespace std { class path; @@ -14,4 +14,4 @@ class directory_entry; class directory_iterator; } // namespace std -#endif // __LIBCOMPILER_FS_H__ \ No newline at end of file +#endif // __NECTI_FS_H__ \ No newline at end of file diff --git a/tools/cppdrv.cc b/tools/cppdrv.cc index 91b27b3..e46c8ee 100644 --- a/tools/cppdrv.cc +++ b/tools/cppdrv.cc @@ -20,8 +20,8 @@ int main(int argc, char const* argv[]) { if (auto code = CPlusPlusPreprocessorMain(2, argv); code > 0) { std::printf("cppdrv: preprocessor exited with code %i.\n", code); - return LIBCOMPILER_EXEC_ERROR; + return NECTI_EXEC_ERROR; } - return LIBCOMPILER_SUCCESS; + return NECTI_SUCCESS; } \ No newline at end of file diff --git a/tools/pef-amd64-cxxdrv.cc b/tools/pef-amd64-cxxdrv.cc index 5ddeb16..c7ca39e 100644 --- a/tools/pef-amd64-cxxdrv.cc +++ b/tools/pef-amd64-cxxdrv.cc @@ -37,7 +37,7 @@ Int32 main(Int32 argc, Char const* argv[]) { return EXIT_FAILURE; } - auto ret = (entrypoint_cxx(argc, argv) == LIBCOMPILER_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; + auto ret = (entrypoint_cxx(argc, argv) == NECTI_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; dlclose(handler); diff --git a/tools/pef-arm64-cdrv.cc b/tools/pef-arm64-cdrv.cc index f8b9e5c..1e4b149 100644 --- a/tools/pef-arm64-cdrv.cc +++ b/tools/pef-arm64-cdrv.cc @@ -37,7 +37,7 @@ Int32 main(Int32 argc, Char const* argv[]) { return EXIT_FAILURE; } - auto ret = (entrypoint_cxx(argc, argv) == LIBCOMPILER_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; + auto ret = (entrypoint_cxx(argc, argv) == NECTI_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE; dlclose(handler); -- cgit v1.2.3 From 5f8ee9584a7a5c911d46f73e24ec7a1201058c50 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Tue, 5 Aug 2025 09:57:44 +0100 Subject: feat! compiler_kit: API breaking changes. feat: debugger_kit: Debugger work in progress implementation. Signed-off-by: Amlal El Mahrouss --- compile_flags.txt | 6 ++-- dev/CompilerKit/CodeGen.h | 4 +-- dev/CompilerKit/Defines.h | 4 +-- dev/CompilerKit/Frontend.h | 2 +- dev/CompilerKit/detail/32x0.h | 22 ++++++------- dev/CompilerKit/detail/64x0.h | 38 +++++++++++----------- dev/CompilerKit/detail/X64.h | 14 ++++---- dev/CompilerKit/lc-osx-san.json | 2 +- dev/CompilerKit/lc-osx.json | 2 +- dev/CompilerKit/lc-posix.json | 2 +- dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 2 +- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 2 +- dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 2 +- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 4 +-- dev/DebuggerKit/CommonCLI.inl | 2 +- dev/DebuggerKit/NeKernelContract.h | 17 ++++++---- dev/DebuggerKit/POSIXMachContract.h | 8 ++--- dev/DebuggerKit/ld-nekernel.json | 4 +-- dev/DebuggerKit/ld-osx.json | 4 +-- dev/DebuggerKit/src/NeKernelContract.cc | 7 ++-- dev/DebuggerKit/src/NeKernelContractCLI.cc | 4 +-- dev/DebuggerKit/src/POSIXMachContractCLI.cc | 2 +- tools/asm.cc | 8 ++--- tools/cppdrv.cc | 2 +- tools/dbg.cc | 2 +- tools/kdbg.cc | 2 +- tools/ld64.cc | 2 +- tools/pef-amd64-cxxdrv.cc | 2 +- tools/pef-arm64-cdrv.cc | 2 +- 29 files changed, 88 insertions(+), 86 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/compile_flags.txt b/compile_flags.txt index fb0007b..2583106 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -4,8 +4,8 @@ -Idev/CompilerKit/Detail -Isdk/ -I./ --DLC_USE_STRUCTS +-DCK_USE_STRUCTS -xc++ --DLD_NEKERNEL_DEBUGGER --DLD_MACH_DEBUGGER +-DDK_NEKERNEL_DEBUGGER +-DDK_MACH_DEBUGGER -DDEBUGGERKIT_POSIX \ No newline at end of file diff --git a/dev/CompilerKit/CodeGen.h b/dev/CompilerKit/CodeGen.h index 1439c27..99c968b 100644 --- a/dev/CompilerKit/CodeGen.h +++ b/dev/CompilerKit/CodeGen.h @@ -10,8 +10,8 @@ #include #include -#define LC_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface -#define LC_ENCODER : public ::CompilerKit::EncoderInterface +#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface +#define CK_ENCODER : public ::CompilerKit::EncoderInterface namespace CompilerKit { class AssemblyFactory; diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h index e3203ba..e9d2560 100644 --- a/dev/CompilerKit/Defines.h +++ b/dev/CompilerKit/Defines.h @@ -97,8 +97,8 @@ KLASS& operator=(KLASS&&) = default; \ KLASS(KLASS&&) = default; -#define LC_IMPORT_C extern "C" -#define LC_IMPORT extern +#define CK_IMPORT_C extern "C" +#define CK_IMPORT extern namespace CompilerKit { inline constexpr int kBaseYear = 1900; diff --git a/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h index 168aa63..baf00d9 100644 --- a/dev/CompilerKit/Frontend.h +++ b/dev/CompilerKit/Frontend.h @@ -8,7 +8,7 @@ #include -#define LC_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface +#define CK_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface namespace CompilerKit { inline static auto kInvalidFrontend = "?"; diff --git a/dev/CompilerKit/detail/32x0.h b/dev/CompilerKit/detail/32x0.h index 124d9f4..f2d30e4 100644 --- a/dev/CompilerKit/detail/32x0.h +++ b/dev/CompilerKit/detail/32x0.h @@ -11,7 +11,7 @@ // @brief Open32x0 support. // @file detail/32x0.h -#define LC_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ +#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, #define kAsmImmediate 0x01 @@ -37,18 +37,18 @@ struct CpuCode32x0 { #define kAsmByteStr ".byte" /* 8-bit */ inline std::vector kOpcodes32x0 = { - LC_ASM_OPCODE("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) - LC_ASM_OPCODE("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) - LC_ASM_OPCODE("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) - LC_ASM_OPCODE("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) - LC_ASM_OPCODE("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) - LC_ASM_OPCODE("lea", 0b0111011, 0b010, + CK_ASM_OPCODE("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) + CK_ASM_OPCODE("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) + CK_ASM_OPCODE("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) + CK_ASM_OPCODE("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) + CK_ASM_OPCODE("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) + CK_ASM_OPCODE("lea", 0b0111011, 0b010, kAsmImmediate) // setup stack and call, store address to CR (1C). - LC_ASM_OPCODE("ret", 0b0111011, 0b110, + CK_ASM_OPCODE("ret", 0b0111011, 0b110, kAsmImmediate) // return from procedure (2C). - LC_ASM_OPCODE("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) - LC_ASM_OPCODE("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) - LC_ASM_OPCODE("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) + CK_ASM_OPCODE("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) + CK_ASM_OPCODE("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) + CK_ASM_OPCODE("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) }; // \brief 64x0 register prefix diff --git a/dev/CompilerKit/detail/64x0.h b/dev/CompilerKit/detail/64x0.h index af01c07..9c12ca5 100644 --- a/dev/CompilerKit/detail/64x0.h +++ b/dev/CompilerKit/detail/64x0.h @@ -12,7 +12,7 @@ // @brief Open64x0 support. // @file detail/64x0.h -#define LC_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ +#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, #define kAsmImmediate 0x01 @@ -32,28 +32,28 @@ struct CpuOpcode64x0 { }; inline std::vector kOpcodes64x0 = { - LC_ASM_OPCODE("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - LC_ASM_OPCODE("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - LC_ASM_OPCODE("jlr", 0b1110011, 0b0000111, + CK_ASM_OPCODE("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + CK_ASM_OPCODE("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + CK_ASM_OPCODE("jlr", 0b1110011, 0b0000111, kAsmJump) // jump to linked return register - LC_ASM_OPCODE("jrl", 0b1110011, 0b0001111, + CK_ASM_OPCODE("jrl", 0b1110011, 0b0001111, kAsmJump) // jump from return register. - LC_ASM_OPCODE("mv", 0b0100011, 0b101, kAsmRegToReg) LC_ASM_OPCODE( - "bg", 0b1100111, 0b111, kAsmRegToReg) LC_ASM_OPCODE("bl", 0b1100111, 0b011, kAsmRegToReg) - LC_ASM_OPCODE("beq", 0b1100111, 0b000, kAsmRegToReg) - LC_ASM_OPCODE("bne", 0b1100111, 0b001, kAsmRegToReg) - LC_ASM_OPCODE("bge", 0b1100111, 0b101, kAsmRegToReg) - LC_ASM_OPCODE("ble", 0b1100111, 0b100, kAsmRegToReg) - LC_ASM_OPCODE("stw", 0b0001111, 0b100, kAsmImmediate) - LC_ASM_OPCODE("ldw", 0b0001111, 0b100, kAsmImmediate) - LC_ASM_OPCODE("lda", 0b0001111, 0b101, kAsmImmediate) - LC_ASM_OPCODE("sta", 0b0001111, 0b001, kAsmImmediate) + CK_ASM_OPCODE("mv", 0b0100011, 0b101, kAsmRegToReg) CK_ASM_OPCODE( + "bg", 0b1100111, 0b111, kAsmRegToReg) CK_ASM_OPCODE("bl", 0b1100111, 0b011, kAsmRegToReg) + CK_ASM_OPCODE("beq", 0b1100111, 0b000, kAsmRegToReg) + CK_ASM_OPCODE("bne", 0b1100111, 0b001, kAsmRegToReg) + CK_ASM_OPCODE("bge", 0b1100111, 0b101, kAsmRegToReg) + CK_ASM_OPCODE("ble", 0b1100111, 0b100, kAsmRegToReg) + CK_ASM_OPCODE("stw", 0b0001111, 0b100, kAsmImmediate) + CK_ASM_OPCODE("ldw", 0b0001111, 0b100, kAsmImmediate) + CK_ASM_OPCODE("lda", 0b0001111, 0b101, kAsmImmediate) + CK_ASM_OPCODE("sta", 0b0001111, 0b001, kAsmImmediate) // add/sub without carry flag - LC_ASM_OPCODE("add", 0b0101011, 0b100, kAsmImmediate) - LC_ASM_OPCODE("sub", 0b0101011, 0b101, kAsmImmediate) + CK_ASM_OPCODE("add", 0b0101011, 0b100, kAsmImmediate) + CK_ASM_OPCODE("sub", 0b0101011, 0b101, kAsmImmediate) // add/sub with carry flag - LC_ASM_OPCODE("addc", 0b0101011, 0b110, kAsmImmediate) LC_ASM_OPCODE( - "subc", 0b0101011, 0b111, kAsmImmediate) LC_ASM_OPCODE("sc", 0b1110011, 0b00, kAsmSyscall)}; + CK_ASM_OPCODE("addc", 0b0101011, 0b110, kAsmImmediate) CK_ASM_OPCODE( + "subc", 0b0101011, 0b111, kAsmImmediate) CK_ASM_OPCODE("sc", 0b1110011, 0b00, kAsmSyscall)}; // \brief 64x0 register prefix // example: r32, r0 diff --git a/dev/CompilerKit/detail/X64.h b/dev/CompilerKit/detail/X64.h index 3f7420a..ed995be 100644 --- a/dev/CompilerKit/detail/X64.h +++ b/dev/CompilerKit/detail/X64.h @@ -11,7 +11,7 @@ // @brief AMD64 support. // @file detail/X64.h -#define LC_ASM_OPCODE(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, +#define CK_ASM_OPCODE(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, typedef char i64_character_t; typedef uint8_t i64_byte_t; @@ -39,11 +39,11 @@ struct CpuOpcodeAMD64 { #define kJumpLimitStandardLimit 0xEB inline std::vector kOpcodesAMD64 = { - LC_ASM_OPCODE("int", 0xCD) LC_ASM_OPCODE("into", 0xCE) LC_ASM_OPCODE("intd", 0xF1) - LC_ASM_OPCODE("int3", 0xC3) LC_ASM_OPCODE("iret", 0xCF) LC_ASM_OPCODE("retf", 0xCB) - LC_ASM_OPCODE("retn", 0xC3) LC_ASM_OPCODE("ret", 0xC3) LC_ASM_OPCODE("sti", 0xfb) - LC_ASM_OPCODE("cli", 0xfa) LC_ASM_OPCODE("hlt", 0xf4) LC_ASM_OPCODE("nop", 0x90) - LC_ASM_OPCODE("mov", 0x48) LC_ASM_OPCODE("call", 0xFF) - LC_ASM_OPCODE("syscall", 0x0F) LC_ASM_OPCODE("xor", 0x48)}; + CK_ASM_OPCODE("int", 0xCD) CK_ASM_OPCODE("into", 0xCE) CK_ASM_OPCODE("intd", 0xF1) + CK_ASM_OPCODE("int3", 0xC3) CK_ASM_OPCODE("iret", 0xCF) CK_ASM_OPCODE("retf", 0xCB) + CK_ASM_OPCODE("retn", 0xC3) CK_ASM_OPCODE("ret", 0xC3) CK_ASM_OPCODE("sti", 0xfb) + CK_ASM_OPCODE("cli", 0xfa) CK_ASM_OPCODE("hlt", 0xf4) CK_ASM_OPCODE("nop", 0x90) + CK_ASM_OPCODE("mov", 0x48) CK_ASM_OPCODE("call", 0xFF) + CK_ASM_OPCODE("syscall", 0x0F) CK_ASM_OPCODE("xor", 0x48)}; #define kAsmRegisterLimit 16 diff --git a/dev/CompilerKit/lc-osx-san.json b/dev/CompilerKit/lc-osx-san.json index 5ec4209..f190db2 100644 --- a/dev/CompilerKit/lc-osx-san.json +++ b/dev/CompilerKit/lc-osx-san.json @@ -23,7 +23,7 @@ ], "cpp_macros": [ "__NECTI__=202505", - "LC_USE_STRUCTS=1", + "CK_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] } \ No newline at end of file diff --git a/dev/CompilerKit/lc-osx.json b/dev/CompilerKit/lc-osx.json index e434ee8..4880763 100644 --- a/dev/CompilerKit/lc-osx.json +++ b/dev/CompilerKit/lc-osx.json @@ -18,7 +18,7 @@ ], "cpp_macros": [ "__NECTI__=202505", - "LC_USE_STRUCTS=1", + "CK_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] } \ No newline at end of file diff --git a/dev/CompilerKit/lc-posix.json b/dev/CompilerKit/lc-posix.json index e8668b9..e80ce65 100644 --- a/dev/CompilerKit/lc-posix.json +++ b/dev/CompilerKit/lc-posix.json @@ -18,7 +18,7 @@ ], "cpp_macros": [ "__NECTI__=202505", - "LC_USE_STRUCTS=1", + "CK_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] } \ No newline at end of file diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc index c7ac387..6ee7e32 100644 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc @@ -1044,7 +1044,7 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCCInterface final LC_ASSEMBLY_INTERFACE { +class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { public: explicit AssemblyCCInterface() = default; ~AssemblyCCInterface() override = default; diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc index dd230c5..1c1582f 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -1043,7 +1043,7 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCCInterface final LC_ASSEMBLY_INTERFACE { +class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { public: explicit AssemblyCCInterface() = default; ~AssemblyCCInterface() override = default; diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc index 0ffbef0..40598c9 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc @@ -1062,7 +1062,7 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointCLang final LC_ASSEMBLY_INTERFACE { +class AssemblyMountpointCLang final CK_ASSEMBLY_INTERFACE { public: explicit AssemblyMountpointCLang() = default; ~AssemblyMountpointCLang() override = default; diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index 5a0fc02..98a8018 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -117,7 +117,7 @@ static Boolean kInBraces = false; static size_t kBracesCount = 0UL; /* @brief C++ compiler backend for the NeKernel C++ driver */ -class CompilerFrontendCPlusPlusAMD64 final LC_COMPILER_FRONTEND { +class CompilerFrontendCPlusPlusAMD64 final CK_COMPILER_FRONTEND { public: explicit CompilerFrontendCPlusPlusAMD64() = default; ~CompilerFrontendCPlusPlusAMD64() override = default; @@ -718,7 +718,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCPlusPlusInterfaceAMD64 final LC_ASSEMBLY_INTERFACE { +class AssemblyCPlusPlusInterfaceAMD64 final CK_ASSEMBLY_INTERFACE { public: explicit AssemblyCPlusPlusInterfaceAMD64() = default; ~AssemblyCPlusPlusInterfaceAMD64() override = default; diff --git a/dev/DebuggerKit/CommonCLI.inl b/dev/DebuggerKit/CommonCLI.inl index 325be23..cf006f5 100644 --- a/dev/DebuggerKit/CommonCLI.inl +++ b/dev/DebuggerKit/CommonCLI.inl @@ -17,7 +17,7 @@ static BOOL kKeepRunning = false; -#ifdef LD_NEKERNEL_DEBUGGER +#ifdef DK_NEKERNEL_DEBUGGER static DebuggerKit::NeKernel::NeKernelContract kKernelDebugger; #else static DebuggerKit::POSIX::POSIXMachContract kDebugger; diff --git a/dev/DebuggerKit/NeKernelContract.h b/dev/DebuggerKit/NeKernelContract.h index 9797639..20d86cd 100644 --- a/dev/DebuggerKit/NeKernelContract.h +++ b/dev/DebuggerKit/NeKernelContract.h @@ -3,10 +3,10 @@ (C) 2025 Amlal El Mahrouss */ -#ifndef LD_NEKERNEL_CONTRACT_H -#define LD_NEKERNEL_CONTRACT_H +#ifndef DK_NEKERNEL_CONTRACT_H +#define DK_NEKERNEL_CONTRACT_H -#ifdef LD_NEKERNEL_DEBUGGER +#ifdef DK_NEKERNEL_DEBUGGER #include @@ -14,8 +14,11 @@ namespace DebuggerKit::NeKernel { class NeKernelContract; namespace Detail { - inline constexpr size_t kDebugCmdLen = 256U; - typedef char rt_debug_cmd[kDebugCmdLen]; + inline constexpr auto kDebugCmdLen = 256U; + inline constexpr auto kDebugPort = 51820; + inline constexpr auto kDebugMagic = "VMK1.0.0;"; + inline constexpr auto kDebugVersion = 0x0100; + typedef char rt_debug_cmd[kDebugCmdLen]; } // namespace Detail class NeKernelContract : public DebuggerContract { @@ -42,6 +45,6 @@ class NeKernelContract : public DebuggerContract { }; } // namespace DebuggerKit::NeKernel -#endif // ifdef LD_NEKERNEL_DEBUGGER +#endif // ifdef DK_NEKERNEL_DEBUGGER -#endif // LD_NEKERNEL_CONTRACT_H \ No newline at end of file +#endif // DK_NEKERNEL_CONTRACT_H \ No newline at end of file diff --git a/dev/DebuggerKit/POSIXMachContract.h b/dev/DebuggerKit/POSIXMachContract.h index a2c49ce..b04a13a 100644 --- a/dev/DebuggerKit/POSIXMachContract.h +++ b/dev/DebuggerKit/POSIXMachContract.h @@ -4,7 +4,7 @@ #pragma once -#ifdef LD_MACH_DEBUGGER +#ifdef DK_MACH_DEBUGGER /// @file POSIXMachContract.h /// @brief POSIX Mach debugger. @@ -28,10 +28,10 @@ #include #include -LC_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, +CK_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt); -LC_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, +CK_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection); @@ -93,7 +93,7 @@ class POSIXMachContract : public DebuggerContract { BOOL BreakAt(std::string symbol) noexcept override { if (!m_path.empty() && std::filesystem::exists(m_path) && std::filesystem::is_regular_file(m_path)) { - auto handle = dlopen(m_path.c_str(), RTLD_LAZY); + auto handle = dlopen(m_path.c_str(), RTDK_LAZY); if (handle == nullptr) { return false; diff --git a/dev/DebuggerKit/ld-nekernel.json b/dev/DebuggerKit/ld-nekernel.json index be55d51..45ee51d 100644 --- a/dev/DebuggerKit/ld-nekernel.json +++ b/dev/DebuggerKit/ld-nekernel.json @@ -10,8 +10,8 @@ "compiler_flags": ["-fPIC", "-shared"], "cpp_macros": [ "__NECTI__=202505", - "LC_USE_STRUCTS=1", - "LD_NEKERNEL_DEBUGGER", + "CK_USE_STRUCTS=1", + "DK_NEKERNEL_DEBUGGER", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] } diff --git a/dev/DebuggerKit/ld-osx.json b/dev/DebuggerKit/ld-osx.json index a7c5fac..c220756 100644 --- a/dev/DebuggerKit/ld-osx.json +++ b/dev/DebuggerKit/ld-osx.json @@ -10,9 +10,9 @@ "compiler_flags": ["-fPIC", "-shared"], "cpp_macros": [ "__NECTI__=202505", - "LC_USE_STRUCTS=1", + "CK_USE_STRUCTS=1", "DEBUGGERKIT_POSIX", - "LD_MACH_DEBUGGER", + "DK_MACH_DEBUGGER", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] } diff --git a/dev/DebuggerKit/src/NeKernelContract.cc b/dev/DebuggerKit/src/NeKernelContract.cc index c78e2f2..a469e46 100644 --- a/dev/DebuggerKit/src/NeKernelContract.cc +++ b/dev/DebuggerKit/src/NeKernelContract.cc @@ -5,7 +5,7 @@ Purpose: NeKernel Debugger */ -#ifdef LD_NEKERNEL_DEBUGGER +#ifdef DK_NEKERNEL_DEBUGGER /// @author Amlal El Mahrouss /// @brief Kernel Debugger Protocol @@ -16,8 +16,6 @@ #include -constexpr static UInt16 kDebugPort = 51820; - using namespace DebuggerKit::NeKernel; NeKernelContract::NeKernelContract() = default; @@ -26,6 +24,7 @@ NeKernelContract::~NeKernelContract() = default; BOOL NeKernelContract::Attach(CompilerKit::STLString path, CompilerKit::STLString argv, ProcessID& pid) noexcept { + if (path.empty() || argv.empty()) return NO; return NO; } @@ -45,4 +44,4 @@ BOOL NeKernelContract::Detach() noexcept { return NO; } -#endif // LD_NEKERNEL_DEBUGGER \ No newline at end of file +#endif // DK_NEKERNEL_DEBUGGER \ No newline at end of file diff --git a/dev/DebuggerKit/src/NeKernelContractCLI.cc b/dev/DebuggerKit/src/NeKernelContractCLI.cc index 49cf6c8..1dd87a5 100644 --- a/dev/DebuggerKit/src/NeKernelContractCLI.cc +++ b/dev/DebuggerKit/src/NeKernelContractCLI.cc @@ -5,7 +5,7 @@ Purpose: NeKernel Debugger CLI. */ -#ifdef LD_NEKERNEL_DEBUGGER +#ifdef DK_NEKERNEL_DEBUGGER #include #include @@ -98,4 +98,4 @@ NECTI_MODULE(DebuggerNeKernel) { return EXIT_FAILURE; } -#endif // LD_NEKERNEL_DEBUGGER \ No newline at end of file +#endif // DK_NEKERNEL_DEBUGGER \ No newline at end of file diff --git a/dev/DebuggerKit/src/POSIXMachContractCLI.cc b/dev/DebuggerKit/src/POSIXMachContractCLI.cc index 80825c3..2b2ebc5 100644 --- a/dev/DebuggerKit/src/POSIXMachContractCLI.cc +++ b/dev/DebuggerKit/src/POSIXMachContractCLI.cc @@ -5,7 +5,7 @@ Purpose: OS X/Darwin Debugger */ -#ifdef LD_MACH_DEBUGGER +#ifdef DK_MACH_DEBUGGER #include #include diff --git a/tools/asm.cc b/tools/asm.cc index 5e7cae9..f600408 100644 --- a/tools/asm.cc +++ b/tools/asm.cc @@ -14,10 +14,10 @@ #include #include -LC_IMPORT_C int AssemblerMainPower64(int argc, char const* argv[]); -LC_IMPORT_C int AssemblerMainARM64(int argc, char const* argv[]); -LC_IMPORT_C int AssemblerMain64x0(int argc, char const* argv[]); -LC_IMPORT_C int AssemblerMainAMD64(int argc, char const* argv[]); +CK_IMPORT_C int AssemblerMainPower64(int argc, char const* argv[]); +CK_IMPORT_C int AssemblerMainARM64(int argc, char const* argv[]); +CK_IMPORT_C int AssemblerMain64x0(int argc, char const* argv[]); +CK_IMPORT_C int AssemblerMainAMD64(int argc, char const* argv[]); enum AsmKind : Int32 { kInvalidAssembler = 0, diff --git a/tools/cppdrv.cc b/tools/cppdrv.cc index e46c8ee..3152753 100644 --- a/tools/cppdrv.cc +++ b/tools/cppdrv.cc @@ -14,7 +14,7 @@ #include #include -LC_IMPORT_C int CPlusPlusPreprocessorMain(int argc, char const* argv[]); +CK_IMPORT_C int CPlusPlusPreprocessorMain(int argc, char const* argv[]); int main(int argc, char const* argv[]) { if (auto code = CPlusPlusPreprocessorMain(2, argv); code > 0) { diff --git a/tools/dbg.cc b/tools/dbg.cc index e8e75fc..1ee9c37 100644 --- a/tools/dbg.cc +++ b/tools/dbg.cc @@ -9,7 +9,7 @@ /// @file dbg.cxx /// @brief NE debugger. -LC_IMPORT_C Int32 DebuggerMachPOSIX(Int32 argc, Char const* argv[]); +CK_IMPORT_C Int32 DebuggerMachPOSIX(Int32 argc, Char const* argv[]); /// @brief Debugger entrypoint. /// @return Status code of debugger. diff --git a/tools/kdbg.cc b/tools/kdbg.cc index 5fd06e8..d7aaa93 100644 --- a/tools/kdbg.cc +++ b/tools/kdbg.cc @@ -9,7 +9,7 @@ /// @file kdbg.cxx /// @brief NeKernel debugger. -LC_IMPORT_C Int32 DebuggerNeKernel(Int32 argc, Char const* argv[]); +CK_IMPORT_C Int32 DebuggerNeKernel(Int32 argc, Char const* argv[]); /// @brief Debugger entrypoint. /// @return Status code of debugger. diff --git a/tools/ld64.cc b/tools/ld64.cc index 612b370..e551fee 100644 --- a/tools/ld64.cc +++ b/tools/ld64.cc @@ -9,7 +9,7 @@ /// @file ld64.cxx /// @brief NE Linker for AE objects. -LC_IMPORT_C int DynamicLinker64PEF(int argc, char const* argv[]); +CK_IMPORT_C int DynamicLinker64PEF(int argc, char const* argv[]); int main(int argc, char const* argv[]) { return DynamicLinker64PEF(argc, argv); diff --git a/tools/pef-amd64-cxxdrv.cc b/tools/pef-amd64-cxxdrv.cc index c7ca39e..21b68a0 100644 --- a/tools/pef-amd64-cxxdrv.cc +++ b/tools/pef-amd64-cxxdrv.cc @@ -17,7 +17,7 @@ static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; static auto kSymbol = "CompilerCPlusPlusAMD64"; Int32 main(Int32 argc, Char const* argv[]) { - CompilerKitDylib handler = dlopen(kPath, RTLD_LAZY | RTLD_GLOBAL); + CompilerKitDylib handler = dlopen(kPath, RTDK_LAZY | RTDK_GLOBAL); if (!handler) { kStdOut; diff --git a/tools/pef-arm64-cdrv.cc b/tools/pef-arm64-cdrv.cc index 1e4b149..4dbf39e 100644 --- a/tools/pef-arm64-cdrv.cc +++ b/tools/pef-arm64-cdrv.cc @@ -17,7 +17,7 @@ static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; static auto kSymbol = "CompilerCLangARM64"; Int32 main(Int32 argc, Char const* argv[]) { - CompilerKitDylib handler = dlopen(kPath, RTLD_LAZY | RTLD_GLOBAL); + CompilerKitDylib handler = dlopen(kPath, RTDK_LAZY | RTDK_GLOBAL); if (!handler) { kStdOut; -- cgit v1.2.3 From b7a832affbcc20fd25b51a6ffb7cff9e30b5dc29 Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Wed, 6 Aug 2025 17:51:19 +0300 Subject: Patch: BasicString.cc Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- dev/CompilerKit/src/BasicString.cc | 181 ++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 105 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/BasicString.cc b/dev/CompilerKit/src/BasicString.cc index b9aaa3f..6ca1e46 100644 --- a/dev/CompilerKit/src/BasicString.cc +++ b/dev/CompilerKit/src/BasicString.cc @@ -21,6 +21,7 @@ #include namespace CompilerKit { + Char* BasicString::Data() { return m_Data; } @@ -34,43 +35,24 @@ SizeType BasicString::Length() const { } bool BasicString::operator==(const BasicString& 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; + const SizeType len = Length(); + if (rhs.Length() != len) return false; + return memcmp(m_Data, rhs.m_Data, len) == 0; } bool BasicString::operator==(const Char* 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; + const SizeType rhs_len = string_length(rhs); + const SizeType len = Length(); + if (rhs_len != len) return false; + return memcmp(m_Data, rhs, len) == 0; } bool BasicString::operator!=(const BasicString& 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; + return !(*this == rhs); } bool BasicString::operator!=(const Char* 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; + return !(*this == rhs); } BasicString StringBuilder::Construct(const Char* data) { @@ -82,126 +64,115 @@ BasicString StringBuilder::Construct(const Char* 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]; +BasicString StringBuilder::FromInt(const char* fmt, int i) { + if (!fmt) return BasicString(0); - if (!ret) return ("-1"); + Char result[sizeof(int64_t)] = {0}; + if (!to_str(result, sizeof(int64_t), i)) return BasicString(0); - memset(ret, 0, ret_len); + const SizeType fmt_len = string_length(fmt); + const SizeType res_len = string_length(result); - Char result[sizeof(int64_t)]; - - if (!to_str(result, sizeof(int64_t), i)) { - delete[] ret; - return ("-1"); - } - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(result); + BasicString output(fmt_len + res_len); + bool inserted = false; for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (auto y_idx = 0; y_idx < res_len; ++y_idx) { - ret[y_idx] = result[result_cnt]; - ++result_cnt; - } - - break; + if (!inserted && fmt[idx] == '%') { + output += result; + inserted = true; + continue; } - - ret[idx] = fmt[idx]; + output += Char{fmt[idx]}; } - return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ + return output; } -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)]; +BasicString StringBuilder::FromBool(const char* fmt, bool val) { + if (!fmt) return BasicString(0); - if (!ret) return ("?"); + const Char* boolean_expr = val ? "true" : "false"; + const SizeType fmt_len = string_length(fmt); + const SizeType res_len = string_length(boolean_expr); - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(boolean_expr); + BasicString output(fmt_len + res_len); + bool inserted = false; 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; + if (!inserted && fmt[idx] == '%') { + output += boolean_expr; + inserted = true; + continue; } - - ret[idx] = fmt[idx]; + output += Char{fmt[idx]}; } - return ret; + return output; } 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; - } + const SizeType lhs_len = string_length(lhs); + const SizeType rhs_len = string_length(rhs); - return true; + if (lhs_len != rhs_len) return false; + return memcmp(lhs, rhs, lhs_len) == 0; } -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 ("?"); +BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { + if (!fmt || !fmtRight) return BasicString(0); - for (SizeType idx = 0; idx < string_length(fmt); ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; + const SizeType fmt_len = string_length(fmt); + const SizeType rhs_len = string_length(fmtRight); - for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { - ret[result_cnt] = fmtRight[y_idx]; - ++result_cnt; - } + BasicString output(fmt_len + rhs_len); + bool inserted = false; - break; + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (!inserted && fmt[idx] == '%') { + output += fmtRight; + inserted = true; + continue; } - - ret[idx] = fmt[idx]; + output += Char{fmt[idx]}; } - return ret; + return output; } BasicString& BasicString::operator+=(const Char* rhs) { - if (strlen(rhs) > this->m_Sz) { + const SizeType rhs_len = strlen(rhs); + if (this->m_Cur + rhs_len >= this->m_Sz) { throw std::runtime_error("out_of_bounds: BasicString"); } - memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); - this->m_Cur += strlen(rhs); + memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); + this->m_Cur += rhs_len; + this->m_Data[this->m_Cur] = '\0'; return *this; } BasicString& BasicString::operator+=(const BasicString& rhs) { - if (rhs.m_Cur > this->m_Sz) { + if (this->m_Cur + rhs.m_Cur >= this->m_Sz) { throw std::runtime_error("out_of_bounds: BasicString"); } - memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); - this->m_Cur += strlen(rhs.CData()); + memcpy(this->m_Data + this->m_Cur, rhs.CData(), rhs.m_Cur); + this->m_Cur += rhs.m_Cur; + this->m_Data[this->m_Cur] = '\0'; return *this; } -} // namespace CompilerKit + +BasicString& BasicString::operator+=(Char ch) { + if (this->m_Cur + 1 >= this->m_Sz) { + // + } + + this->m_Data[this->m_Cur++] = ch; + this->m_Data[this->m_Cur] = '\0'; + + return *this; +} + +} // namespace CompilerKit -- cgit v1.2.3 From a3c60cba463d9df8311e9052101adbacbaa1ce28 Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Wed, 6 Aug 2025 17:52:32 +0300 Subject: Patch BasicString.cc Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- dev/CompilerKit/src/BasicString.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/BasicString.cc b/dev/CompilerKit/src/BasicString.cc index 6ca1e46..dc263aa 100644 --- a/dev/CompilerKit/src/BasicString.cc +++ b/dev/CompilerKit/src/BasicString.cc @@ -166,7 +166,7 @@ BasicString& BasicString::operator+=(const BasicString& rhs) { BasicString& BasicString::operator+=(Char ch) { if (this->m_Cur + 1 >= this->m_Sz) { - // + throw std::runtime_error("out_of_bounds.."); } this->m_Data[this->m_Cur++] = ch; -- cgit v1.2.3 From 3658cb8407814603aceaf2970a5c1016b6c9fdc8 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Wed, 6 Aug 2025 16:41:31 +0100 Subject: feat! breaking API changes before NeKernel.org 0.0.4. Signed-off-by: Amlal El Mahrouss --- MailMap | 2 +- dev/CompilerKit/BasicString.h | 82 -- dev/CompilerKit/CodeGen.h | 206 ----- dev/CompilerKit/Compiler.h | 206 +++++ dev/CompilerKit/Frontend.h | 2 +- dev/CompilerKit/StringKit.h | 83 ++ dev/CompilerKit/ck-osx-san.json | 29 + dev/CompilerKit/ck-osx.json | 24 + dev/CompilerKit/ck-posix.json | 24 + dev/CompilerKit/lc-osx-san.json | 29 - dev/CompilerKit/lc-osx.json | 24 - dev/CompilerKit/lc-posix.json | 24 - dev/CompilerKit/src/AssemblyFactory.cc | 52 ++ dev/CompilerKit/src/Backend/Assembler32x0.cc | 2 +- dev/CompilerKit/src/Backend/Assembler64x0.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerARM64.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerPowerPC.cc | 2 +- dev/CompilerKit/src/BasicString.cc | 178 ---- dev/CompilerKit/src/CodeGen.cc | 52 -- dev/CompilerKit/src/Frontend.cc | 51 -- dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 2 +- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 2 +- dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 2 +- dev/CompilerKit/src/FrontendHelpers.cc | 51 ++ dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 5 +- .../src/Macro/CPlusPlusCompilerPreProcessor.cc | 893 --------------------- dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc | 893 +++++++++++++++++++++ dev/CompilerKit/src/StringKit.cc | 179 +++++ dev/CompilerKit/utils/AsmUtils.h | 3 +- dev/CompilerKit/utils/CompilerUtils.h | 2 +- docs/drawio/COMPILERKIT_DESIGN.drawio | 64 ++ docs/drawio/DEBUGGERKIT_DESIGN.drawio | 47 ++ docs/drawio/LIBCOMPILER_DESIGN.drawio | 64 -- docs/drawio/LIBDEBUGGER_DESIGN.drawio | 47 -- tools/asm.cc | 2 +- tools/dbg.cc | 2 +- tools/kdbg.cc | 2 +- tools/ld64.cc | 2 +- 38 files changed, 1669 insertions(+), 1669 deletions(-) delete mode 100644 dev/CompilerKit/BasicString.h delete mode 100644 dev/CompilerKit/CodeGen.h create mode 100644 dev/CompilerKit/Compiler.h create mode 100644 dev/CompilerKit/StringKit.h create mode 100644 dev/CompilerKit/ck-osx-san.json create mode 100644 dev/CompilerKit/ck-osx.json create mode 100644 dev/CompilerKit/ck-posix.json delete mode 100644 dev/CompilerKit/lc-osx-san.json delete mode 100644 dev/CompilerKit/lc-osx.json delete mode 100644 dev/CompilerKit/lc-posix.json create mode 100644 dev/CompilerKit/src/AssemblyFactory.cc delete mode 100644 dev/CompilerKit/src/BasicString.cc delete mode 100644 dev/CompilerKit/src/CodeGen.cc delete mode 100644 dev/CompilerKit/src/Frontend.cc create mode 100644 dev/CompilerKit/src/FrontendHelpers.cc delete mode 100644 dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc create mode 100644 dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc create mode 100644 dev/CompilerKit/src/StringKit.cc create mode 100644 docs/drawio/COMPILERKIT_DESIGN.drawio create mode 100644 docs/drawio/DEBUGGERKIT_DESIGN.drawio delete mode 100644 docs/drawio/LIBCOMPILER_DESIGN.drawio delete mode 100644 docs/drawio/LIBDEBUGGER_DESIGN.drawio (limited to 'dev/CompilerKit/src') diff --git a/MailMap b/MailMap index 6f36f25..99f9dd1 100644 --- a/MailMap +++ b/MailMap @@ -1 +1 @@ -@amlel-el-mahrouss - amlal@nekernel.org +@amlel-el-mahrouss - amlal@nekernel.org \ No newline at end of file diff --git a/dev/CompilerKit/BasicString.h b/dev/CompilerKit/BasicString.h deleted file mode 100644 index c4cb55a..0000000 --- a/dev/CompilerKit/BasicString.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - * - * ======================================================== - */ - -#pragma once - -#include -#include - -namespace CompilerKit { -class StringBuilder; -class BasicString; - -/** - * @brief BasicString class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - -class BasicString final { - public: - explicit BasicString() = delete; - - explicit BasicString(SizeType Sz) noexcept : m_Sz(Sz) { - m_Data = new Char[Sz]; - assert(m_Data); - } - - ~BasicString() noexcept { - if (m_Data) { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - NECTI_COPY_DEFAULT(BasicString); - - Char* Data(); - const Char* CData() const; - SizeType Length() const; - - bool operator==(const Char* rhs) const; - bool operator!=(const Char* rhs) const; - - bool operator==(const BasicString& rhs) const; - bool operator!=(const BasicString& rhs) const; - - BasicString& operator+=(const Char* rhs); - BasicString& operator+=(const BasicString& 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 be delete[] after they're used. - */ -struct StringBuilder final { - static BasicString Construct(const Char* 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); -}; - -using PStringOr = ErrorOr; -} // namespace CompilerKit diff --git a/dev/CompilerKit/CodeGen.h b/dev/CompilerKit/CodeGen.h deleted file mode 100644 index 99c968b..0000000 --- a/dev/CompilerKit/CodeGen.h +++ /dev/null @@ -1,206 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved - -------------------------------------------- */ - -#pragma once - -#include -#include -#include - -#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface -#define CK_ENCODER : public ::CompilerKit::EncoderInterface - -namespace CompilerKit { -class AssemblyFactory; -class AssemblyInterface; - -/// @brief Simple assembly factory -class AssemblyFactory final { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - NECTI_COPY_DEFAULT(AssemblyFactory); - - public: - enum { - kArchInvalid = 0, - kArchAMD64 = 100, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchAARCH64, - kArchUnknown, - kArchCount = kArchUnknown - kArchAMD64, - }; - - Int32 Compile(std::string sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; -}; - -/// @brief Assembly to binary generator class. -/// @note This interface creates according to the CPU target of the child class. -class AssemblyInterface { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - NECTI_COPY_DEFAULT(AssemblyInterface); - - virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } - - /// @brief compile to object file. - /// @note Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string src, Int32 arch) = 0; -}; - -union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; -}; - -union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) : raw(raw) {} - - ~NumberCast64() { raw = 0; } - - Char number[8]; - UInt64 raw; -}; - -union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) : raw(raw) {} - - ~NumberCast32() { raw = 0; } - - Char number[4]; - UInt32 raw; -}; - -union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) : raw(raw) {} - - ~NumberCast16() { raw = 0; } - - Char number[2]; - UInt16 raw; -}; - -union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) : raw(raw) {} - - ~NumberCast8() { raw = 0; } - - Char number; - UInt8 raw; -}; - -class EncoderInterface { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - NECTI_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string line, std::string file) = 0; - virtual bool WriteLine(std::string line, 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; - - NECTI_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, 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_ARM64__ - -class EncoderARM64 final : public EncoderInterface { - public: - explicit EncoderARM64() = default; - ~EncoderARM64() override = default; - - NECTI_COPY_DEFAULT(EncoderARM64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_ARM64__ - -#ifdef __ASM_NEED_64x0__ - -class Encoder64x0 final : public EncoderInterface { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - NECTI_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, 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; - - NECTI_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, 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; - - NECTI_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, 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/dev/CompilerKit/Compiler.h b/dev/CompilerKit/Compiler.h new file mode 100644 index 0000000..60d63ff --- /dev/null +++ b/dev/CompilerKit/Compiler.h @@ -0,0 +1,206 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +#pragma once + +#include +#include +#include + +#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface +#define CK_ENCODER : public ::CompilerKit::EncoderInterface + +namespace CompilerKit { +class AssemblyFactory; +class AssemblyInterface; + +/// @brief Simple assembly factory +class AssemblyFactory final { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + NECTI_COPY_DEFAULT(AssemblyFactory); + + public: + enum { + kArchInvalid = 0, + kArchAMD64 = 100, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchAARCH64, + kArchUnknown, + kArchCount = kArchUnknown - kArchAMD64, + }; + + Int32 Compile(std::string sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; +}; + +/// @brief Assembly to binary generator class. +/// @note This interface creates according to the CPU target of the child class. +class AssemblyInterface { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + NECTI_COPY_DEFAULT(AssemblyInterface); + + virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } + + /// @brief compile to object file. + /// @note Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string src, Int32 arch) = 0; +}; + +union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; +}; + +union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) : raw(raw) {} + + ~NumberCast64() { raw = 0; } + + Char number[8]; + UInt64 raw; +}; + +union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) : raw(raw) {} + + ~NumberCast32() { raw = 0; } + + Char number[4]; + UInt32 raw; +}; + +union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) : raw(raw) {} + + ~NumberCast16() { raw = 0; } + + Char number[2]; + UInt16 raw; +}; + +union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) : raw(raw) {} + + ~NumberCast8() { raw = 0; } + + Char number; + UInt8 raw; +}; + +class EncoderInterface { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + NECTI_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string line, std::string file) = 0; + virtual bool WriteLine(std::string line, 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; + + NECTI_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, 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_ARM64__ + +class EncoderARM64 final : public EncoderInterface { + public: + explicit EncoderARM64() = default; + ~EncoderARM64() override = default; + + NECTI_COPY_DEFAULT(EncoderARM64); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; + +#endif // __ASM_NEED_ARM64__ + +#ifdef __ASM_NEED_64x0__ + +class Encoder64x0 final : public EncoderInterface { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + NECTI_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, 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; + + NECTI_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, 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; + + NECTI_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, 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/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h index baf00d9..4719c3d 100644 --- a/dev/CompilerKit/Frontend.h +++ b/dev/CompilerKit/Frontend.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #define CK_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface diff --git a/dev/CompilerKit/StringKit.h b/dev/CompilerKit/StringKit.h new file mode 100644 index 0000000..18b3ad8 --- /dev/null +++ b/dev/CompilerKit/StringKit.h @@ -0,0 +1,83 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +#pragma once + +#include +#include + +namespace CompilerKit { +class StringBuilder; +class BasicString; + +/** + * @brief BasicString class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + +class BasicString final { + public: + explicit BasicString() = delete; + + explicit BasicString(SizeType Sz) noexcept : m_Sz(Sz) { + m_Data = new Char[Sz]; + assert(m_Data); + } + + ~BasicString() noexcept { + if (m_Data) { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + NECTI_COPY_DEFAULT(BasicString); + + Char* Data(); + const Char* CData() const; + SizeType Length() const; + + bool operator==(const Char* rhs) const; + bool operator!=(const Char* rhs) const; + + bool operator==(const BasicString& rhs) const; + bool operator!=(const BasicString& rhs) const; + + BasicString& operator+=(const Char* rhs); + BasicString& operator+=(const Char rhs); + BasicString& operator+=(const BasicString& 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 be delete[] after they're used. + */ +struct StringBuilder final { + static BasicString Construct(const Char* data); + static BasicString FromInt(const char* fmt, int n); + static BasicString FromBool(const char* fmt, bool n); + static BasicString Format(const char* fmt, const char* from); + static BOOL Equals(const char* lhs, const char* rhs); +}; + +using BasicStringOr = ErrorOr; +} // namespace CompilerKit diff --git a/dev/CompilerKit/ck-osx-san.json b/dev/CompilerKit/ck-osx-san.json new file mode 100644 index 0000000..f190db2 --- /dev/null +++ b/dev/CompilerKit/ck-osx-san.json @@ -0,0 +1,29 @@ +{ + "compiler_path": "clang++", + "compiler_std": "c++20", + "headers_path": [ + "../CompilerKit", + "../", + "../CompilerKit/src/", + "../CompilerKit/src/impl" + ], + "sources_path": [ + "src/*.cc", + "src/*/*.cc" + ], + "output_name": "/usr/local/lib/libCompilerKit.dylib", + "compiler_flags": [ + "-fPIC", + "-shared", + "-fstack-protector-all", + "-fno-omit-frame-pointer", + "-g", + "-fsanitize=address", + "-fsanitize=undefined" + ], + "cpp_macros": [ + "__NECTI__=202505", + "CK_USE_STRUCTS=1", + "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" + ] +} \ No newline at end of file diff --git a/dev/CompilerKit/ck-osx.json b/dev/CompilerKit/ck-osx.json new file mode 100644 index 0000000..4880763 --- /dev/null +++ b/dev/CompilerKit/ck-osx.json @@ -0,0 +1,24 @@ +{ + "compiler_path": "clang++", + "compiler_std": "c++20", + "headers_path": [ + "../CompilerKit", + "../", + "../CompilerKit/src/", + "../CompilerKit/src/impl" + ], + "sources_path": [ + "src/*.cc", + "src/*/*.cc" + ], + "output_name": "/usr/local/lib/libCompilerKit.dylib", + "compiler_flags": [ + "-fPIC", + "-shared" + ], + "cpp_macros": [ + "__NECTI__=202505", + "CK_USE_STRUCTS=1", + "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" + ] +} \ No newline at end of file diff --git a/dev/CompilerKit/ck-posix.json b/dev/CompilerKit/ck-posix.json new file mode 100644 index 0000000..e80ce65 --- /dev/null +++ b/dev/CompilerKit/ck-posix.json @@ -0,0 +1,24 @@ +{ + "compiler_path": "g++", + "compiler_std": "c++20", + "headers_path": [ + "../CompilerKit", + "../", + "../CompilerKit/src/", + "../CompilerKit/src/impl" + ], + "sources_path": [ + "src/*.cc", + "src/*/*.cc" + ], + "output_name": "/usr/local/lib/libCompilerKit.so", + "compiler_flags": [ + "-fPIC", + "-shared" + ], + "cpp_macros": [ + "__NECTI__=202505", + "CK_USE_STRUCTS=1", + "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" + ] +} \ No newline at end of file diff --git a/dev/CompilerKit/lc-osx-san.json b/dev/CompilerKit/lc-osx-san.json deleted file mode 100644 index f190db2..0000000 --- a/dev/CompilerKit/lc-osx-san.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared", - "-fstack-protector-all", - "-fno-omit-frame-pointer", - "-g", - "-fsanitize=address", - "-fsanitize=undefined" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} \ No newline at end of file diff --git a/dev/CompilerKit/lc-osx.json b/dev/CompilerKit/lc-osx.json deleted file mode 100644 index 4880763..0000000 --- a/dev/CompilerKit/lc-osx.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} \ No newline at end of file diff --git a/dev/CompilerKit/lc-posix.json b/dev/CompilerKit/lc-posix.json deleted file mode 100644 index e80ce65..0000000 --- a/dev/CompilerKit/lc-posix.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compiler_path": "g++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.so", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} \ No newline at end of file diff --git a/dev/CompilerKit/src/AssemblyFactory.cc b/dev/CompilerKit/src/AssemblyFactory.cc new file mode 100644 index 0000000..1f08b32 --- /dev/null +++ b/dev/CompilerKit/src/AssemblyFactory.cc @@ -0,0 +1,52 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +#include +#include + +/** + * @file AssemblyFactory.cc + * @author Amlal El Mahrouss (amlal@nekernel.org) + * @brief Compiler API of NeCTI + * @version 0.0.2 + * + * @copyright Copyright (c) 2024-2025 Amlal El Mahrouss + * + */ + +namespace CompilerKit { +///! @brief Compile for specific format (ELF, PEF, ZBIN) +Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { + if (sourceFile.length() < 1) return NECTI_UNIMPLEMENTED; + + if (!fMounted) return NECTI_UNIMPLEMENTED; + if (arch != fMounted->Arch()) return NECTI_INVALID_ARCH; + + try { + return this->fMounted->CompileToFormat(sourceFile, arch); + } catch (std::exception& e) { + return NECTI_EXEC_ERROR; + } +} + +///! @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 (fMounted) { + fMounted = nullptr; + } + + return mount_prev; +} +} // namespace CompilerKit diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc index bc52d25..a7cb022 100644 --- a/dev/CompilerKit/src/Backend/Assembler32x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler32x0.cc @@ -8,7 +8,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// -// @file 32asm.cxx +// @file 32asm.cc // @author EL Mahrouss Amlal // @brief 32x0 Assembler. diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc index 511c64d..6bc8842 100644 --- a/dev/CompilerKit/src/Backend/Assembler64x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler64x0.cc @@ -8,7 +8,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// -// @file Assembler64x0.cxx +// @file Assembler64x0.cc // @author EL Mahrouss Amlal // @brief 64x000 Assembler. diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc index 6890b2c..331e708 100644 --- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerARM64.cc @@ -6,7 +6,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// -/// @file AssemblerARM64.cxx +/// @file AssemblerARM64.cc /// @author EL Mahrouss Amlal /// @brief 'ACORN' Assembler. diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc index b02a112..bbb5a8b 100644 --- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc +++ b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc @@ -6,7 +6,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// -/// @file AssemblerPower.cxx +/// @file AssemblerPower.cc /// @author EL Mahrouss Amlal /// @brief POWER Assembler. diff --git a/dev/CompilerKit/src/BasicString.cc b/dev/CompilerKit/src/BasicString.cc deleted file mode 100644 index dc263aa..0000000 --- a/dev/CompilerKit/src/BasicString.cc +++ /dev/null @@ -1,178 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - * - * ======================================================== - */ - -/** - * @file BasicString.cc - * @author Amlal (amlal@nekernel.org) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) Amlal El Mahrouss - * - */ - -#include - -namespace CompilerKit { - -Char* BasicString::Data() { - return m_Data; -} - -const Char* BasicString::CData() const { - return m_Data; -} - -SizeType BasicString::Length() const { - return strlen(m_Data); -} - -bool BasicString::operator==(const BasicString& rhs) const { - const SizeType len = Length(); - if (rhs.Length() != len) return false; - return memcmp(m_Data, rhs.m_Data, len) == 0; -} - -bool BasicString::operator==(const Char* rhs) const { - const SizeType rhs_len = string_length(rhs); - const SizeType len = Length(); - if (rhs_len != len) return false; - return memcmp(m_Data, rhs, len) == 0; -} - -bool BasicString::operator!=(const BasicString& rhs) const { - return !(*this == rhs); -} - -bool BasicString::operator!=(const Char* rhs) const { - return !(*this == rhs); -} - -BasicString StringBuilder::Construct(const Char* data) { - if (!data || *data == 0) return BasicString(0); - - BasicString view(strlen(data)); - view += data; - - return view; -} - -BasicString StringBuilder::FromInt(const char* fmt, int i) { - if (!fmt) return BasicString(0); - - Char result[sizeof(int64_t)] = {0}; - if (!to_str(result, sizeof(int64_t), i)) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(result); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += result; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString StringBuilder::FromBool(const char* fmt, bool val) { - if (!fmt) return BasicString(0); - - const Char* boolean_expr = val ? "true" : "false"; - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(boolean_expr); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += boolean_expr; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -bool StringBuilder::Equals(const char* lhs, const char* rhs) { - const SizeType lhs_len = string_length(lhs); - const SizeType rhs_len = string_length(rhs); - - if (lhs_len != rhs_len) return false; - return memcmp(lhs, rhs, lhs_len) == 0; -} - -BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { - if (!fmt || !fmtRight) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType rhs_len = string_length(fmtRight); - - BasicString output(fmt_len + rhs_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += fmtRight; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString& BasicString::operator+=(const Char* rhs) { - const SizeType rhs_len = strlen(rhs); - if (this->m_Cur + rhs_len >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); - this->m_Cur += rhs_len; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(const BasicString& rhs) { - if (this->m_Cur + rhs.m_Cur >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), rhs.m_Cur); - this->m_Cur += rhs.m_Cur; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(Char ch) { - if (this->m_Cur + 1 >= this->m_Sz) { - throw std::runtime_error("out_of_bounds.."); - } - - this->m_Data[this->m_Cur++] = ch; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -} // namespace CompilerKit diff --git a/dev/CompilerKit/src/CodeGen.cc b/dev/CompilerKit/src/CodeGen.cc deleted file mode 100644 index 693d7a5..0000000 --- a/dev/CompilerKit/src/CodeGen.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved - -------------------------------------------- */ - -#include -#include - -/** - * @file CodeGen.cc - * @author Amlal El Mahrouss (amlal@nekernel.org) - * @brief CodeGen API of NeCTI - * @version 0.0.2 - * - * @copyright Copyright (c) 2024-2025 Amlal El Mahrouss - * - */ - -namespace CompilerKit { -///! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { - if (sourceFile.length() < 1) return NECTI_UNIMPLEMENTED; - - if (!fMounted) return NECTI_UNIMPLEMENTED; - if (arch != fMounted->Arch()) return NECTI_INVALID_ARCH; - - try { - return this->fMounted->CompileToFormat(sourceFile, arch); - } catch (std::exception& e) { - return NECTI_EXEC_ERROR; - } -} - -///! @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 (fMounted) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit diff --git a/dev/CompilerKit/src/Frontend.cc b/dev/CompilerKit/src/Frontend.cc deleted file mode 100644 index 37b36f7..0000000 --- a/dev/CompilerKit/src/Frontend.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* ------------------------------------------- - - Copyright (C) 2025 Amlal EL Mahrouss, all rights reserved - -------------------------------------------- */ - -#include - -namespace CompilerKit { -/// 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. -BOOL find_word(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::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. -SizeType find_word_range(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::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 STLString::npos; -} -} // namespace CompilerKit \ No newline at end of file diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc index 6ee7e32..1221521 100644 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc @@ -28,7 +28,7 @@ /* (c) Amlal El Mahrouss */ /// @author EL Mahrouss Amlal (amlel) -/// @file 64x0-cc.cxx +/// @file 64x0-cc.cc /// @brief 64x0 C Compiler. /// TODO: support structures, else if, else, . and -> diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc index 1c1582f..6795c67 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -29,7 +29,7 @@ /* (c) Amlal El Mahrouss */ /// @author EL Mahrouss Amlal (amlel) -/// @file ARM64-cc.cxx +/// @file ARM64-cc.cc /// @brief ARM64 C Compiler. /// TODO: support structures, else if, else, . and -> diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc index 40598c9..1999f48 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc @@ -23,7 +23,7 @@ #define kExitOK 0 /// @author EL Mahrouss Amlal (amlal@nekernel.org) -/// @file cc.cxx +/// @file cc.cc /// @brief POWER64 C Compiler. ///////////////////// diff --git a/dev/CompilerKit/src/FrontendHelpers.cc b/dev/CompilerKit/src/FrontendHelpers.cc new file mode 100644 index 0000000..37b36f7 --- /dev/null +++ b/dev/CompilerKit/src/FrontendHelpers.cc @@ -0,0 +1,51 @@ +/* ------------------------------------------- + + Copyright (C) 2025 Amlal EL Mahrouss, all rights reserved + +------------------------------------------- */ + +#include + +namespace CompilerKit { +/// 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. +BOOL find_word(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::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. +SizeType find_word_range(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::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 STLString::npos; +} +} // namespace CompilerKit \ No newline at end of file diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 0aa2b78..394014c 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -317,7 +317,6 @@ NECTI_MODULE(DynamicLinker64PEF) { if (kVerbose) { kConsoleOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; - kConsoleOut << "Offset: " << command_header.Offset << "\n"; } @@ -660,7 +659,7 @@ NECTI_MODULE(DynamicLinker64PEF) { if ((!kStartFound || kDuplicateSymbols) && (std::filesystem::exists(kOutput) || !unreferenced_symbols.empty())) { if (kVerbose) { - kConsoleOut << "File: " << kOutput << ", is corrupt, removing file...\n"; + kConsoleOut << "File: " << kOutput << " is corrupt now...\n"; } return NECTI_EXEC_ERROR; diff --git a/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc deleted file mode 100644 index 9845967..0000000 --- a/dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc +++ /dev/null @@ -1,893 +0,0 @@ -/* - * ======================================================== - * - * C++ Preprocessor Driver - * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include -#include -#include -#include -#include -#include -#include -#include - -#define kMacroPrefix '#' - -/// @author EL Mahrouss Amlal (amlel) -/// @file bpp.cxx -/// @brief Preprocessor. - -typedef Int32 (*bpp_parser_fn_t)(CompilerKit::STLString& line, std::ifstream& hdr_file, - std::ofstream& pp_out); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Preprocessor internal types. - -///////////////////////////////////////////////////////////////////////////////////////// - -namespace Detail { -enum { - kInvalid = 0, - kEqual = 100, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, - kCount = 6, -}; - -struct bpp_macro_condition final { - int32_t fType; - CompilerKit::STLString fTypeName; - - void Print() { - std::cout << "type: " << fType << "\n"; - std::cout << "type_name: " << fTypeName << "\n"; - } -}; - -struct bpp_macro final { - std::vector fArgs; - CompilerKit::STLString fName; - CompilerKit::STLString fValue; - - void Print() { - std::cout << "name: " << fName << "\n"; - std::cout << "value: " << fValue << "\n"; - - for (auto& arg : fArgs) { - std::cout << "arg: " << arg << "\n"; - } - } -}; -} // namespace Detail - -static std::vector kFiles; -static std::vector kMacros; -static std::vector kIncludes; - -static CompilerKit::STLString kWorkingDir = ""; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_if_condition -// @brief parse #if condition - -///////////////////////////////////////////////////////////////////////////////////////// - -int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, - bool& inactive_code, bool& defined, - CompilerKit::STLString& macro_str) { - if (cond.fType == Detail::kEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { - if (macro.fValue == "0") { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } else if (cond.fType == Detail::kNotEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != CompilerKit::STLString::npos) { - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::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()); - - CompilerKit::STLString number; - - for (auto& macro_num : kMacros) { - if (substr_macro.find(macro_num.fName) != CompilerKit::STLString::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 == Detail::kGreaterThan) { - if (lhs < rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kGreaterEqThan) { - if (lhs <= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kLesserEqThan) { - if (lhs >= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::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) { - CompilerKit::STLString hdr_line; - CompilerKit::STLString line_after_include; - - bool inactive_code = false; - bool defined = false; - - try { - while (std::getline(hdr_file, hdr_line)) { - if (inactive_code) { - if (hdr_line.find("#endif") == CompilerKit::STLString::npos) { - continue; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("#endif") != CompilerKit::STLString::npos) { - inactive_code = false; - } - } - - if (hdr_line.find("*/") != CompilerKit::STLString::npos) { - hdr_line.erase(hdr_line.find("*/"), strlen("*/")); - } - - if (hdr_line.find("/*") != CompilerKit::STLString::npos) { - inactive_code = true; - - // get rid of comment. - hdr_line.erase(hdr_line.find("/*")); - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != CompilerKit::STLString::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)) { - if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != - CompilerKit::STLString::npos) { - if (!macro.fArgs.empty()) { - CompilerKit::STLString symbol_val = macro.fValue; - std::vector args; - - size_t x_arg_indx = 0; - - CompilerKit::STLString line_after_define = hdr_line; - CompilerKit::STLString str_arg; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ' ' || subc == '\t') continue; - - if (subc == ',' || subc == ')') { - if (str_arg.empty()) continue; - - args.push_back(str_arg); - - str_arg.clear(); - - continue; - } - - str_arg.push_back(subc); - } - } - - for (auto arg : macro.fArgs) { - if (symbol_val.find(macro.fArgs[x_arg_indx]) != CompilerKit::STLString::npos) { - symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), - macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); - ++x_arg_indx; - } else { - throw std::runtime_error("cppdrv: Internal error."); - } - } - - auto len = macro.fName.size(); - len += symbol_val.size(); - len += 2; // ( and ) - - hdr_line.erase(hdr_line.find(")"), 1); - - hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), - len, symbol_val); - } else { - auto value = macro.fValue; - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), value); - } - } - } - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("define ") != CompilerKit::STLString::npos) { - auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); - - CompilerKit::STLString macro_value; - CompilerKit::STLString 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; - } - - CompilerKit::STLString str; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ',' || subc == ')') { - if (str.empty()) continue; - - args.push_back(str); - - str.clear(); - - continue; - } - - str.push_back(subc); - } - } - - Detail::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; - } - - pp_out << hdr_line << std::endl; - - continue; - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifndef") != CompilerKit::STLString::npos) { - auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - CompilerKit::STLString 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& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - found = true; - break; - } - } - - if (found) { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != CompilerKit::STLString::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") != CompilerKit::STLString::npos) { - auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - CompilerKit::STLString 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& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - defined = true; - inactive_code = false; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != CompilerKit::STLString::npos) { - inactive_code = true; - - std::vector bpp_macro_condition_list = { - { - .fType = Detail::kEqual, - .fTypeName = "==", - }, - { - .fType = Detail::kNotEqual, - .fTypeName = "!=", - }, - { - .fType = Detail::kLesserThan, - .fTypeName = "<", - }, - { - .fType = Detail::kGreaterThan, - .fTypeName = ">", - }, - { - .fType = Detail::kLesserEqThan, - .fTypeName = "<=", - }, - { - .fType = Detail::kGreaterEqThan, - .fTypeName = ">=", - }, - }; - - int32_t good_to_go = 0; - - for (auto& macro_condition : bpp_macro_condition_list) { - if (hdr_line.find(macro_condition.fTypeName) != CompilerKit::STLString::npos) { - for (auto& found_macro : kMacros) { - if (hdr_line.find(found_macro.fName) != CompilerKit::STLString::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); - CompilerKit::STLString 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& macro_ref : kMacros) { - if (macro_ref.fName.find(macro) != CompilerKit::STLString::npos && - macro_ref.fValue == "1") { - inactive_code = false; - defined = true; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - CompilerKit::STLString message; - - for (auto& ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - std::cout << "warn: " << message << std::endl; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - CompilerKit::STLString 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("include ") != CompilerKit::STLString::npos) { - line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); - - if (it != kAllIncludes.cend()) { - continue; - } - - CompilerKit::STLString 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 == '\"') { - not_local = false; - enable = true; - continue; - } - - if (enable) { - path += ch; - } - } - - if (not_local) { - bool open = false; - - if (path.ends_with('>')) { - path.erase(path.find('>')); - } - - if (path.ends_with('"')) { - path.erase(path.find('"')); - } - - for (auto& include : kIncludes) { - CompilerKit::STLString 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("cppdrv: no such include file: " + path); - } - } else { - std::ifstream header(path); - - if (!header.is_open()) throw std::runtime_error("cppdrv: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } else { - std::cerr << ("cppdrv: unknown pre-processor directive, " + hdr_line) << "\n"; - continue; - } - } - } catch (std::out_of_range& oor) { - return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief main entrypoint of app. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(CPlusPlusPreprocessorMain) { - try { - bool skip = false; - bool double_skip = false; - - Detail::bpp_macro macro_1; - - macro_1.fName = "__true"; - macro_1.fValue = "1"; - - kMacros.push_back(macro_1); - - Detail::bpp_macro macro_unreachable; - - macro_unreachable.fName = "__unreachable"; - macro_unreachable.fValue = "__libcompiler_unreachable"; - - kMacros.push_back(macro_unreachable); - - Detail::bpp_macro macro_unused; - - macro_unreachable.fName = "__unused"; - macro_unreachable.fValue = "__libcompiler_unused"; - - kMacros.push_back(macro_unused); - - Detail::bpp_macro macro_0; - - macro_0.fName = "__false"; - macro_0.fValue = "0"; - - kMacros.push_back(macro_0); - - Detail::bpp_macro macro_zka; - - macro_zka.fName = "__NECTI__"; - macro_zka.fValue = "1"; - - kMacros.push_back(macro_zka); - - Detail::bpp_macro macro_cxx; - - macro_cxx.fName = "__cplusplus"; - macro_cxx.fValue = "202302L"; - - kMacros.push_back(macro_cxx); - - Detail::bpp_macro macro_size_t; - macro_size_t.fName = "__SIZE_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINT32_TYPE__"; - macro_size_t.fValue = "unsigned int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINTPTR_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - 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], "-cpp-ver") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-help") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - printf("%s\n", "-cpp-working-dir : set directory to working path."); - printf("%s\n", "-cpp-include-dir : add directory to include path."); - printf("%s\n", "-cpp-def : define a macro."); - printf("%s\n", "-cpp-ver: print the version."); - printf("%s\n", "-cpp-help: show help (this current command)."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-include-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - - skip = true; - - kIncludes.push_back(inc); - } - - if (strcmp(argv[index], "-cpp-working-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } - - if (strcmp(argv[index], "-cpp-def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) { - CompilerKit::STLString macro_key = argv[index + 1]; - - CompilerKit::STLString 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 += "\""; - - Detail::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 NECTI_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 NECTI_SUCCESS; - } catch (const std::runtime_error& e) { - std::cout << e.what() << '\n'; - } - - return NECTI_EXEC_ERROR; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc new file mode 100644 index 0000000..aaa5793 --- /dev/null +++ b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc @@ -0,0 +1,893 @@ +/* + * ======================================================== + * + * C++ Preprocessor Driver + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define kMacroPrefix '#' + +/// @author EL Mahrouss Amlal (amlel) +/// @file CPlusPlusPreprocessor.cc +/// @brief Preprocessor. + +typedef Int32 (*bpp_parser_fn_t)(CompilerKit::STLString& line, std::ifstream& hdr_file, + std::ofstream& pp_out); + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Preprocessor internal types. + +///////////////////////////////////////////////////////////////////////////////////////// + +namespace Detail { +enum { + kInvalid = 0, + kEqual = 100, + kGreaterEqThan, + kLesserEqThan, + kGreaterThan, + kLesserThan, + kNotEqual, + kCount = 6, +}; + +struct bpp_macro_condition final { + int32_t fType; + CompilerKit::STLString fTypeName; + + void Print() { + std::cout << "type: " << fType << "\n"; + std::cout << "type_name: " << fTypeName << "\n"; + } +}; + +struct bpp_macro final { + std::vector fArgs; + CompilerKit::STLString fName; + CompilerKit::STLString fValue; + + void Print() { + std::cout << "name: " << fName << "\n"; + std::cout << "value: " << fValue << "\n"; + + for (auto& arg : fArgs) { + std::cout << "arg: " << arg << "\n"; + } + } +}; +} // namespace Detail + +static std::vector kFiles; +static std::vector kMacros; +static std::vector kIncludes; + +static CompilerKit::STLString kWorkingDir = ""; + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name bpp_parse_if_condition +// @brief parse #if condition + +///////////////////////////////////////////////////////////////////////////////////////// + +int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, + bool& inactive_code, bool& defined, + CompilerKit::STLString& macro_str) { + if (cond.fType == Detail::kEqual) { + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { + if (macro.fValue == "0") { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + } else if (cond.fType == Detail::kNotEqual) { + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fName) != CompilerKit::STLString::npos) { + if (substr_macro.find(macro.fValue) != CompilerKit::STLString::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()); + + CompilerKit::STLString number; + + for (auto& macro_num : kMacros) { + if (substr_macro.find(macro_num.fName) != CompilerKit::STLString::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 == Detail::kGreaterThan) { + if (lhs < rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::kGreaterEqThan) { + if (lhs <= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::kLesserEqThan) { + if (lhs >= rhs) { + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + if (cond.fType == Detail::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) { + CompilerKit::STLString hdr_line; + CompilerKit::STLString line_after_include; + + bool inactive_code = false; + bool defined = false; + + try { + while (std::getline(hdr_file, hdr_line)) { + if (inactive_code) { + if (hdr_line.find("#endif") == CompilerKit::STLString::npos) { + continue; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("#endif") != CompilerKit::STLString::npos) { + inactive_code = false; + } + } + + if (hdr_line.find("*/") != CompilerKit::STLString::npos) { + hdr_line.erase(hdr_line.find("*/"), strlen("*/")); + } + + if (hdr_line.find("/*") != CompilerKit::STLString::npos) { + inactive_code = true; + + // get rid of comment. + hdr_line.erase(hdr_line.find("/*")); + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != CompilerKit::STLString::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)) { + if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != + CompilerKit::STLString::npos) { + if (!macro.fArgs.empty()) { + CompilerKit::STLString symbol_val = macro.fValue; + std::vector args; + + size_t x_arg_indx = 0; + + CompilerKit::STLString line_after_define = hdr_line; + CompilerKit::STLString str_arg; + + if (line_after_define.find("(") != CompilerKit::STLString::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ' ' || subc == '\t') continue; + + if (subc == ',' || subc == ')') { + if (str_arg.empty()) continue; + + args.push_back(str_arg); + + str_arg.clear(); + + continue; + } + + str_arg.push_back(subc); + } + } + + for (auto arg : macro.fArgs) { + if (symbol_val.find(macro.fArgs[x_arg_indx]) != CompilerKit::STLString::npos) { + symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), + macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); + ++x_arg_indx; + } else { + throw std::runtime_error("cppdrv: Internal error."); + } + } + + auto len = macro.fName.size(); + len += symbol_val.size(); + len += 2; // ( and ) + + hdr_line.erase(hdr_line.find(")"), 1); + + hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), + len, symbol_val); + } else { + auto value = macro.fValue; + + hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), value); + } + } + } + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("define ") != CompilerKit::STLString::npos) { + auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); + + CompilerKit::STLString macro_value; + CompilerKit::STLString 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; + } + + CompilerKit::STLString str; + + if (line_after_define.find("(") != CompilerKit::STLString::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ',' || subc == ')') { + if (str.empty()) continue; + + args.push_back(str); + + str.clear(); + + continue; + } + + str.push_back(subc); + } + } + + Detail::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; + } + + pp_out << hdr_line << std::endl; + + continue; + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifndef") != CompilerKit::STLString::npos) { + auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { + found = true; + break; + } + } + + if (found) { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("else") != CompilerKit::STLString::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") != CompilerKit::STLString::npos) { + auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { + defined = true; + inactive_code = false; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("if") != CompilerKit::STLString::npos) { + inactive_code = true; + + std::vector bpp_macro_condition_list = { + { + .fType = Detail::kEqual, + .fTypeName = "==", + }, + { + .fType = Detail::kNotEqual, + .fTypeName = "!=", + }, + { + .fType = Detail::kLesserThan, + .fTypeName = "<", + }, + { + .fType = Detail::kGreaterThan, + .fTypeName = ">", + }, + { + .fType = Detail::kLesserEqThan, + .fTypeName = "<=", + }, + { + .fType = Detail::kGreaterEqThan, + .fTypeName = ">=", + }, + }; + + int32_t good_to_go = 0; + + for (auto& macro_condition : bpp_macro_condition_list) { + if (hdr_line.find(macro_condition.fTypeName) != CompilerKit::STLString::npos) { + for (auto& found_macro : kMacros) { + if (hdr_line.find(found_macro.fName) != CompilerKit::STLString::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); + CompilerKit::STLString 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& macro_ref : kMacros) { + if (macro_ref.fName.find(macro) != CompilerKit::STLString::npos && + macro_ref.fValue == "1") { + inactive_code = false; + defined = true; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("warning") != CompilerKit::STLString::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); + CompilerKit::STLString message; + + for (auto& ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + std::cout << "warn: " << message << std::endl; + } else if (hdr_line[0] == kMacroPrefix && + hdr_line.find("error") != CompilerKit::STLString::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); + CompilerKit::STLString 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("include ") != CompilerKit::STLString::npos) { + line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); + + kIncludeFile: + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); + + if (it != kAllIncludes.cend()) { + continue; + } + + CompilerKit::STLString 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 == '\"') { + not_local = false; + enable = true; + continue; + } + + if (enable) { + path += ch; + } + } + + if (not_local) { + bool open = false; + + if (path.ends_with('>')) { + path.erase(path.find('>')); + } + + if (path.ends_with('"')) { + path.erase(path.find('"')); + } + + for (auto& include : kIncludes) { + CompilerKit::STLString 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("cppdrv: no such include file: " + path); + } + } else { + std::ifstream header(path); + + if (!header.is_open()) throw std::runtime_error("cppdrv: no such include file: " + path); + + bpp_parse_file(header, pp_out); + } + } else { + std::cerr << ("cppdrv: unknown pre-processor directive, " + hdr_line) << "\n"; + continue; + } + } + } catch (std::out_of_range& oor) { + return; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief main entrypoint of app. + +///////////////////////////////////////////////////////////////////////////////////////// + +NECTI_MODULE(CPlusPlusPreprocessorMain) { + try { + bool skip = false; + bool double_skip = false; + + Detail::bpp_macro macro_1; + + macro_1.fName = "__true"; + macro_1.fValue = "1"; + + kMacros.push_back(macro_1); + + Detail::bpp_macro macro_unreachable; + + macro_unreachable.fName = "__unreachable"; + macro_unreachable.fValue = "__libcompiler_unreachable"; + + kMacros.push_back(macro_unreachable); + + Detail::bpp_macro macro_unused; + + macro_unreachable.fName = "__unused"; + macro_unreachable.fValue = "__libcompiler_unused"; + + kMacros.push_back(macro_unused); + + Detail::bpp_macro macro_0; + + macro_0.fName = "__false"; + macro_0.fValue = "0"; + + kMacros.push_back(macro_0); + + Detail::bpp_macro macro_zka; + + macro_zka.fName = "__NECTI__"; + macro_zka.fValue = "1"; + + kMacros.push_back(macro_zka); + + Detail::bpp_macro macro_cxx; + + macro_cxx.fName = "__cplusplus"; + macro_cxx.fValue = "202302L"; + + kMacros.push_back(macro_cxx); + + Detail::bpp_macro macro_size_t; + macro_size_t.fName = "__SIZE_TYPE__"; + macro_size_t.fValue = "unsigned long long int"; + + kMacros.push_back(macro_size_t); + + macro_size_t.fName = "__UINT32_TYPE__"; + macro_size_t.fValue = "unsigned int"; + + kMacros.push_back(macro_size_t); + + macro_size_t.fName = "__UINTPTR_TYPE__"; + macro_size_t.fValue = "unsigned long long int"; + + kMacros.push_back(macro_size_t); + + 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], "-cpp-ver") == 0) { + printf("%s\n", + "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " + "reserved."); + + return NECTI_SUCCESS; + } + + if (strcmp(argv[index], "-cpp-help") == 0) { + printf("%s\n", + "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " + "reserved."); + printf("%s\n", "-cpp-working-dir : set directory to working path."); + printf("%s\n", "-cpp-include-dir : add directory to include path."); + printf("%s\n", "-cpp-def : define a macro."); + printf("%s\n", "-cpp-ver: print the version."); + printf("%s\n", "-cpp-help: show help (this current command)."); + + return NECTI_SUCCESS; + } + + if (strcmp(argv[index], "-cpp-include-dir") == 0) { + CompilerKit::STLString inc = argv[index + 1]; + + skip = true; + + kIncludes.push_back(inc); + } + + if (strcmp(argv[index], "-cpp-working-dir") == 0) { + CompilerKit::STLString inc = argv[index + 1]; + skip = true; + kWorkingDir = inc; + } + + if (strcmp(argv[index], "-cpp-def") == 0 && argv[index + 1] != nullptr && + argv[index + 2] != nullptr) { + CompilerKit::STLString macro_key = argv[index + 1]; + + CompilerKit::STLString 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 += "\""; + + Detail::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 NECTI_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 NECTI_SUCCESS; + } catch (const std::runtime_error& e) { + std::cout << e.what() << '\n'; + } + + return NECTI_EXEC_ERROR; +} + +// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/StringKit.cc b/dev/CompilerKit/src/StringKit.cc new file mode 100644 index 0000000..13142a6 --- /dev/null +++ b/dev/CompilerKit/src/StringKit.cc @@ -0,0 +1,179 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + * + * ======================================================== + */ + +/** + * @file BasicString.cc + * @author Amlal (amlal@nekernel.org) + * @brief C++ string manipulation API. + * @version 0.2 + * @date 2024-01-23 + * + * @copyright Copyright (c) Amlal El Mahrouss + * + */ + +#include + +namespace CompilerKit { + +Char* BasicString::Data() { + return m_Data; +} + +const Char* BasicString::CData() const { + return m_Data; +} + +SizeType BasicString::Length() const { + return strlen(m_Data); +} + +bool BasicString::operator==(const BasicString& rhs) const { + const SizeType len = Length(); + if (rhs.Length() != len) return false; + return memcmp(m_Data, rhs.m_Data, len) == 0; +} + +bool BasicString::operator==(const Char* rhs) const { + const SizeType rhs_len = string_length(rhs); + const SizeType len = Length(); + if (rhs_len != len) return false; + return memcmp(m_Data, rhs, len) == 0; +} + +bool BasicString::operator!=(const BasicString& rhs) const { + return !(*this == rhs); +} + +bool BasicString::operator!=(const Char* rhs) const { + return !(*this == rhs); +} + +BasicString StringBuilder::Construct(const Char* data) { + if (!data || *data == 0) return BasicString(0); + + BasicString view(strlen(data)); + view += data; + + return view; +} + +BasicString StringBuilder::FromInt(const char* fmt, int i) { + if (!fmt) return BasicString(0); + + Char result[sizeof(int64_t)] = {0}; + if (!to_str(result, sizeof(int64_t), i)) return BasicString(0); + + const SizeType fmt_len = string_length(fmt); + const SizeType res_len = string_length(result); + + BasicString output(fmt_len + res_len); + bool inserted = false; + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (!inserted && fmt[idx] == '%') { + output += result; + inserted = true; + continue; + } + output += Char{fmt[idx]}; + } + + return output; +} + +BasicString StringBuilder::FromBool(const char* fmt, bool val) { + if (!fmt) return BasicString(0); + + const Char* boolean_expr = val ? "true" : "false"; + const SizeType fmt_len = string_length(fmt); + const SizeType res_len = string_length(boolean_expr); + + BasicString output(fmt_len + res_len); + bool inserted = false; + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (!inserted && fmt[idx] == '%') { + output += boolean_expr; + inserted = true; + continue; + } + output += Char{fmt[idx]}; + } + + return output; +} + +bool StringBuilder::Equals(const char* lhs, const char* rhs) { + const SizeType lhs_len = string_length(lhs); + const SizeType rhs_len = string_length(rhs); + + if (lhs_len != rhs_len) return false; + return memcmp(lhs, rhs, lhs_len) == 0; +} + +BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { + if (!fmt || !fmtRight) return BasicString(0); + + const SizeType fmt_len = string_length(fmt); + const SizeType rhs_len = string_length(fmtRight); + + BasicString output(fmt_len + rhs_len); + bool inserted = false; + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (!inserted && fmt[idx] == '%') { + output += fmtRight; + inserted = true; + continue; + } + output += Char{fmt[idx]}; + } + + return output; +} + +BasicString& BasicString::operator+=(const Char* rhs) { + const SizeType rhs_len = strlen(rhs); + if (this->m_Cur + rhs_len >= this->m_Sz) { + throw std::runtime_error("out_of_bounds: BasicString"); + } + + memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); + + this->m_Cur += rhs_len; + this->m_Data[this->m_Cur] = '\0'; + + return *this; +} + +BasicString& BasicString::operator+=(const BasicString& rhs) { + if (this->m_Cur + rhs.m_Cur >= this->m_Sz) { + throw std::runtime_error("out_of_bounds: BasicString"); + } + + memcpy(this->m_Data + this->m_Cur, rhs.CData(), rhs.m_Cur); + this->m_Cur += rhs.m_Cur; + this->m_Data[this->m_Cur] = '\0'; + + return *this; +} + +BasicString& BasicString::operator+=(const Char ch) { + if (this->m_Cur + 1 >= this->m_Sz) { + throw std::runtime_error("out_of_bounds.."); + } + + this->m_Data[this->m_Cur++] = ch; + this->m_Data[this->m_Cur] = '\0'; + + return *this; +} + +} // namespace CompilerKit diff --git a/dev/CompilerKit/utils/AsmUtils.h b/dev/CompilerKit/utils/AsmUtils.h index f74fb1b..889d359 100644 --- a/dev/CompilerKit/utils/AsmUtils.h +++ b/dev/CompilerKit/utils/AsmUtils.h @@ -6,9 +6,8 @@ #pragma once -#include +#include #include - #include using namespace CompilerKit; diff --git a/dev/CompilerKit/utils/CompilerUtils.h b/dev/CompilerKit/utils/CompilerUtils.h index bf48b79..f69d117 100644 --- a/dev/CompilerKit/utils/CompilerUtils.h +++ b/dev/CompilerKit/utils/CompilerUtils.h @@ -6,7 +6,7 @@ #pragma once -#include +#include #include #include #include diff --git a/docs/drawio/COMPILERKIT_DESIGN.drawio b/docs/drawio/COMPILERKIT_DESIGN.drawio new file mode 100644 index 0000000..78934b6 --- /dev/null +++ b/docs/drawio/COMPILERKIT_DESIGN.drawio @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/drawio/DEBUGGERKIT_DESIGN.drawio b/docs/drawio/DEBUGGERKIT_DESIGN.drawio new file mode 100644 index 0000000..0b3802d --- /dev/null +++ b/docs/drawio/DEBUGGERKIT_DESIGN.drawio @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/drawio/LIBCOMPILER_DESIGN.drawio b/docs/drawio/LIBCOMPILER_DESIGN.drawio deleted file mode 100644 index a13c2a3..0000000 --- a/docs/drawio/LIBCOMPILER_DESIGN.drawio +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/drawio/LIBDEBUGGER_DESIGN.drawio b/docs/drawio/LIBDEBUGGER_DESIGN.drawio deleted file mode 100644 index 0b3802d..0000000 --- a/docs/drawio/LIBDEBUGGER_DESIGN.drawio +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/asm.cc b/tools/asm.cc index f600408..621cb37 100644 --- a/tools/asm.cc +++ b/tools/asm.cc @@ -4,7 +4,7 @@ ------------------------------------------- */ -/// @file asm.cxx +/// @file asm.cc /// @brief Assembler frontend. #include diff --git a/tools/dbg.cc b/tools/dbg.cc index 1ee9c37..4174083 100644 --- a/tools/dbg.cc +++ b/tools/dbg.cc @@ -6,7 +6,7 @@ #include -/// @file dbg.cxx +/// @file dbg.cc /// @brief NE debugger. CK_IMPORT_C Int32 DebuggerMachPOSIX(Int32 argc, Char const* argv[]); diff --git a/tools/kdbg.cc b/tools/kdbg.cc index d7aaa93..8e1f108 100644 --- a/tools/kdbg.cc +++ b/tools/kdbg.cc @@ -6,7 +6,7 @@ #include -/// @file kdbg.cxx +/// @file kdbg.cc /// @brief NeKernel debugger. CK_IMPORT_C Int32 DebuggerNeKernel(Int32 argc, Char const* argv[]); diff --git a/tools/ld64.cc b/tools/ld64.cc index e551fee..982c2fc 100644 --- a/tools/ld64.cc +++ b/tools/ld64.cc @@ -6,7 +6,7 @@ #include -/// @file ld64.cxx +/// @file ld64.cc /// @brief NE Linker for AE objects. CK_IMPORT_C int DynamicLinker64PEF(int argc, char const* argv[]); -- cgit v1.2.3 From ca9e7094d1c2eebbd37b3e27f7b60900242ed823 Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Thu, 7 Aug 2025 01:03:08 +0300 Subject: Sec: Compiler Frontend Patched buffer overflows and errors in the AMD64 compiler that could lead to crashes or undefined behavior. Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 103 +++++++++++---------- 1 file changed, 56 insertions(+), 47 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index 98a8018..b83f290 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -19,6 +19,8 @@ #include #include #include +#include +#include /* NeKernel C++ Compiler Driver */ /* This is part of the CompilerKit. */ @@ -27,8 +29,6 @@ /// @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. /////////////////////// @@ -84,11 +84,29 @@ struct CompilerState final { CompilerKit::STLString fLastFile; CompilerKit::STLString fLastError; }; + +/// @brief prints an error into stdout. +/// @param reason the reason of the error. +/// @param file where does it originate from? +void p_error(const CompilerKit::STLString& reason, const CompilerKit::STLString& file) noexcept { + std::cerr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; +} + +/// @brief crash handler for segmentation faults +/// @param signal the signal number +void drvi_crash_handler(int signal) noexcept { + std::cerr << kRed << "Compiler crashed with signal: " << signal << kWhite << std::endl; + std::cerr << "Last file: " << kState.fLastFile << std::endl; + std::cerr << "Last error: " << kState.fLastError << std::endl; + std::exit(EXIT_FAILURE); +} } // namespace Detail static Detail::CompilerState kState; static Int32 kOnClassScope = 0; +static Boolean kVerbose = false; +static Int32 kErrorLimit = 0; ///////////////////////////////////////////////////////////////////////////////////////// @@ -222,7 +240,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (keywordPos == CompilerKit::STLString::npos || openParen == CompilerKit::STLString::npos || closeParen == CompilerKit::STLString::npos || closeParen <= openParen) { - Detail::print_error("Malformed if expression: " + text, file); + Detail::p_error("Malformed if expression: " + text, file); break; } @@ -234,37 +252,26 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( 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); + // trim non-alphanumeric characters from right + while (!right.empty() && !std::isalnum(right.back())) { + right.pop_back(); + } + while (!right.empty() && !std::isalnum(right.front())) { + right.erase(0, 1); } - i = left.size() - 1; - try { - while (!std::isalnum(left[i])) { - left.erase(i, 1); - --i; - } - - left.erase(0, i); - } catch (...) { - left.erase(0, i); + // trim non-alphanumeric characters from left + while (!left.empty() && !std::isalnum(left.back())) { + left.pop_back(); + } + while (!left.empty() && !std::isalnum(left.front())) { + left.erase(0, 1); } - if (!isdigit(left[0]) || !isdigit(right[0])) { + if ((!left.empty() && !isdigit(left[0])) || (!right.empty() && !isdigit(right[0]))) { auto indexRight = 0UL; - auto& valueOfVar = !isdigit(left[0]) ? left : right; + auto& valueOfVar = (!left.empty() && !isdigit(left[0])) ? left : right; if (!valueOfVar.empty()) { for (auto pairRight : kRegisterMap) { @@ -273,7 +280,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( CompilerKit::STLString instr = "mov "; if (pairRight != valueOfVar) { - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; syntax_tree.fUserValue += instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; @@ -283,7 +290,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( goto lc_done_iterarting_on_if; } - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; syntax_tree.fUserValue += instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; @@ -345,14 +352,14 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (text.ends_with(";") && text.find("return") == CompilerKit::STLString::npos) goto lc_write_assembly; else if (text.size() <= indexFnName) - Detail::print_error("Invalid function name: " + symbol_name_fn, file); + Detail::p_error("Invalid function name: " + symbol_name_fn, file); indexFnName = 0; for (auto& ch : symbol_name_fn) { if (ch == ' ' || ch == '\t') { if (symbol_name_fn[indexFnName - 1] != ')') - Detail::print_error("Invalid function name: " + symbol_name_fn, file); + Detail::p_error("Invalid function name: " + symbol_name_fn, file); } ++indexFnName; @@ -470,10 +477,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( varName.erase(varName.find("\t"), 1); } - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) { - if (i > valueOfVar.size()) break; - - valueOfVar.erase(i, 1); + // Remove leading non-alphanumeric characters while (!valueOfVar.empty() && !isalnum(valueOfVar[0])) { + valueOfVar.erase(0, 1); } constexpr auto kTrueVal = "true"; @@ -523,12 +528,12 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( goto done; } - if (valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && !isdigit(valueOfVar[0])) { + if (!valueOfVar.empty() && valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && !isdigit(valueOfVar[0])) { for (auto pair : kRegisterMap) { if (pair == valueOfVar) goto done; } - Detail::print_error("Variable not declared: " + varName, file); + Detail::p_error("Variable not declared: " + varName, file); break; } @@ -579,10 +584,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( std::size_t indxReg = 0UL; - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) { - if (i > valueOfVar.size()) break; - - valueOfVar.erase(i, 1); + // Remove leading non-alphanumeric characters while (!valueOfVar.empty() && !isalnum(valueOfVar[0])) { + valueOfVar.erase(0, 1); } while (valueOfVar.find(" ") != CompilerKit::STLString::npos) { @@ -632,7 +635,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( } if (syntax_tree.fUserValue.empty()) { - Detail::print_error("Variable not declared: " + varName, file); + Detail::p_error("Variable not declared: " + varName, file); } kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); @@ -646,7 +649,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( subText = subText.erase(subText.find(";")); size_t indxReg = 0UL; - if (subText[0] != '\"' && subText[0] != '\'') { + if (!subText.empty() && subText[0] != '\"' && subText[0] != '\'') { if (!isdigit(subText[0])) { for (auto pair : kRegisterMap) { ++indxReg; @@ -684,7 +687,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( }); if (it == kOriginMap.end()) - Detail::print_error("Invalid return value: " + subText, file); + Detail::p_error("Invalid return value: " + subText, file); std::stringstream ss; ss << it->second; @@ -821,6 +824,12 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { kCompilerFrontend = new CompilerFrontendCPlusPlusAMD64(); kFactory.Mount(new AssemblyCPlusPlusInterfaceAMD64()); + + // Ensure cleanup on exit + std::atexit([]() { + delete kCompilerFrontend; + kCompilerFrontend = nullptr; + }); CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); @@ -862,7 +871,7 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { CompilerKit::STLString err = "Unknown option: "; err += argv[index]; - Detail::print_error(err, "cxxdrv"); + Detail::p_error(err, "cxxdrv"); continue; } @@ -888,5 +897,5 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { } // -// Last rev 23-5-25 +// Last rev 25-8-7 // -- cgit v1.2.3 From afd704793a8779642094202fe6ac8acf9073140b Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Thu, 7 Aug 2025 20:04:23 +0300 Subject: Update for consistency Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 68 +++++++++++----------- 1 file changed, 35 insertions(+), 33 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index b83f290..5897030 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -10,6 +10,7 @@ /// BUGS: 0 #define kPrintF printf +#define kStdErr std::cerr #define kExitOK (EXIT_SUCCESS) #define kExitNO (EXIT_FAILURE) @@ -48,21 +49,22 @@ /// @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 +// Avoids relative_path which could discard parts of the original. +std::filesystem::path expand_home(const std::filesystem::path& input) { + const std::string& raw = input.string(); - if (!home) { - home = std::getenv("USERPROFILE"); // For Windows - } + if (!raw.empty() && raw[0] == '~') { + const char* home = std::getenv("HOME"); + if (!home) home = std::getenv("USERPROFILE"); - if (home) { - return std::filesystem::path(home) / p.relative_path().string().substr(1); - } else { + if (!home) throw std::runtime_error("Home directory not found in environment variables"); - } + + return std::filesystem::path(home) / raw.substr(1); + } + + return input; } - return p; } struct CompilerRegisterMap final { @@ -88,16 +90,16 @@ struct CompilerState final { /// @brief prints an error into stdout. /// @param reason the reason of the error. /// @param file where does it originate from? -void p_error(const CompilerKit::STLString& reason, const CompilerKit::STLString& file) noexcept { - std::cerr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; +void print_error(const CompilerKit::STLString& reason, const CompilerKit::STLString& file) noexcept { + kStdErr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; } /// @brief crash handler for segmentation faults /// @param signal the signal number void drvi_crash_handler(int signal) noexcept { - std::cerr << kRed << "Compiler crashed with signal: " << signal << kWhite << std::endl; - std::cerr << "Last file: " << kState.fLastFile << std::endl; - std::cerr << "Last error: " << kState.fLastError << std::endl; + kStdErr << kRed << "Compiler crashed with signal: " << signal << kWhite << std::endl; + kStdErr << "Last file: " << kState.fLastFile << std::endl; + kStdErr << "Last error: " << kState.fLastError << std::endl; std::exit(EXIT_FAILURE); } } // namespace Detail @@ -204,7 +206,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( std::size_t pos = text.find(keyword.keyword_name); if (pos == std::string::npos) continue; - // Safe guard: can't go before start of string + // can't go before start of string if (pos > 0 && text[pos - 1] == '+' && keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) continue; @@ -213,7 +215,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) continue; - // Safe guard: don't go out of range + // don't go out of range if ((pos + keyword.keyword_name.size()) < text.size() && text[pos + keyword.keyword_name.size()] == '=' && keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) @@ -240,7 +242,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (keywordPos == CompilerKit::STLString::npos || openParen == CompilerKit::STLString::npos || closeParen == CompilerKit::STLString::npos || closeParen <= openParen) { - Detail::p_error("Malformed if expression: " + text, file); + Detail::print_error("Malformed if expression: " + text, file); break; } @@ -252,19 +254,18 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( expr.find("<=") + strlen("<=")); auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - // trim non-alphanumeric characters from right - while (!right.empty() && !std::isalnum(right.back())) { + // Trim whitespace + while (!right.empty() && (right.back() == ' ' || right.back() == '\t')) { right.pop_back(); } - while (!right.empty() && !std::isalnum(right.front())) { + while (!right.empty() && (right.front() == ' ' || right.front() == '\t')) { right.erase(0, 1); } - // trim non-alphanumeric characters from left - while (!left.empty() && !std::isalnum(left.back())) { + while (!left.empty() && (left.back() == ' ' || left.back() == '\t')) { left.pop_back(); } - while (!left.empty() && !std::isalnum(left.front())) { + while (!left.empty() && (left.front() == ' ' || left.front() == '\t')) { left.erase(0, 1); } @@ -352,14 +353,14 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (text.ends_with(";") && text.find("return") == CompilerKit::STLString::npos) goto lc_write_assembly; else if (text.size() <= indexFnName) - Detail::p_error("Invalid function name: " + symbol_name_fn, file); + Detail::print_error("Invalid function name: " + symbol_name_fn, file); indexFnName = 0; for (auto& ch : symbol_name_fn) { if (ch == ' ' || ch == '\t') { if (symbol_name_fn[indexFnName - 1] != ')') - Detail::p_error("Invalid function name: " + symbol_name_fn, file); + Detail::print_error("Invalid function name: " + symbol_name_fn, file); } ++indexFnName; @@ -477,7 +478,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( varName.erase(varName.find("\t"), 1); } - // Remove leading non-alphanumeric characters while (!valueOfVar.empty() && !isalnum(valueOfVar[0])) { + // Remove whitespace only (keep operators and quotes) + while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { valueOfVar.erase(0, 1); } @@ -533,7 +535,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (pair == valueOfVar) goto done; } - Detail::p_error("Variable not declared: " + varName, file); + Detail::print_error("Variable not declared: " + varName, file); break; } @@ -584,7 +586,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( std::size_t indxReg = 0UL; - // Remove leading non-alphanumeric characters while (!valueOfVar.empty() && !isalnum(valueOfVar[0])) { + while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { valueOfVar.erase(0, 1); } @@ -635,7 +637,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( } if (syntax_tree.fUserValue.empty()) { - Detail::p_error("Variable not declared: " + varName, file); + Detail::print_error("Variable not declared: " + varName, file); } kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); @@ -687,7 +689,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( }); if (it == kOriginMap.end()) - Detail::p_error("Invalid return value: " + subText, file); + Detail::print_error("Invalid return value: " + subText, file); std::stringstream ss; ss << it->second; @@ -871,7 +873,7 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { CompilerKit::STLString err = "Unknown option: "; err += argv[index]; - Detail::p_error(err, "cxxdrv"); + Detail::print_error(err, "cxxdrv"); continue; } -- cgit v1.2.3 From 870e0e02f171f2f77057fe0d02627214a4f09ae1 Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Fri, 8 Aug 2025 13:16:24 +0300 Subject: :) Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index 5897030..c31a81c 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -10,7 +10,7 @@ /// BUGS: 0 #define kPrintF printf -#define kStdErr std::cerr +#define kPrintErr std::cerr #define kExitOK (EXIT_SUCCESS) #define kExitNO (EXIT_FAILURE) @@ -91,16 +91,7 @@ struct CompilerState final { /// @param reason the reason of the error. /// @param file where does it originate from? void print_error(const CompilerKit::STLString& reason, const CompilerKit::STLString& file) noexcept { - kStdErr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; -} - -/// @brief crash handler for segmentation faults -/// @param signal the signal number -void drvi_crash_handler(int signal) noexcept { - kStdErr << kRed << "Compiler crashed with signal: " << signal << kWhite << std::endl; - kStdErr << "Last file: " << kState.fLastFile << std::endl; - kStdErr << "Last error: " << kState.fLastError << std::endl; - std::exit(EXIT_FAILURE); + kPrintErr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; } } // namespace Detail @@ -833,7 +824,7 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { kCompilerFrontend = nullptr; }); - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); + for (auto index = 1UL; index < argc; ++index) { if (!argv[index]) break; -- cgit v1.2.3 From 00ca2763dc843d9127376b8e5c5a133659a56a75 Mon Sep 17 00:00:00 2001 From: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:36:56 +0300 Subject: CPlusPlusCompilerAMD64.cc Signed-off-by: 0xf00sec <159052166+0xf00sec@users.noreply.github.com> --- dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index c31a81c..ad2b8e1 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -817,6 +817,8 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { kCompilerFrontend = new CompilerFrontendCPlusPlusAMD64(); kFactory.Mount(new AssemblyCPlusPlusInterfaceAMD64()); + + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); // Ensure cleanup on exit std::atexit([]() { @@ -825,7 +827,6 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { }); - for (auto index = 1UL; index < argc; ++index) { if (!argv[index]) break; @@ -834,6 +835,7 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { skip = false; continue; } + if (strcmp(argv[index], "-cxx-verbose") == 0) { kVerbose = true; -- cgit v1.2.3 From 85a8e5967def8164b90824c9095c3a93d62d96b2 Mon Sep 17 00:00:00 2001 From: Amlal Date: Sat, 9 Aug 2025 19:53:40 +0200 Subject: feat: compiler_kit: post PR compiler error fixes. Signed-off-by: Amlal --- dev/CompilerKit/Compiler.h | 2 +- dev/CompilerKit/Defines.h | 52 +++++++++++----------- dev/CompilerKit/Frontend.h | 11 ++--- dev/CompilerKit/Macros.h | 12 ++--- dev/CompilerKit/UUID.h | 2 +- dev/CompilerKit/src/Backend/Assembler32x0.cc | 2 +- dev/CompilerKit/src/Backend/Assembler64x0.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerAMD64.cc | 2 +- dev/CompilerKit/src/Backend/AssemblerARM64.cc | 4 +- dev/CompilerKit/src/Backend/AssemblerPowerPC.cc | 4 +- dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 9 ++-- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 9 ++-- dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 9 ++-- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 46 +++++++++---------- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 17 +++---- dev/CompilerKit/src/StringKit.cc | 20 ++++----- dev/DebuggerKit/NeKernelContract.h | 4 +- dev/DebuggerKit/Platform.h | 2 +- dev/DebuggerKit/src/NeKernelContractCLI.cc | 3 +- dev/LibC++/__abi+unreachable.cc | 9 ++-- dev/LibC++/__abi.h | 6 +-- dev/LibC++/base_exception.h | 6 +-- dev/LibC++/defines.h | 2 +- dev/ThirdParty/Dialogs.h | 41 +++++++++-------- tools/pef-amd64-cxxdrv.cc | 7 ++- tools/pef-arm64-cdrv.cc | 7 ++- 26 files changed, 140 insertions(+), 150 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/Compiler.h b/dev/CompilerKit/Compiler.h index 60d63ff..46059b8 100644 --- a/dev/CompilerKit/Compiler.h +++ b/dev/CompilerKit/Compiler.h @@ -6,9 +6,9 @@ #pragma once -#include #include #include +#include #define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface #define CK_ENCODER : public ::CompilerKit::EncoderInterface diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h index e9d2560..ffaae0d 100644 --- a/dev/CompilerKit/Defines.h +++ b/dev/CompilerKit/Defines.h @@ -51,6 +51,8 @@ #define Char char #define Boolean bool +#include +#include #include #include #include @@ -81,20 +83,39 @@ #define rt_copy_memory(dst, src, len) memcpy(dst, src, len) #endif -#define NECTI_COPY_DELETE(KLASS) \ +#define ATTRIBUTE(X) __attribute__((X)) +#define PACKED ATTRIBUTE(packed) + +typedef char char_type; + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts \ + { ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" } + +#define kAsmFileExtsMax (7U) + +#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) + +#ifdef MSVC +#pragma scalar_storage_order big - endian +#endif // ifdef MSVC + +#define NECTI_COPY_DELETE(KLASS) \ KLASS& operator=(const KLASS&) = delete; \ KLASS(const KLASS&) = delete; -#define NECTI_COPY_DEFAULT(KLASS) \ +#define NECTI_COPY_DEFAULT(KLASS) \ KLASS& operator=(const KLASS&) = default; \ KLASS(const KLASS&) = default; -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ +#define NECTI_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ KLASS(KLASS&&) = delete; -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ +#define NECTI_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ KLASS(KLASS&&) = default; #define CK_IMPORT_C extern "C" @@ -149,23 +170,4 @@ inline bool install_signal(Int32 signal, void (*handler)(int)) noexcept { } } // namespace CompilerKit -#define ATTRIBUTE(X) __attribute__((X)) -#define PACKED ATTRIBUTE(packed) - -typedef char char_type; - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" } - -#define kAsmFileExtsMax (7U) - -#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) - -#ifdef MSVC -#pragma scalar_storage_order big - endian -#endif // ifdef MSVC - #endif /* ifndef __NECTI_DEFINES_H__ */ diff --git a/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h index 4719c3d..0f81342 100644 --- a/dev/CompilerKit/Frontend.h +++ b/dev/CompilerKit/Frontend.h @@ -59,20 +59,17 @@ enum KeywordKind { /// \brief Compiler keyword information struct. struct CompilerKeyword { CompilerKeyword(STLString name, KeywordKind kind) : keyword_name(name), keyword_kind(kind) {} - + STLString keyword_name{""}; KeywordKind keyword_kind{kKeywordKindInvalid}; }; struct SyntaxLeafList final { struct SyntaxLeaf final { - Int32 fUserType{0U}; - CompilerKeyword fUserData{ - "", - kKeywordKindInvalid - }; + Int32 fUserType{0U}; + CompilerKeyword fUserData{"", kKeywordKindInvalid}; - STLString fUserValue{""}; + STLString fUserValue{""}; struct SyntaxLeaf* fNext{nullptr}; }; diff --git a/dev/CompilerKit/Macros.h b/dev/CompilerKit/Macros.h index ee42be5..f05729c 100644 --- a/dev/CompilerKit/Macros.h +++ b/dev/CompilerKit/Macros.h @@ -9,20 +9,20 @@ #ifndef _MACROS_H_ #define _MACROS_H_ -#define NECTI_COPY_DELETE(KLASS) \ +#define NECTI_COPY_DELETE(KLASS) \ KLASS& operator=(const KLASS&) = delete; \ KLASS(const KLASS&) = delete; -#define NECTI_COPY_DEFAULT(KLASS) \ +#define NECTI_COPY_DEFAULT(KLASS) \ KLASS& operator=(const KLASS&) = default; \ KLASS(const KLASS&) = default; -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ +#define NECTI_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ KLASS(KLASS&&) = delete; -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ +#define NECTI_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ KLASS(KLASS&&) = default; /// @note xxxx is the error placeholder, in hexadecimal. diff --git a/dev/CompilerKit/UUID.h b/dev/CompilerKit/UUID.h index 39db276..d54eec7 100644 --- a/dev/CompilerKit/UUID.h +++ b/dev/CompilerKit/UUID.h @@ -172,7 +172,7 @@ namespace Detail { 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)); + process_byte(static_cast((bitCount) & 0xFF)); memcpy(digest, m_digest, 5 * sizeof(uint32_t)); return digest; diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc index a7cb022..8478930 100644 --- a/dev/CompilerKit/src/Backend/Assembler32x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler32x0.cc @@ -22,9 +22,9 @@ #endif #include -#include #include #include +#include #include ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc index 6bc8842..c2dd31c 100644 --- a/dev/CompilerKit/src/Backend/Assembler64x0.cc +++ b/dev/CompilerKit/src/Backend/Assembler64x0.cc @@ -22,9 +22,9 @@ #endif #include -#include #include #include +#include #include #include #include diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc index b085773..7e21c93 100644 --- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc @@ -29,9 +29,9 @@ #define kAssemblerPragmaSym '#' #include -#include #include #include +#include #include #include #include diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc index 331e708..ec0f16b 100644 --- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc +++ b/dev/CompilerKit/src/Backend/AssemblerARM64.cc @@ -20,12 +20,12 @@ #endif #include -#include #include #include #include -#include #include +#include +#include #include #include #include diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc index bbb5a8b..3282ccb 100644 --- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc +++ b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc @@ -20,12 +20,12 @@ #endif #include -#include #include #include #include -#include #include +#include +#include #include #include #include diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc index 1221521..de76807 100644 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc @@ -10,9 +10,9 @@ /// BUGS: 0 /// TODO: none -#include #include #include +#include #include #include #include @@ -141,8 +141,8 @@ class CompilerFrontend64x0 final : public CompilerKit::CompilerFrontendInterface NECTI_COPY_DEFAULT(CompilerFrontend64x0); - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; const char* Language() override { return "64k C"; } }; @@ -182,7 +182,8 @@ union double_cast final { ///////////////////////////////////////////////////////////////////////////////////////// -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::string text_, std::string file) { +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::string text_, + std::string file) { std::string text = text_; bool typeFound = false; diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc index 6795c67..9cfc019 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc @@ -10,9 +10,9 @@ /// BUGS: 0 /// TODO: none -#include #include #include +#include #include #include @@ -142,8 +142,8 @@ class CompilerFrontendARM64 final : public CompilerKit::CompilerFrontendInterfac NECTI_COPY_DEFAULT(CompilerFrontendARM64); - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; const char* Language() override { return "64k C"; } }; @@ -183,7 +183,8 @@ union double_cast final { ///////////////////////////////////////////////////////////////////////////////////////// -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::string text, std::string file) { +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::string text, + std::string file) { bool typeFound = false; bool fnFound = false; diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc index 1999f48..1888ed0 100644 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc @@ -7,9 +7,9 @@ * ======================================================== */ -#include #include #include +#include #include #include #include @@ -132,8 +132,8 @@ class CompilerFrontendPower64 final : public CompilerKit::CompilerFrontendInterf NECTI_COPY_DEFAULT(CompilerFrontendPower64); - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; + std::string Check(const char* text, const char* file); + CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; const char* Language() override { return "POWER C"; } }; @@ -173,7 +173,8 @@ union double_cast final { ///////////////////////////////////////////////////////////////////////////////////////// -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::string text_, std::string file) { +CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::string text_, + std::string file) { std::string text = text_; bool typeFound = false; diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc index ad2b8e1..c92f2e2 100644 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc @@ -15,10 +15,10 @@ #define kExitOK (EXIT_SUCCESS) #define kExitNO (EXIT_FAILURE) -#include #include #include #include +#include #include #include #include @@ -48,7 +48,6 @@ ///////////////////////////////////// /// @internal -namespace Detail { // Avoids relative_path which could discard parts of the original. std::filesystem::path expand_home(const std::filesystem::path& input) { const std::string& raw = input.string(); @@ -57,14 +56,12 @@ std::filesystem::path expand_home(const std::filesystem::path& input) { const char* home = std::getenv("HOME"); if (!home) home = std::getenv("USERPROFILE"); - if (!home) - throw std::runtime_error("Home directory not found in environment variables"); + if (!home) throw std::runtime_error("Home directory not found in environment variables"); return std::filesystem::path(home) / raw.substr(1); } return input; - } } struct CompilerRegisterMap final { @@ -90,16 +87,14 @@ struct CompilerState final { /// @brief prints an error into stdout. /// @param reason the reason of the error. /// @param file where does it originate from? -void print_error(const CompilerKit::STLString& reason, const CompilerKit::STLString& file) noexcept { +void print_error(const CompilerKit::STLString& reason, + const CompilerKit::STLString& file) noexcept { kPrintErr << kRed << "Error in " << file << ": " << reason << kWhite << std::endl; } -} // namespace Detail -static Detail::CompilerState kState; +static CompilerState kState; static Int32 kOnClassScope = 0; -static Boolean kVerbose = false; -static Int32 kErrorLimit = 0; ///////////////////////////////////////////////////////////////////////////////////////// @@ -245,7 +240,7 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( expr.find("<=") + strlen("<=")); auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - // Trim whitespace + // Trim whitespace while (!right.empty() && (right.back() == ' ' || right.back() == '\t')) { right.pop_back(); } @@ -323,8 +318,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( break; accept: - CompilerKit::STLString symbol_name_fn = text; - size_t indexFnName = 0; + CompilerKit::STLString symbol_name_fn = text; + size_t indexFnName = 0; // this one is for the type. for (auto& ch : text) { @@ -369,11 +364,11 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( break; lc_write_assembly: - auto it = - std::find_if(kOriginMap.begin(), kOriginMap.end(), - [&symbol_name_fn](std::pair pair) -> bool { - return symbol_name_fn == pair.first; - }); + auto it = std::find_if( + kOriginMap.begin(), kOriginMap.end(), + [&symbol_name_fn](std::pair pair) -> bool { + return symbol_name_fn == pair.first; + }); if (it != kOriginMap.end()) { std::stringstream ss; @@ -490,8 +485,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (pairRight != valueOfVar) { if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + - ": db " + valueOfVar + ", 0\n\n"; + syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + + valueOfVar + ", 0\n\n"; syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + "__NECTI_LOCAL_VAR_" + varName + "\n"; kOrigin += 1UL; @@ -507,8 +502,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( if (((int) indexRight - 1) < 0) { if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + - ": db " + valueOfVar + ", 0\n"; + syntax_tree.fUserValue = + "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n"; syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + "__NECTI_LOCAL_VAR_" + varName + "\n"; kOrigin += 1UL; @@ -521,7 +516,8 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( goto done; } - if (!valueOfVar.empty() && valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && !isdigit(valueOfVar[0])) { + if (!valueOfVar.empty() && valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && + !isdigit(valueOfVar[0])) { for (auto pair : kRegisterMap) { if (pair == valueOfVar) goto done; } @@ -819,14 +815,13 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { kFactory.Mount(new AssemblyCPlusPlusInterfaceAMD64()); CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - + // Ensure cleanup on exit std::atexit([]() { delete kCompilerFrontend; kCompilerFrontend = nullptr; }); - for (auto index = 1UL; index < argc; ++index) { if (!argv[index]) break; @@ -835,7 +830,6 @@ NECTI_MODULE(CompilerCPlusPlusAMD64) { skip = false; continue; } - if (strcmp(argv[index], "-cxx-verbose") == 0) { kVerbose = true; diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 394014c..2d149df 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -13,19 +13,19 @@ /// @note Do not look up for anything with .code64/.data64/.zero64! /// It will be loaded when the program loader will start the image. - +#include +#include #include #include -#include #include #include #include -#include #include -#define kLinkerVersionStr \ - "NeKernel.org 64-Bit Linker (Preferred Executable Format) %s, (c) Amlal El Mahrouss, and NeKernel Contributors " \ - "2024-2025 " \ +#define kLinkerVersionStr \ + "NeKernel.org 64-Bit Linker (Preferred Executable Format) %s, (c) Amlal El Mahrouss, and " \ + "NeKernel Contributors " \ + "2024-2025 " \ "all rights reserved.\n" #define MemoryCopy(DST, SRC, SZ) memcpy(DST, SRC, SZ) @@ -44,10 +44,7 @@ /// @brief PEF stack size symbol. #define kLinkerStackSizeSymbol "__PEFSizeOfReserveStack" -#define kConsoleOut \ - (std::cout << "\e[0;31m" \ - << "ld64: " \ - << "\e[0;97m") +#define kConsoleOut (std::cout << "\e[0;31m" << "ld64: " << "\e[0;97m") enum { kABITypeNull = 0, diff --git a/dev/CompilerKit/src/StringKit.cc b/dev/CompilerKit/src/StringKit.cc index 13142a6..67f2f55 100644 --- a/dev/CompilerKit/src/StringKit.cc +++ b/dev/CompilerKit/src/StringKit.cc @@ -42,7 +42,7 @@ bool BasicString::operator==(const BasicString& rhs) const { bool BasicString::operator==(const Char* rhs) const { const SizeType rhs_len = string_length(rhs); - const SizeType len = Length(); + const SizeType len = Length(); if (rhs_len != len) return false; return memcmp(m_Data, rhs, len) == 0; } @@ -74,7 +74,7 @@ BasicString StringBuilder::FromInt(const char* fmt, int i) { const SizeType res_len = string_length(result); BasicString output(fmt_len + res_len); - bool inserted = false; + bool inserted = false; for (SizeType idx = 0; idx < fmt_len; ++idx) { if (!inserted && fmt[idx] == '%') { @@ -91,12 +91,12 @@ BasicString StringBuilder::FromInt(const char* fmt, int i) { BasicString StringBuilder::FromBool(const char* fmt, bool val) { if (!fmt) return BasicString(0); - const Char* boolean_expr = val ? "true" : "false"; - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(boolean_expr); + const Char* boolean_expr = val ? "true" : "false"; + const SizeType fmt_len = string_length(fmt); + const SizeType res_len = string_length(boolean_expr); BasicString output(fmt_len + res_len); - bool inserted = false; + bool inserted = false; for (SizeType idx = 0; idx < fmt_len; ++idx) { if (!inserted && fmt[idx] == '%') { @@ -125,7 +125,7 @@ BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { const SizeType rhs_len = string_length(fmtRight); BasicString output(fmt_len + rhs_len); - bool inserted = false; + bool inserted = false; for (SizeType idx = 0; idx < fmt_len; ++idx) { if (!inserted && fmt[idx] == '%') { @@ -146,7 +146,7 @@ BasicString& BasicString::operator+=(const Char* rhs) { } memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); - + this->m_Cur += rhs_len; this->m_Data[this->m_Cur] = '\0'; @@ -171,9 +171,9 @@ BasicString& BasicString::operator+=(const Char ch) { } this->m_Data[this->m_Cur++] = ch; - this->m_Data[this->m_Cur] = '\0'; + this->m_Data[this->m_Cur] = '\0'; return *this; } -} // namespace CompilerKit +} // namespace CompilerKit diff --git a/dev/DebuggerKit/NeKernelContract.h b/dev/DebuggerKit/NeKernelContract.h index 20d86cd..098244e 100644 --- a/dev/DebuggerKit/NeKernelContract.h +++ b/dev/DebuggerKit/NeKernelContract.h @@ -14,8 +14,8 @@ namespace DebuggerKit::NeKernel { class NeKernelContract; namespace Detail { - inline constexpr auto kDebugCmdLen = 256U; - inline constexpr auto kDebugPort = 51820; + inline constexpr auto kDebugCmdLen = 256U; + inline constexpr auto kDebugPort = 51820; inline constexpr auto kDebugMagic = "VMK1.0.0;"; inline constexpr auto kDebugVersion = 0x0100; typedef char rt_debug_cmd[kDebugCmdLen]; diff --git a/dev/DebuggerKit/Platform.h b/dev/DebuggerKit/Platform.h index b24c5d9..6a3ef7c 100644 --- a/dev/DebuggerKit/Platform.h +++ b/dev/DebuggerKit/Platform.h @@ -13,5 +13,5 @@ #include #include #else -#error !!! DebuggerKit needs a networking backend !!! +#error !!! DebuggerKit needs a networking backend !!! #endif \ No newline at end of file diff --git a/dev/DebuggerKit/src/NeKernelContractCLI.cc b/dev/DebuggerKit/src/NeKernelContractCLI.cc index 1dd87a5..0eb04d3 100644 --- a/dev/DebuggerKit/src/NeKernelContractCLI.cc +++ b/dev/DebuggerKit/src/NeKernelContractCLI.cc @@ -30,7 +30,8 @@ static void dbgi_ctrlc_handler(std::int32_t _) { NECTI_MODULE(DebuggerNeKernel) { pfd::notify("Debugger Event", - "NeKernel Debugger\n(C) 2025 Amlal El Mahrouss and NeKernel.org contributors, all rights reserved."); + "NeKernel Debugger\n(C) 2025 Amlal El Mahrouss and NeKernel.org contributors, all " + "rights reserved."); if (argc >= 5 && std::string(argv[1]) == "-k" && argv[2] != nullptr && std::string(argv[3]) == "-ip" && argv[4] != nullptr) { diff --git a/dev/LibC++/__abi+unreachable.cc b/dev/LibC++/__abi+unreachable.cc index 9f436c0..90c50e1 100644 --- a/dev/LibC++/__abi+unreachable.cc +++ b/dev/LibC++/__abi+unreachable.cc @@ -1,7 +1,7 @@ /* ------------------------------------------- - - Copyright (C) 2025 Amlal El Mahrouss, all rights reserved. - + + Copyright (C) 2025 Amlal El Mahrouss, all rights reserved. + ------------------------------------------- */ #include @@ -12,6 +12,5 @@ static const int32_t __unreachable_code = 34; extern "C" void __libcompiler_unreachable(void) { std::base_process::signal(__unreachable_code); - while (1) - ; + while (1); } \ No newline at end of file diff --git a/dev/LibC++/__abi.h b/dev/LibC++/__abi.h index d2cc52f..48d4449 100644 --- a/dev/LibC++/__abi.h +++ b/dev/LibC++/__abi.h @@ -1,7 +1,7 @@ /* ------------------------------------------- - - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. - + + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + ------------------------------------------- */ #pragma once diff --git a/dev/LibC++/base_exception.h b/dev/LibC++/base_exception.h index 9a599be..29f996b 100644 --- a/dev/LibC++/base_exception.h +++ b/dev/LibC++/base_exception.h @@ -6,9 +6,9 @@ #pragma once -#include -#include #include +#include +#include #include /// @author Amlal El Mahrouss (amlal@nekernel.org) @@ -34,4 +34,4 @@ inline void __throw_bad_array_new_length(const char* what) { __throw_general(what); __builtin_unreachable(); // prevent from continuing. } -} // namespace std::base_exception +} // namespace std::base_exception::abi diff --git a/dev/LibC++/defines.h b/dev/LibC++/defines.h index 2fedac5..21c43e4 100644 --- a/dev/LibC++/defines.h +++ b/dev/LibC++/defines.h @@ -16,7 +16,7 @@ extern "C" { #ifndef __GNUC__ -typedef __SIZE_TYPE__ size_t; +typedef __SIZE_TYPE__ size_t; typedef __SSIZE_TYPE__ ssize_t; typedef void* ptr_type; diff --git a/dev/ThirdParty/Dialogs.h b/dev/ThirdParty/Dialogs.h index 84e239f..ce50b81 100644 --- a/dev/ThirdParty/Dialogs.h +++ b/dev/ThirdParty/Dialogs.h @@ -175,7 +175,7 @@ namespace internal { #elif __EMSCRIPTEN__ void start(int exit_code); #else - void start_process(std::vector const& command); + void start_process(std::vector const& command); #endif ~executor(); @@ -490,10 +490,10 @@ inline settings::settings(bool resync) { #if _WIN32 flags(flag::is_vista) = internal::is_vista(); #elif !__APPLE__ - flags(flag::has_zenity) = check_program("zenity"); + flags(flag::has_zenity) = check_program("zenity"); flags(flag::has_matedialog) = check_program("matedialog"); - flags(flag::has_qarma) = check_program("qarma"); - flags(flag::has_kdialog) = check_program("kdialog"); + flags(flag::has_qarma) = check_program("qarma"); + flags(flag::has_kdialog) = check_program("kdialog"); // If multiple helpers are available, try to default to the best one if (flags(flag::has_zenity) && flags(flag::has_kdialog)) { @@ -540,7 +540,7 @@ inline bool settings::check_program(std::string const& program) { (void) program; return false; #else - int exit_code = -1; + int exit_code = -1; internal::executor async; async.start_process({"/bin/sh", "-c", "which " + program}); async.result(&exit_code); @@ -604,7 +604,7 @@ inline std::string path::home() { if (size_max != -1) len = size_t(size_max); #endif std::vector buf(len); - struct passwd pwd, *result; + struct passwd pwd, *result; if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) return result->pw_dir; #endif return "/"; @@ -717,7 +717,7 @@ inline void internal::executor::start_process(std::vector const& co } close(in[1]); - m_fd = out[0]; + m_fd = out[0]; auto flags = fcntl(m_fd, F_GETFL); fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); @@ -753,7 +753,7 @@ inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) // FIXME: do something (void) timeout; #else - char buf[BUFSIZ]; + char buf[BUFSIZ]; ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore if (received > 0) { m_stdout += std::string(buf, received); @@ -764,7 +764,7 @@ inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) // (this happens when the calling application handles or ignores SIG_CHLD) and results in // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for // a little while. - int status; + int status; pid_t child = waitpid(m_pid, &status, WNOHANG); if (child != m_pid && (child >= 0 || errno != ECHILD)) { // FIXME: this happens almost always at first iteration @@ -782,8 +782,7 @@ inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) inline void internal::executor::stop() { // Loop until the user closes the dialog - while (!ready()) - ; + while (!ready()); } // dll implementation @@ -879,11 +878,11 @@ inline std::vector internal::dialog::desktop_helper() const { #if __APPLE__ return {"osascript"}; #else - return {flags(flag::has_zenity) ? "zenity" + return {flags(flag::has_zenity) ? "zenity" : flags(flag::has_matedialog) ? "matedialog" - : flags(flag::has_qarma) ? "qarma" - : flags(flag::has_kdialog) ? "kdialog" - : "echo"}; + : flags(flag::has_qarma) ? "qarma" + : flags(flag::has_kdialog) ? "kdialog" + : "echo"}; #endif } @@ -1125,9 +1124,9 @@ inline internal::file_dialog::file_dialog(type in_type, std::string const& title // Split the pattern list to check whether "*" is in there; if it // is, we have to disable filters because there is no mechanism in // OS X for the user to override the filter. - std::regex sep("\\s+"); - std::string filter_list; - bool has_filter = true; + std::regex sep("\\s+"); + std::string filter_list; + bool has_filter = true; std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); std::sregex_token_iterator end; for (; iter != end; ++iter) { @@ -1236,7 +1235,7 @@ inline std::vector internal::file_dialog::vector_result() { return m_vector_result; #else std::vector ret; - auto result = m_async->result(); + auto result = m_async->result(); for (;;) { // Split result along newline characters auto i = result.find('\n'); @@ -1569,7 +1568,7 @@ inline message::message(std::string const& title, std::string const& text, if_cancel = button::ok; break; } - m_mappings[1] = if_cancel; + m_mappings[1] = if_cancel; m_mappings[256] = if_cancel; // XXX: I think this was never correct script += " with icon "; switch (_icon) { @@ -1656,7 +1655,7 @@ inline message::message(std::string const& title, std::string const& text, if (_choice == choice::yes_no_cancel) flag += "cancel"; command.push_back(flag); if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) { - m_mappings[0] = button::yes; + m_mappings[0] = button::yes; m_mappings[256] = button::no; } } diff --git a/tools/pef-amd64-cxxdrv.cc b/tools/pef-amd64-cxxdrv.cc index 21b68a0..274df09 100644 --- a/tools/pef-amd64-cxxdrv.cc +++ b/tools/pef-amd64-cxxdrv.cc @@ -9,11 +9,11 @@ #include #include +#include #include #include -#include -static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; +static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; static auto kSymbol = "CompilerCPlusPlusAMD64"; Int32 main(Int32 argc, Char const* argv[]) { @@ -26,8 +26,7 @@ Int32 main(Int32 argc, Char const* argv[]) { return EXIT_FAILURE; } - CompilerKitEntrypoint entrypoint_cxx = - (CompilerKitEntrypoint) dlsym(handler, kSymbol); + CompilerKitEntrypoint entrypoint_cxx = (CompilerKitEntrypoint) dlsym(handler, kSymbol); if (!entrypoint_cxx) { kStdOut; diff --git a/tools/pef-arm64-cdrv.cc b/tools/pef-arm64-cdrv.cc index 4dbf39e..1d2822b 100644 --- a/tools/pef-arm64-cdrv.cc +++ b/tools/pef-arm64-cdrv.cc @@ -9,11 +9,11 @@ #include #include +#include #include #include -#include -static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; +static auto kPath = "/usr/local/lib/libCompilerKit.dylib"; static auto kSymbol = "CompilerCLangARM64"; Int32 main(Int32 argc, Char const* argv[]) { @@ -26,8 +26,7 @@ Int32 main(Int32 argc, Char const* argv[]) { return EXIT_FAILURE; } - CompilerKitEntrypoint entrypoint_cxx = - (CompilerKitEntrypoint) dlsym(handler, kSymbol); + CompilerKitEntrypoint entrypoint_cxx = (CompilerKitEntrypoint) dlsym(handler, kSymbol); if (!entrypoint_cxx) { kStdOut; -- cgit v1.2.3 From a47b01da9e61a6f5ce5d21b408d58b6ee6f97639 Mon Sep 17 00:00:00 2001 From: Amlal Date: Sat, 9 Aug 2025 21:14:14 +0200 Subject: fix: remove useless char_type typedef. --- dev/CompilerKit/Defines.h | 2 -- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h index ffaae0d..36d51ef 100644 --- a/dev/CompilerKit/Defines.h +++ b/dev/CompilerKit/Defines.h @@ -86,8 +86,6 @@ #define ATTRIBUTE(X) __attribute__((X)) #define PACKED ATTRIBUTE(packed) -typedef char char_type; - #define kObjectFileExt ".obj" #define kBinaryFileExt ".bin" diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 2d149df..c1b72f9 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -263,7 +263,7 @@ NECTI_MODULE(DynamicLinker64PEF) { pef_container.Count = cnt; - char_type* raw_ae_records = new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + Char* raw_ae_records = new Char[cnt * sizeof(CompilerKit::AERecordHeader)]; if (!raw_ae_records) { if (kVerbose) kConsoleOut << "allocation failed for records of count: " << cnt << "\n"; -- cgit v1.2.3 From db664f45199c24e94a69a96eaea3dee751607dbd Mon Sep 17 00:00:00 2001 From: Amlal Date: Mon, 11 Aug 2025 21:42:06 +0200 Subject: feat! final compiler_kit refactors. Signed-off-by: Amlal --- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 39 ++++++++++------------ dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc | 4 +-- dev/LibC++/__abi+unreachable.cc | 2 +- dev/LibC++/__abi.h | 2 +- 4 files changed, 22 insertions(+), 25 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index c1b72f9..6c8ca95 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -28,9 +28,6 @@ "2024-2025 " \ "all rights reserved.\n" -#define MemoryCopy(DST, SRC, SZ) memcpy(DST, SRC, SZ) -#define StringCompare(DST, SRC) strcmp(DST, SRC) - #define kPefNoCpu (0U) #define kPefNoSubCpu (0U) @@ -80,7 +77,7 @@ NECTI_MODULE(DynamicLinker64PEF) { * @brief parse flags and trigger options. */ for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) { - if (StringCompare(argv[linker_arg], "-help") == 0) { + if (std::strcmp(argv[linker_arg], "-help") == 0) { kLinkerSplash(); kConsoleOut << "-version: Show linker version.\n"; @@ -97,43 +94,43 @@ NECTI_MODULE(DynamicLinker64PEF) { kConsoleOut << "-output: Select the output file name.\n"; return NECTI_SUCCESS; - } else if (StringCompare(argv[linker_arg], "-version") == 0) { + } else if (std::strcmp(argv[linker_arg], "-version") == 0) { kLinkerSplash(); return NECTI_SUCCESS; - } else if (StringCompare(argv[linker_arg], "-fat") == 0) { + } else if (std::strcmp(argv[linker_arg], "-fat") == 0) { kFatBinaryEnable = true; continue; - } else if (StringCompare(argv[linker_arg], "-64k") == 0) { + } else if (std::strcmp(argv[linker_arg], "-64k") == 0) { kArch = CompilerKit::kPefArch64000; continue; - } else if (StringCompare(argv[linker_arg], "-amd64") == 0) { + } else if (std::strcmp(argv[linker_arg], "-amd64") == 0) { kArch = CompilerKit::kPefArchAMD64; continue; - } else if (StringCompare(argv[linker_arg], "-32k") == 0) { + } else if (std::strcmp(argv[linker_arg], "-32k") == 0) { kArch = CompilerKit::kPefArch32000; continue; - } else if (StringCompare(argv[linker_arg], "-power64") == 0) { + } else if (std::strcmp(argv[linker_arg], "-power64") == 0) { kArch = CompilerKit::kPefArchPowerPC; continue; - } else if (StringCompare(argv[linker_arg], "-riscv64") == 0) { + } else if (std::strcmp(argv[linker_arg], "-riscv64") == 0) { kArch = CompilerKit::kPefArchRISCV; continue; - } else if (StringCompare(argv[linker_arg], "-arm64") == 0) { + } else if (std::strcmp(argv[linker_arg], "-arm64") == 0) { kArch = CompilerKit::kPefArchARM64; continue; - } else if (StringCompare(argv[linker_arg], "-verbose") == 0) { + } else if (std::strcmp(argv[linker_arg], "-verbose") == 0) { kVerbose = true; continue; - } else if (StringCompare(argv[linker_arg], "-dylib") == 0) { + } else if (std::strcmp(argv[linker_arg], "-dylib") == 0) { if (kOutput.empty()) { continue; } @@ -146,7 +143,7 @@ NECTI_MODULE(DynamicLinker64PEF) { is_executable = false; continue; - } else if (StringCompare(argv[linker_arg], "-output") == 0) { + } else if (std::strcmp(argv[linker_arg], "-output") == 0) { if ((linker_arg + 1) > argc) continue; kOutput = argv[linker_arg + 1]; @@ -279,7 +276,7 @@ NECTI_MODULE(DynamicLinker64PEF) { CompilerKit::PEFCommandHeader command_header{0}; std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; - MemoryCopy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); + std::memcpy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); CompilerKit::STLString cmd_hdr_name(command_header.Name); @@ -474,7 +471,7 @@ NECTI_MODULE(DynamicLinker64PEF) { } } - MemoryCopy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); + std::memcpy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); abi_cmd_hdr.Size = abi.size(); abi_cmd_hdr.Offset = output_fc.tellp(); @@ -490,7 +487,7 @@ NECTI_MODULE(DynamicLinker64PEF) { stack_cmd_hdr.Size = sizeof(uintptr_t); stack_cmd_hdr.Offset = 0; - MemoryCopy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); + std::memcpy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); command_headers.push_back(stack_cmd_hdr); @@ -507,8 +504,8 @@ NECTI_MODULE(DynamicLinker64PEF) { uuids::uuid id = gen(); auto uuidStr = uuids::to_string(id); - MemoryCopy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - MemoryCopy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); + std::memcpy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + std::memcpy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name); uuid_cmd_hdr.Offset = output_fc.tellp(); @@ -533,7 +530,7 @@ NECTI_MODULE(DynamicLinker64PEF) { end_exec_hdr.Flags = CompilerKit::kPefLinkerID; end_exec_hdr.Kind = CompilerKit::kPefZero; - MemoryCopy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); + std::memcpy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); end_exec_hdr.Size = strlen(end_exec_hdr.Name); diff --git a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc index aaa5793..3a649a7 100644 --- a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc +++ b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc @@ -740,14 +740,14 @@ NECTI_MODULE(CPlusPlusPreprocessorMain) { Detail::bpp_macro macro_unreachable; macro_unreachable.fName = "__unreachable"; - macro_unreachable.fValue = "__libcompiler_unreachable"; + macro_unreachable.fValue = "__compilerkit_unreachable"; kMacros.push_back(macro_unreachable); Detail::bpp_macro macro_unused; macro_unreachable.fName = "__unused"; - macro_unreachable.fValue = "__libcompiler_unused"; + macro_unreachable.fValue = "__compilerkit_unused"; kMacros.push_back(macro_unused); diff --git a/dev/LibC++/__abi+unreachable.cc b/dev/LibC++/__abi+unreachable.cc index 90c50e1..fb1d336 100644 --- a/dev/LibC++/__abi+unreachable.cc +++ b/dev/LibC++/__abi+unreachable.cc @@ -9,7 +9,7 @@ static const int32_t __unreachable_code = 34; -extern "C" void __libcompiler_unreachable(void) { +extern "C" void __compilerkit_unreachable(void) { std::base_process::signal(__unreachable_code); while (1); diff --git a/dev/LibC++/__abi.h b/dev/LibC++/__abi.h index 48d4449..9e46689 100644 --- a/dev/LibC++/__abi.h +++ b/dev/LibC++/__abi.h @@ -6,4 +6,4 @@ #pragma once -extern "C" void __libcompiler_unreachable(void); +extern "C" void __compilerkit_unreachable(void); -- cgit v1.2.3 From a2d091a55cdc465a4f90181f2b404bdd062dbad6 Mon Sep 17 00:00:00 2001 From: Amlal Date: Tue, 12 Aug 2025 15:25:04 +0200 Subject: feat: Linker test and improvements to the linker. Signed-off-by: Amlal --- dev/CompilerKit/ck-posix.json | 4 ++-- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 23 ++++++++++++++++------- tests/test_02_linker/CMakeLists.txt | 23 +++++++++++++++++++++++ tests/test_02_linker/linker_test.cc | 24 ++++++++++++++++++++++++ tests/test_02_linker/sample/sample.cc | 3 +++ tests/test_02_linker/sample/sample.cc.pp | 3 +++ 6 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 tests/test_02_linker/CMakeLists.txt create mode 100644 tests/test_02_linker/linker_test.cc create mode 100644 tests/test_02_linker/sample/sample.cc create mode 100644 tests/test_02_linker/sample/sample.cc.pp (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/ck-posix.json b/dev/CompilerKit/ck-posix.json index e80ce65..e3ff231 100644 --- a/dev/CompilerKit/ck-posix.json +++ b/dev/CompilerKit/ck-posix.json @@ -11,7 +11,7 @@ "src/*.cc", "src/*/*.cc" ], - "output_name": "/usr/local/lib/libCompilerKit.so", + "output_name": "/usr/lib/libCompilerKit.so", "compiler_flags": [ "-fPIC", "-shared" @@ -21,4 +21,4 @@ "CK_USE_STRUCTS=1", "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" ] -} \ No newline at end of file +} diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 6c8ca95..917b592 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -62,6 +62,8 @@ static Bool kDuplicateSymbols = false; static const Char* kLdDefineSymbol = ":UndefinedSymbol:"; static const Char* kLdDynamicSym = ":RuntimeSymbol:"; +static CompilerKit::STLString kLinkerStart = kPefStart; + /* object code and list. */ static std::vector kObjectList; static std::vector kObjectBytes; @@ -71,7 +73,7 @@ static std::vector kObjectBytes; NECTI_MODULE(DynamicLinker64PEF) { bool is_executable = true; - ::signal(SIGSEGV, Detail::drvi_crash_handler); + CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); /** * @brief parse flags and trigger options. @@ -109,6 +111,13 @@ NECTI_MODULE(DynamicLinker64PEF) { } else if (std::strcmp(argv[linker_arg], "-amd64") == 0) { kArch = CompilerKit::kPefArchAMD64; + continue; + } else if (std::strcmp(argv[linker_arg], "-start") == 0) { + if (argv[linker_arg + 1] == nullptr || argv[linker_arg][0] == '-') continue; + + kLinkerStart = argv[linker_arg + 1]; + linker_arg += 2; + continue; } else if (std::strcmp(argv[linker_arg], "-32k") == 0) { kArch = CompilerKit::kPefArch32000; @@ -284,7 +293,7 @@ NECTI_MODULE(DynamicLinker64PEF) { if (cmd_hdr_name.find(kPefCode64) == CompilerKit::STLString::npos && cmd_hdr_name.find(kPefData64) == CompilerKit::STLString::npos && cmd_hdr_name.find(kPefZero64) == CompilerKit::STLString::npos) { - if (cmd_hdr_name.find(kPefStart) == CompilerKit::STLString::npos && + if (cmd_hdr_name.find(kLinkerStart) == CompilerKit::STLString::npos && *command_header.Name == 0) { if (cmd_hdr_name.find(kLdDefineSymbol) != CompilerKit::STLString::npos) { goto ld_mark_header; @@ -294,7 +303,7 @@ NECTI_MODULE(DynamicLinker64PEF) { } } - if (cmd_hdr_name.find(kPefStart) != CompilerKit::STLString::npos && + if (cmd_hdr_name.find(kLinkerStart) != CompilerKit::STLString::npos && cmd_hdr_name.find(kPefCode64) != CompilerKit::STLString::npos) { kStartFound = true; } @@ -422,11 +431,11 @@ NECTI_MODULE(DynamicLinker64PEF) { if (!kStartFound && is_executable) { if (kVerbose) - kConsoleOut << "Undefined entrypoint: " << kPefStart + kConsoleOut << "Undefined entrypoint: " << kLinkerStart << ", you may have forget to link " "against the C++ runtime library.\n"; - kConsoleOut << "Undefined entrypoint " << kPefStart << " for executable: " << kOutput << "\n"; + kConsoleOut << "Undefined entrypoint " << kLinkerStart << " for executable: " << kOutput << "\n"; } // step 4: write all PEF commands. @@ -560,9 +569,9 @@ NECTI_MODULE(DynamicLinker64PEF) { CompilerKit::STLString name = command_headers[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. + /// it is always a code64 container. And should equal to kLinkerStart as well. /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != CompilerKit::STLString::npos && + if (name.find(kLinkerStart) != CompilerKit::STLString::npos && name.find(kPefCode64) != CompilerKit::STLString::npos) { pef_container.Start = command_headers[commandHeaderIndex].Offset; auto tellCurPos = output_fc.tellp(); diff --git a/tests/test_02_linker/CMakeLists.txt b/tests/test_02_linker/CMakeLists.txt new file mode 100644 index 0000000..f3493fc --- /dev/null +++ b/tests/test_02_linker/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.10) +project(NeCTILinkerTest) + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +enable_testing() + +add_executable(LinkerTestBasic linker_test.cc) +target_link_libraries(LinkerTestBasic gtest_main) + +set_property(TARGET LinkerTestBasic PROPERTY CXX_STANDARD 20) +target_include_directories(LinkerTestBasic PUBLIC ../../) + +include(GoogleTest) +gtest_discover_tests(LinkerTestBasic) diff --git a/tests/test_02_linker/linker_test.cc b/tests/test_02_linker/linker_test.cc new file mode 100644 index 0000000..88d51de --- /dev/null +++ b/tests/test_02_linker/linker_test.cc @@ -0,0 +1,24 @@ +/* ------------------------------------------- + + Copyright (C) 2024-2025 Amlal EL Mahrouss, all rights reserved + + ------------------------------------------- */ + + +/// @brief Linker Unit test, from the C++ unit to the final executable. +/// @author Amlal El Mahrouss + +#include + +TEST(LinkerTest, BasicLinkTest) +{ + /// @note this is the driver, it will look for a .cc.pp (.pp stands for pre-processed) + auto expr = std::system("pef-amd64-cxxdrv sample/sample.cc"); + EXPECT_TRUE(expr == 0) << "C++ Driver did not compile the easy C++ unit."; + + expr = std::system("asm -asm:x64 sample/sample.cc.pp.masm"); + EXPECT_TRUE(expr == 0) << "Assembler did not assemble the easy asm unit."; + + expr = std::system("ld64 -fat-binary sample/sample.cc.pp.obj -start __NECTI_main -output main.exec"); + EXPECT_TRUE(expr == 0) << "Linker did not link the easy object."; +} diff --git a/tests/test_02_linker/sample/sample.cc b/tests/test_02_linker/sample/sample.cc new file mode 100644 index 0000000..4cce7f6 --- /dev/null +++ b/tests/test_02_linker/sample/sample.cc @@ -0,0 +1,3 @@ +int main() { + return 0; +} diff --git a/tests/test_02_linker/sample/sample.cc.pp b/tests/test_02_linker/sample/sample.cc.pp new file mode 100644 index 0000000..cb3f748 --- /dev/null +++ b/tests/test_02_linker/sample/sample.cc.pp @@ -0,0 +1,3 @@ +int main() { + return 0; +} -- cgit v1.2.3 From 2a36b103240c5724d2a4a8dc4820d2ceea72e56b Mon Sep 17 00:00:00 2001 From: Amlal Date: Tue, 12 Aug 2025 15:32:30 +0200 Subject: feat: ld64: Fix linker issues with start symbol fetch. feat: tests: add linker test. Signed-off-by: Amlal --- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 4 ++-- tests/test_02_linker/linker_test.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 917b592..946a3c7 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -113,10 +113,10 @@ NECTI_MODULE(DynamicLinker64PEF) { continue; } else if (std::strcmp(argv[linker_arg], "-start") == 0) { - if (argv[linker_arg + 1] == nullptr || argv[linker_arg][0] == '-') continue; + if (argv[linker_arg + 1] == nullptr || argv[linker_arg + 1][0] == '-') continue; kLinkerStart = argv[linker_arg + 1]; - linker_arg += 2; + linker_arg += 1; continue; } else if (std::strcmp(argv[linker_arg], "-32k") == 0) { diff --git a/tests/test_02_linker/linker_test.cc b/tests/test_02_linker/linker_test.cc index 88d51de..7f220f7 100644 --- a/tests/test_02_linker/linker_test.cc +++ b/tests/test_02_linker/linker_test.cc @@ -19,6 +19,6 @@ TEST(LinkerTest, BasicLinkTest) expr = std::system("asm -asm:x64 sample/sample.cc.pp.masm"); EXPECT_TRUE(expr == 0) << "Assembler did not assemble the easy asm unit."; - expr = std::system("ld64 -fat-binary sample/sample.cc.pp.obj -start __NECTI_main -output main.exec"); + expr = std::system("ld64 -amd64 sample/sample.cc.pp.obj -start __NECTI_main -output main.exec"); EXPECT_TRUE(expr == 0) << "Linker did not link the easy object."; } -- cgit v1.2.3 From 0c33b7b88bb3a96f1967937c7b7e0ff348a3d131 Mon Sep 17 00:00:00 2001 From: Amlal Date: Tue, 12 Aug 2025 19:38:55 +0200 Subject: abi! breaking ABI changes, PEF linker has been updated. Signed-off-by: Amlal --- dev/CompilerKit/PEF.h | 1 + dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/PEF.h b/dev/CompilerKit/PEF.h index a1feec6..b3950c1 100644 --- a/dev/CompilerKit/PEF.h +++ b/dev/CompilerKit/PEF.h @@ -95,6 +95,7 @@ typedef struct PEFCommandHeader final { UInt32 Flags; /* container flags */ UInt16 Kind; /* container kind */ UIntPtr Offset; /* File offset */ + SizeType OffsetSize; UIntPtr VMAddress; /* Virtual Address */ SizeType Size; /* Virtual Size */ } PACKED PEFCommandHeader, *PEFCommandHeaderPtr; diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 946a3c7..55ba9b4 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -313,8 +313,9 @@ NECTI_MODULE(DynamicLinker64PEF) { command_header.Kind = ae_records[ae_record_index].fKind; command_header.Size = ae_records[ae_record_index].fSize; command_header.Cpu = hdr.fArch; - command_header.VMAddress = org; /// TODO: + command_header.VMAddress = org; command_header.SubCpu = hdr.fSubArch; + command_header.OffsetSize = ae_records[ae_record_index].fSize; org += command_header.Size; -- cgit v1.2.3 From d02783c473d0bc70b3160591ffd949e43abc5ec5 Mon Sep 17 00:00:00 2001 From: Amlal Date: Fri, 15 Aug 2025 18:06:05 +0200 Subject: refactor: ld64: use STLString instead of constructing it each time. Signed-off-by: Amlal --- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 55ba9b4..0b842c2 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -374,10 +374,12 @@ NECTI_MODULE(DynamicLinker64PEF) { CompilerKit::STLString::npos) { if (kVerbose) kConsoleOut << "Found undefined symbol: " << command_hdr.Name << "\n"; + CompilerKit::STLString cmd_hdr_name = command_hdr.Name; + if (auto it = std::find(not_found.begin(), not_found.end(), - CompilerKit::STLString(command_hdr.Name)); + cmd_hdr_name); it == not_found.end()) { - not_found.emplace_back(command_hdr.Name); + not_found.emplace_back(cmd_hdr_name); } } -- cgit v1.2.3 From 5b4ec3bd557014b61c1e0b0b3279086c7d9e6653 Mon Sep 17 00:00:00 2001 From: Amlal Date: Fri, 15 Aug 2025 18:09:33 +0200 Subject: fix: Pushing missing feature of last commit. Signed-off-by: Amlal --- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index 0b842c2..cfd5079 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -366,6 +366,8 @@ NECTI_MODULE(DynamicLinker64PEF) { // step 2: check for errors (multiple symbols, undefined ones) + CompilerKit::STLString cmd_hdr_name; + for (auto& command_hdr : command_headers) { // check if this symbol needs to be resolved. if (CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) != @@ -374,7 +376,7 @@ NECTI_MODULE(DynamicLinker64PEF) { CompilerKit::STLString::npos) { if (kVerbose) kConsoleOut << "Found undefined symbol: " << command_hdr.Name << "\n"; - CompilerKit::STLString cmd_hdr_name = command_hdr.Name; + cmd_hdr_name = command_hdr.Name; if (auto it = std::find(not_found.begin(), not_found.end(), cmd_hdr_name); -- cgit v1.2.3 From b71c7caf229abc4b24f79646fcd37af52f4bc918 Mon Sep 17 00:00:00 2001 From: Amlal Date: Fri, 15 Aug 2025 23:59:49 +0200 Subject: feat! breaking ABI changes (AE object format) now has a version field. Signed-off-by: Amlal --- dev/CompilerKit/AE.h | 23 +++++++++++++---------- dev/CompilerKit/PEF.h | 14 ++++++++++---- dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 20 ++++++++++---------- 3 files changed, 33 insertions(+), 24 deletions(-) (limited to 'dev/CompilerKit/src') diff --git a/dev/CompilerKit/AE.h b/dev/CompilerKit/AE.h index 6561baf..1c334ad 100644 --- a/dev/CompilerKit/AE.h +++ b/dev/CompilerKit/AE.h @@ -11,8 +11,10 @@ #include -#define kAEMag0 'A' -#define kAEMag1 'E' +#define kAEVer (0x0120) + +#define kAEMag0 'O' +#define kAEMag1 'B' #define kAESymbolLen (255) #define kAEPad (8) @@ -31,14 +33,15 @@ namespace CompilerKit { // One thing to keep in mind. // This object format, is reloctable. typedef struct AEHeader final { - Char fMagic[kAEMagLen]; - Char fArch; - Char fSubArch; - SizeType fCount; - Char fSize; - SizeType fStartCode; - SizeType fCodeSize; - Char fPad[kAEPad]; + Char fMagic[kAEMagLen] = {}; + UInt16 fVersion{kAEVer}; + Char fArch{}; + Char fSubArch{}; + SizeType fCount{}; + Char fSize{}; + SizeType fStartCode{}; + SizeType fCodeSize{}; + Char fPad[kAEPad] = {}; } PACKED AEHeader, *AEHeaderPtr; // @brief Advanced Executable Record. diff --git a/dev/CompilerKit/PEF.h b/dev/CompilerKit/PEF.h index b3950c1..a997f17 100644 --- a/dev/CompilerKit/PEF.h +++ b/dev/CompilerKit/PEF.h @@ -29,6 +29,7 @@ #define kPefCode64 ".code64" #define kPefData64 ".data64" +/* @note counting the \0 at the end */ #define kPefMagicLen (5) #define kPefVersion (0x0500) @@ -36,9 +37,11 @@ #define kPefBaseOrigin (0x40000000) +/* @note this doesn't have to be __ImageStart only, any C initialization stub will do. */ #define kPefStart "__ImageStart" namespace CompilerKit { + /* @brief Architecture type. */ enum { kPefArchIntel86S, kPefArchAMD64, @@ -51,8 +54,9 @@ enum { kPefArchInvalid = 0xFF, }; + /* @brief Architecture vendor. */ enum { - kPefSubArchGeneric, + kPefSubArchGeneric = 0, kPefSubArchAMD = 200, kPefSubArchIntel, kPefSubArchARM, @@ -60,6 +64,7 @@ enum { }; enum { + kPefKindInvalid = 0, kPefKindExec = 1, /* .exec */ kPefKindDylib = 2, /* .dylib */ kPefKindObject = 4, /* .obj */ @@ -68,7 +73,7 @@ enum { kPefKindCount, }; -/* PEF container */ +/* PEF container information */ typedef struct PEFContainer final { Char Magic[kPefMagicLen]; UInt32 Linker; /* Linker used to link executable */ @@ -88,6 +93,7 @@ typedef struct PEFContainer final { /* PEF executable section and commands. */ + /* @brief Command Header, a la Mach-O, designed with FAT binaries and virtual memory in mind. */ typedef struct PEFCommandHeader final { Char Name[kPefNameLen]; /* container name */ UInt32 Cpu; /* container cpu */ @@ -96,8 +102,8 @@ typedef struct PEFCommandHeader final { UInt16 Kind; /* container kind */ UIntPtr Offset; /* File offset */ SizeType OffsetSize; - UIntPtr VMAddress; /* Virtual Address */ - SizeType Size; /* Virtual Size */ + UIntPtr VirtualAddress; /* Virtual Address */ + SizeType VirtualSize; /* Virtual Size */ } PACKED PEFCommandHeader, *PEFCommandHeaderPtr; enum { diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc index cfd5079..04dda25 100644 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc @@ -311,13 +311,13 @@ NECTI_MODULE(DynamicLinker64PEF) { ld_mark_header: command_header.Offset = offset_of_obj; command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; + command_header.VirtualSize = ae_records[ae_record_index].fSize; command_header.Cpu = hdr.fArch; - command_header.VMAddress = org; + command_header.VirtualAddress = org; command_header.SubCpu = hdr.fSubArch; command_header.OffsetSize = ae_records[ae_record_index].fSize; - org += command_header.Size; + org += command_header.VirtualSize; if (kVerbose) { kConsoleOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; @@ -457,7 +457,7 @@ NECTI_MODULE(DynamicLinker64PEF) { date_cmd_hdr.Flags = 0; date_cmd_hdr.Kind = CompilerKit::kPefZero; date_cmd_hdr.Offset = output_fc.tellp(); - date_cmd_hdr.Size = timeStampStr.size(); + date_cmd_hdr.VirtualSize = timeStampStr.size(); command_headers.push_back(date_cmd_hdr); @@ -487,7 +487,7 @@ NECTI_MODULE(DynamicLinker64PEF) { std::memcpy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); - abi_cmd_hdr.Size = abi.size(); + abi_cmd_hdr.VirtualSize = abi.size(); abi_cmd_hdr.Offset = output_fc.tellp(); abi_cmd_hdr.Flags = 0; abi_cmd_hdr.Kind = CompilerKit::kPefLinkerID; @@ -498,7 +498,7 @@ NECTI_MODULE(DynamicLinker64PEF) { stack_cmd_hdr.Cpu = kArch; stack_cmd_hdr.Flags = 0; - stack_cmd_hdr.Size = sizeof(uintptr_t); + stack_cmd_hdr.VirtualSize = sizeof(uintptr_t); stack_cmd_hdr.Offset = 0; std::memcpy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); @@ -521,7 +521,7 @@ NECTI_MODULE(DynamicLinker64PEF) { std::memcpy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); std::memcpy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); - uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name); + uuid_cmd_hdr.VirtualSize = strlen(uuid_cmd_hdr.Name); uuid_cmd_hdr.Offset = output_fc.tellp(); uuid_cmd_hdr.Flags = CompilerKit::kPefLinkerID; uuid_cmd_hdr.Kind = CompilerKit::kPefZero; @@ -546,7 +546,7 @@ NECTI_MODULE(DynamicLinker64PEF) { std::memcpy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); - end_exec_hdr.Size = strlen(end_exec_hdr.Name); + end_exec_hdr.VirtualSize = strlen(end_exec_hdr.Name); command_headers.push_back(end_exec_hdr); @@ -569,7 +569,7 @@ NECTI_MODULE(DynamicLinker64PEF) { } command_headers[commandHeaderIndex].Offset += previous_offset; - previous_offset += command_headers[commandHeaderIndex].Size; + previous_offset += command_headers[commandHeaderIndex].VirtualSize; CompilerKit::STLString name = command_headers[commandHeaderIndex].Name; @@ -589,7 +589,7 @@ NECTI_MODULE(DynamicLinker64PEF) { if (kVerbose) { kConsoleOut << "Command name: " << name << "\n"; - kConsoleOut << "VMAddress of command content: " << command_headers[commandHeaderIndex].Offset + kConsoleOut << "VirtualAddress of command content: " << command_headers[commandHeaderIndex].Offset << "\n"; } -- cgit v1.2.3