summaryrefslogtreecommitdiffhomepage
path: root/dev/CompilerKit/src
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal@nekernel.org>2025-07-30 08:50:15 +0100
committerAmlal El Mahrouss <amlal@nekernel.org>2025-07-30 08:50:15 +0100
commit1c8c5cff67b20d86c442b0917d6c1fc6407140df (patch)
tree53ebea660bef14cdc2ff5b7ebefb4049f705f997 /dev/CompilerKit/src
parent073811d89c98d6e1c078a032ca2eedefebf80384 (diff)
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 <amlal@nekernel.org>
Diffstat (limited to 'dev/CompilerKit/src')
-rw-r--r--dev/CompilerKit/src/Backend/Assembler32x0.cc39
-rw-r--r--dev/CompilerKit/src/Backend/Assembler64x0.cc874
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerAMD64.cc1206
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerARM64.cc587
-rw-r--r--dev/CompilerKit/src/Backend/AssemblerPowerPC.cc911
-rw-r--r--dev/CompilerKit/src/BasicString.cc207
-rw-r--r--dev/CompilerKit/src/CodeGen.cc52
-rw-r--r--dev/CompilerKit/src/Frontend.cc51
-rw-r--r--dev/CompilerKit/src/Frontend/CCompiler64x0.cc1286
-rw-r--r--dev/CompilerKit/src/Frontend/CCompilerARM64.cc1284
-rw-r--r--dev/CompilerKit/src/Frontend/CCompilerPower64.cc1303
-rw-r--r--dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc892
-rw-r--r--dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc672
-rw-r--r--dev/CompilerKit/src/Macro/CPlusPlusCompilerPreProcessor.cc893
14 files changed, 10257 insertions, 0 deletions
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 <CompilerKit/AE.h>
+#include <CompilerKit/detail/32x0.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @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 <CompilerKit/AE.h>
+#include <CompilerKit/detail/64x0.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// 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<std::pair<std::string, std::uintptr_t>> kOriginLabel;
+
+static std::vector<e64k_num_t> kBytes;
+
+static CompilerKit::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<CompilerKit::AERecordHeader> kRecords;
+static std::vector<std::string> 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<const char*>(&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<std::string> operands_inst = {"stw", "ldw", "lda", "sta"};
+
+ // these don't.
+ std::vector<std::string> 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 <CompilerKit/AE.h>
+#include <CompilerKit/detail/X64.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <algorithm>
+#include <cstdlib>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// 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<std::pair<std::string, std::uintptr_t>> kOriginLabel;
+
+/// @brief keep it simple by default.
+static std::int32_t kRegisterBitWidth = 16U;
+
+static std::vector<i64_byte_t> kAppBytes;
+
+static CompilerKit::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<CompilerKit::AERecordHeader> kRecords;
+static std::vector<std::string> kDefinedSymbols;
+static std::vector<std::string> kUndefinedSymbols;
+
+static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
+
+// \brief forward decl.
+static bool asm_read_attributes(std::string line);
+
+#include <CompilerKit/utils/AsmUtils.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @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<i64_hword_t>(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<const char*>(&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<RegMapAMD64> 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<RegMapAMD64> currentRegList;
+
+ for (auto& reg : kRegisterList) {
+ std::vector<char> 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 <CompilerKit/AE.h>
+#include <CompilerKit/detail/Aarch64.h>
+#include <CompilerKit/ErrorID.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/utils/AsmUtils.h>
+#include <CompilerKit/Version.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// 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<std::pair<std::string, std::uintptr_t>> kOriginLabel;
+
+static std::vector<uint8_t> kBytes;
+
+static CompilerKit::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<CompilerKit::AERecordHeader> kRecords;
+static std::vector<std::string> 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<const char*>(&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 <CompilerKit/AE.h>
+#include <CompilerKit/detail/PowerPC.h>
+#include <CompilerKit/ErrorID.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/utils/AsmUtils.h>
+#include <CompilerKit/Version.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// 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<std::pair<std::string, std::uintptr_t>> kOriginLabel;
+
+static std::vector<uint8_t> kBytes;
+
+static CompilerKit::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<CompilerKit::AERecordHeader> kRecords;
+static std::vector<std::string> 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<const char*>(&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<std::string> operands_inst = {"stw", "li"};
+
+ // these don't.
+ std::vector<std::string> 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<size_t> 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 <CompilerKit/BasicString.h>
+
+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 <CompilerKit/CodeGen.h>
+#include <CompilerKit/ErrorID.h>
+
+/**
+ * @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 <CompilerKit/Frontend.h>
+
+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 <CompilerKit/detail/64x0.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/UUID.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+
+/* 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<std::pair<Int32, std::string>> fOffsets;
+};
+
+struct CompilerState final {
+ std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> 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<std::string> 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<Detail::CompilerType> kCompilerVariables;
+static std::vector<std::string> kCompilerFunctions;
+static std::vector<Detail::CompilerType> 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<int, std::mt19937::state_size>{};
+ 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<std::string> 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<CompilerVariableRange> 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<char> opens;
+ std::vector<char> 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<const char*> exts = kAsmFileExts;
+ dest += exts[4];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(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<std::string> keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"};
+
+ ///
+ /// Replace, optimize, fix assembly output.
+ ///
+
+ for (auto& leaf : kState.fSyntaxTree->fLeafList) {
+ std::vector<std::string> 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 <CompilerKit/Version.h>
+
+#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 <CompilerKit/detail/Aarch64.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/UUID.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+
+/* 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<std::pair<Int32, std::string>> fOffsets;
+};
+
+struct CompilerState final {
+ std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> 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<std::string> 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<Detail::CompilerType> kCompilerVariables;
+static std::vector<std::string> kCompilerFunctions;
+static std::vector<Detail::CompilerType> 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<int, std::mt19937::state_size>{};
+ 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<std::string> 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<CompilerVariableRange> 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<char> opens;
+ std::vector<char> 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<const char*> exts = kAsmFileExts;
+ dest += exts[4];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(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<std::string> keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"};
+
+ ///
+ /// Replace, optimize, fix assembly output.
+ ///
+
+ for (auto& leaf : kState.fSyntaxTree->fLeafList) {
+ std::vector<std::string> 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 <CompilerKit/Version.h>
+
+#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 <CompilerKit/detail/PowerPC.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/UUID.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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<std::pair<Int32, std::string>> fOffsets;
+};
+
+struct CompilerState final {
+ std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> 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<std::string> 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<Detail::CompilerType> kCompilerVariables;
+static std::vector<std::string> kCompilerFunctions;
+static std::vector<Detail::CompilerType> 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<int, std::mt19937::state_size>{};
+ 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<std::string> 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<CompilerVariableRange> 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<char> opens;
+ std::vector<char> 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<const char*> exts = kAsmFileExts;
+ dest += exts[4];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(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<std::string> keywords = {"ld", "stw", "add", "sub", "or"};
+
+ ///
+ /// Replace, optimize, fix assembly output.
+ ///
+
+ for (auto& leaf : kState.fSyntaxTree->fLeafList) {
+ std::vector<std::string> 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 <CompilerKit/Version.h>
+
+#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 <CompilerKit/detail/X64.h>
+#include <CompilerKit/Frontend.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/UUID.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+
+/* 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<std::pair<UInt32, CompilerKit::STLString>> fOffsets;
+};
+
+/// \brief Compiler state structure.
+struct CompilerState final {
+ std::vector<CompilerRegisterMap> fStackMapVector;
+ std::vector<CompilerStructMap> 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<CompilerKit::CompilerKeyword> 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<CompilerKit::STLString> kRegisterMap;
+
+static std::vector<CompilerKit::STLString> 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<CompilerKit::STLString> 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<std::pair<CompilerKit::STLString, std::uintptr_t>> 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<std::pair<CompilerKit::CompilerKeyword, std::size_t>> 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<CompilerKit::STLString, std::uintptr_t> 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<CompilerKit::STLString> 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<CompilerKit::STLString, std::uintptr_t> 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<CompilerKit::STLString> 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 <CompilerKit/Defines.h>
+#include <CompilerKit/ErrorID.h>
+#include <CompilerKit/CodeGen.h>
+#include <CompilerKit/PEF.h>
+#include <CompilerKit/UUID.h>
+#include <CompilerKit/Version.h>
+#include <CompilerKit/AE.h>
+#include <CompilerKit/utils/CompilerUtils.h>
+
+#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<CompilerKit::STLString> kObjectList;
+static std::vector<Detail::DynamicLinkerBlob> 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<CompilerKit::PEFCommandHeader> 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<char> 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<CompilerKit::STLString> not_found;
+ std::vector<CompilerKit::STLString> 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<int, std::mt19937::state_size>{};
+ 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<CompilerKit::STLString> undef_symbols;
+ std::vector<CompilerKit::STLString> dupl_symbols;
+ std::vector<CompilerKit::STLString> 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<CompilerKit::STLString> 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 <CompilerKit/ErrorID.h>
+#include <CompilerKit/Frontend.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <vector>
+
+#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<CompilerKit::STLString> 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<CompilerKit::STLString> kFiles;
+static std::vector<Detail::bpp_macro> kMacros;
+static std::vector<CompilerKit::STLString> 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<CompilerKit::STLString> 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<CompilerKit::STLString> 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<CompilerKit::STLString> 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<Detail::bpp_macro_condition> 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 <path>: set directory to working path.");
+ printf("%s\n", "-cpp-include-dir <path>: add directory to include path.");
+ printf("%s\n", "-cpp-def <name> <value>: 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