summaryrefslogtreecommitdiffhomepage
path: root/Sources
diff options
context:
space:
mode:
Diffstat (limited to 'Sources')
-rw-r--r--Sources/32asm.cc52
-rw-r--r--Sources/64asm.cc954
-rw-r--r--Sources/64x0-cc.cc1354
-rw-r--r--Sources/AsmKit.cc51
-rw-r--r--Sources/Detail/ReadMe.md3
-rw-r--r--Sources/Detail/asmutils.h111
-rw-r--r--Sources/Detail/compilerutils.h14
-rw-r--r--Sources/String.cc198
-rw-r--r--Sources/amd64-cplusplus.cc397
-rw-r--r--Sources/bpp.cc898
-rw-r--r--Sources/coff2ae.cc22
-rw-r--r--Sources/compile_flags.txt5
-rw-r--r--Sources/elf2ae.cc22
-rw-r--r--Sources/i64asm.cc1247
-rw-r--r--Sources/link.cc641
-rw-r--r--Sources/ppc-cc.cc1368
-rw-r--r--Sources/ppcasm.cc977
17 files changed, 0 insertions, 8314 deletions
diff --git a/Sources/32asm.cc b/Sources/32asm.cc
deleted file mode 100644
index e5aa500..0000000
--- a/Sources/32asm.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-/// bugs: 0
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @file 32asm.cxx
-// @author Amlal El Mahrouss
-// @brief 32x0 Assembler.
-
-// REMINDER: when dealing with an undefined symbol use (string
-// size):LinkerFindSymbol:(string) so that ld will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define __ASM_NEED_32x0__ 1
-
-#include <Headers/AsmKit/CPU/32x0.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#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"
-
-#define kStdOut (std::cout << kWhite)
-#define kStdErr (std::cout << kRed)
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief 32x0 Assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSAssembler32000) { return 0; }
diff --git a/Sources/64asm.cc b/Sources/64asm.cc
deleted file mode 100644
index d2568e2..0000000
--- a/Sources/64asm.cc
+++ /dev/null
@@ -1,954 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-/// bugs: 0
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @file 64asm.cxx
-// @author Amlal El Mahrouss
-// @brief 64x0 Assembler.
-
-// REMINDER: when dealing with an undefined symbol use (string
-// size):LinkerFindSymbol:(string) so that ld will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define __ASM_NEED_64x0__ 1
-
-#include <Headers/AsmKit/CPU/64x0.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#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"
-
-#define kStdOut (std::cout << kWhite)
-#define kStdErr (std::cout << kRed)
-
-static char kOutputArch = CompilerKit::kPefArch64000;
-static Boolean kOutputAsBinary = false;
-
-static UInt32 kErrorLimit = 10;
-static UInt32 kAcceptableErrors = 0;
-
-constexpr auto c64x0IPAlignment = 0x4U;
-
-static std::size_t kCounter = 1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-static bool kVerbose = false;
-
-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);
-
-namespace detail {
-void print_error(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- kStdErr << kRed << "[ 64asm ] " << kWhite
- << ((file == "64asm") ? "internal assembler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- kStdErr << kRed << "[ 64asm ] " << kWhite << reason << kBlank << std::endl;
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-void print_warning(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (!file.empty()) {
- kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl;
- }
-
- kStdOut << kYellow << "[ 64asm ] " << kWhite << reason << kBlank << std::endl;
-}
-} // namespace detail
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief 64x0 assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSAssembler64000) {
- for (size_t i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) {
- kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) "
- "2024 Mahrouss Logic.\n";
- return 0;
- } else if (strcmp(argv[i], "-h") == 0) {
- kStdOut << "64asm: 64x0 Assembler.\n64asm: 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], "-binary") == 0) {
- kOutputAsBinary = true;
- continue;
- } else if (strcmp(argv[i], "-verbose") == 0) {
- kVerbose = true;
- continue;
- }
-
- kStdOut << "64asm: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "64asm: 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 << "64asm: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAEInvalidOpcode, 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, "64asm");
- }
-
- std::filesystem::remove(object_output);
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "64asm: 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 << "64asm: At least one record is needed to write an object "
- "file.\n64asm: Make one using `export .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 << "64asm: 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 << "64asm: Wrote symbol " << sym << " to file...\n";
-
- _record_hdr.fKind = kAEInvalidOpcode;
- _record_hdr.fSize = sym.size();
- _record_hdr.fOffset = record_count;
-
- ++record_count;
-
- memset(_record_hdr.fPad, kAEInvalidOpcode, 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 << "64asm: 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 << "64asm: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "64asm: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "64asm: Exit failed.\n";
-
- return -1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string &line) {
- // import is the opposite of export, it signals to the ld
- // that we need this symbol.
- if (ParserKit::find_word(line, "import")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid import directive in flat binary mode.",
- "64asm");
- throw std::runtime_error("invalid_import_bin");
- }
-
- auto name = line.substr(line.find("import") + strlen("import"));
-
- /// sanity check to avoid stupid linker errors.
- if (name.size() == 0) {
- detail::print_error("Invalid import", "ppcasm");
- throw std::runtime_error("invalid_import");
- }
-
- 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, kAEInvalidOpcode, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // export is a special keyword used by 64asm to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64.,
- // .zero64
- else if (ParserKit::find_word(line, "export")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid export directive in flat binary mode.",
- "64asm");
- throw std::runtime_error("invalid_export_bin");
- }
-
- auto name = line.substr(line.find("export") + strlen("export"));
-
- 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, kAEInvalidOpcode, 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(const 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,
- const std::string &file) {
- std::string err_str;
-
- if (line.empty() || ParserKit::find_word(line, "import") ||
- ParserKit::find_word(line, "export") ||
- line.find('#') != std::string::npos || ParserKit::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(line)) {
- err_str = "Line contains non alphanumeric characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!detail::algorithm::is_valid(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 (ParserKit::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, "64asm");
- 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 << "64asm: 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, "64asm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "64asm: 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, "64asm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "64asm: 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 << "64asm: 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,
- const std::string &file) {
- if (ParserKit::find_word(line, "export ")) return true;
-
- for (auto &opcode64x0 : kOpcodes64x0) {
- // strict check here
- if (ParserKit::find_word(line, opcode64x0.fName) &&
- detail::algorithm::is_valid(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 << "64asm: Register found: " << register_syntax << "\n";
- kStdOut << "64asm: 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 64asm 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 == "dec") {
- 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("import ") != std::string::npos) {
- detail::print_error("invalid usage import 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("import") != std::string::npos) {
- cpy_jump_label.erase(cpy_jump_label.find("import"), strlen("import"));
-
- if (name == "sta") {
- detail::print_error("import is not allowed on a sta operation.",
- file);
- throw std::runtime_error("import_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 << "64asm: 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 += c64x0IPAlignment;
-
- break;
- }
- }
-
- return true;
-}
-
-// Last rev 13-1-24
diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc
deleted file mode 100644
index c23e3c1..0000000
--- a/Sources/64x0-cc.cc
+++ /dev/null
@@ -1,1354 +0,0 @@
-/*
- * ========================================================
- *
- * cc
- * Copyright Mahrouss Logic, all rights reserved.
- *
- * ========================================================
- */
-
-/// BUGS: ?
-/// TODO:
-
-#include <Headers/AsmKit/CPU/64x0.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/UUID.hpp>
-#include <cstdio>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <random>
-#include <string>
-#include <utility>
-#include <vector>
-
-#define kOk 0
-
-/* C driver */
-/* This is part of CodeTools C SDK. */
-/* (c) Mahrouss Logic */
-
-/// @author Amlal El Mahrouss (amlel)
-/// @file 64x0-cc.cc
-/// @brief 64x0 C Compiler.
-
-/// TODO: support structures, else if, else, . and ->
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-
-/////////////////////////////////////
-
-// INTERNAL STUFF OF THE C COMPILER
-
-/////////////////////////////////////
-
-namespace detail {
-// \brief name to register struct.
-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<ParserKit::SyntaxLeafList> fSyntaxTreeList;
- std::vector<CompilerRegisterMap> kStackFrame;
- std::vector<CompilerStructMap> kStructMap;
- ParserKit::SyntaxLeafList *fSyntaxTree{nullptr};
- std::unique_ptr<std::ofstream> fOutputAssembly;
- std::string fLastFile;
- std::string fLastError;
- bool fVerbose;
-};
-} // namespace detail
-
-static detail::CompilerState kState;
-static SizeType kErrorLimit = 100;
-static std::string kIfFunction = "";
-static Int32 kAcceptableErrors = 0;
-
-namespace detail {
-void print_error(std::string reason, std::string file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (file.find(".pp") != std::string::npos) {
- file.erase(file.find(".pp"), 3);
- }
-
- if (kState.fLastFile != file) {
- std::cout << kRed << "[ cc ] " << kWhite
- << ((file == "cc") ? "internal compiler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl;
-
- kState.fLastFile = file;
- } else {
- std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite
- << reason << kBlank << std::endl;
- }
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-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 CompilerBackendCLang final : public ParserKit::CompilerBackend {
- public:
- explicit CompilerBackendCLang() = default;
- ~CompilerBackendCLang() override = default;
-
- MPCC_COPY_DEFAULT(CompilerBackendCLang);
-
- std::string Check(const char *text, const char *file);
- bool Compile(const std::string &text, const char *file) override;
-
- const char *Language() override { return "64k C"; }
-};
-
-static CompilerBackendCLang *kCompilerBackend = 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.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerBackendCLang::Compile(const std::string &text, const char *file) {
- std::string textBuffer = 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 < textBuffer.size(); ++text_index) {
- auto syntaxLeaf = ParserKit::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 = textBuffer.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 (textBuffer.find('(') != std::string::npos) {
- syntaxLeaf.fUserValue = buf;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- }
-
- typeFound = true;
- break;
- }
- }
-
- break;
- }
-
- match_type += substr[y];
- }
- }
-
- if (textBuffer[text_index] == '{') {
- if (kInStruct) {
- continue;
- }
-
- kInBraces = true;
- ++kBracesCount;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- }
-
- // return keyword handler
- if (textBuffer[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 < textBuffer.size();
- ++return_index) {
- if (textBuffer[return_index] != return_keyword[index]) {
- for (size_t value_index = return_index;
- value_index < textBuffer.size(); ++value_index) {
- if (textBuffer[value_index] == ';') break;
-
- value += textBuffer[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 += " import";
- 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 (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') {
- auto expr = textBuffer.substr(text_index + 2);
- textBuffer.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 = "__MPCC_IF_PROC_";
- kIfFunction += std::to_string(time_off._Raw);
-
- syntaxLeaf.fUserValue = "\tlda r12, import ";
- syntaxLeaf.fUserValue +=
- kIfFunction +
- "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq "
- "r10, r11, r12\ndword export .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 (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') {
- if (fnFound) continue;
- if (kIfFound) continue;
-
- if (textBuffer[text_index] == ';' && kInStruct) continue;
-
- if (textBuffer.find("typedef ") != std::string::npos) continue;
-
- if (textBuffer[text_index] == '=' && kInStruct) {
- detail::print_error("assignement of value in struct " + textBuffer,
- file);
- continue;
- }
-
- if (textBuffer[text_index] == ';' && kInStruct) {
- bool space_found_ = false;
- std::string sym;
-
- for (auto &ch : textBuffer) {
- 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 (textBuffer[text_index] == '=' && kInStruct) {
- continue;
- }
-
- if (textBuffer[text_index + 1] == '=' ||
- textBuffer[text_index - 1] == '!' ||
- textBuffer[text_index - 1] == '<' ||
- textBuffer[text_index - 1] == '>') {
- continue;
- }
-
- std::string substr;
-
- if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) {
- if (textBuffer.find("*") != std::string::npos) {
- if (textBuffer.find("=") > textBuffer.find("*"))
- substr += "\tlda ";
- else
- substr += "\tldw ";
- } else {
- substr += "\tldw ";
- }
- } else if (textBuffer.find('=') != std::string::npos && !kInBraces) {
- substr += "stw export .data64 ";
- }
-
- int first_encountered = 0;
-
- std::string str_name;
-
- for (size_t text_index_2 = 0; text_index_2 < textBuffer.size();
- ++text_index_2) {
- if (textBuffer[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 < textBuffer.size(); ++text_index_2) {
- if (textBuffer[text_index_2] == '\"') break;
-
- substr += textBuffer[text_index_2];
- }
- }
-
- if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}')
- continue;
-
- if (textBuffer[text_index_2] == ';') {
- break;
- }
-
- if (textBuffer[text_index_2] == ' ' ||
- textBuffer[text_index_2] == '\t') {
- if (first_encountered != 2) {
- if (textBuffer[text_index] != '=' &&
- substr.find("export .data64") == std::string::npos &&
- !kInStruct)
- substr += "export .data64 ";
- }
-
- ++first_encountered;
-
- continue;
- }
-
- if (textBuffer[text_index_2] == '=') {
- if (!kInBraces) {
- substr.replace(substr.find("export .data64"),
- strlen("export .data64"), "export .zero64 ");
- }
-
- substr += ",";
- continue;
- }
-
- substr += textBuffer[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"), "import ");
-
- if (substr.find("export .data64") != std::string::npos)
- substr.erase(substr.find("export .data64"), strlen("export .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 (textBuffer[text_index] == '=') break;
- }
-
- // function handler.
-
- if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) {
- std::string substr;
- std::string args_buffer;
- std::string args;
-
- bool type_crossed = false;
-
- for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size();
- ++idx) {
- if (textBuffer[idx] == ',') continue;
-
- if (textBuffer[idx] == ' ') continue;
-
- if (textBuffer[idx] == ')') break;
- }
-
- for (char substr_first_index : textBuffer) {
- 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 : textBuffer) {
- 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 += "export .code64 ";
-
- syntaxLeaf.fUserValue += substr;
- syntaxLeaf.fUserValue += "\n";
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- fnFound = true;
- }
-
- kCompilerFunctions.push_back(textBuffer);
- }
-
- if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') {
- textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), "");
-
- for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) {
- if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ')
- textBuffer.erase(_text_i, 1);
- }
-
- syntaxLeaf.fUserValue += "dec ";
- syntaxLeaf.fUserValue += textBuffer;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- break;
- }
-
- if (textBuffer[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 = ParserKit::SyntaxLeafList::SyntaxLeaf();
- syntaxLeaf.fUserValue = "\n";
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- return true;
-}
-
-static bool kShouldHaveBraces = false;
-static std::string kFnName;
-
-std::string CompilerBackendCLang::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 imports a variable.
- // so that's why it's not declare upper.
- if (ParserKit::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 (ParserKit::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 && !ParserKit::find_word(ln, "|") &&
- !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") &&
- !ParserKit::find_word(ln, "&&") && !ParserKit::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 : public CompilerKit::AssemblyInterface {
- public:
- explicit AssemblyMountpointCLang() = default;
- ~AssemblyMountpointCLang() override = default;
-
- MPCC_COPY_DEFAULT(AssemblyMountpointCLang);
-
- [[maybe_unused]] static Int32 Arch() noexcept {
- return CompilerKit::AssemblyFactory::kArch64x0;
- }
-
- Int32 CompileToFormat(std::string &src, Int32 arch) override {
- if (arch != AssemblyMountpointCLang::Arch()) return -1;
-
- if (kCompilerBackend == nullptr) return -1;
-
- /* @brief copy contents wihtout extension */
- std::string src_file = src.data();
- std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
- std::string dest;
-
- for (auto &ch : src_file) {
- if (ch == '.') {
- break;
- }
-
- dest += ch;
- }
-
- /* According to PEF ABI. */
- std::vector<const char *> exts = kAsmFileExts;
- dest += exts[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";
-
- ParserKit::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 = kCompilerBackend->Check(line_src.c_str(), src.data());
- err.empty()) {
- kCompilerBackend->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", "dec", "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 (ParserKit::find_word(leaf.fUserValue, access_ident)) {
- for (auto &struc : kState.kStructMap) {
- /// TODO:
- }
- }
- }
-
- for (auto &keyword : keywords) {
- if (ParserKit::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 (ParserKit::find_word(leaf.fUserValue, needle)) {
- if (leaf.fUserValue.find("import " + needle) !=
- std::string::npos) {
- std::string range = "import " + needle;
- leaf.fUserValue.replace(
- leaf.fUserValue.find("import " + 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 != "dec") {
- 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 kOk;
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#include <Version.hxx>
-
-#define kPrintF printf
-#define kSplashCxx() \
- kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion)
-
-static void cc_print_help() { kSplashCxx(); }
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define kExt ".c"
-
-MPCC_MODULE(NewOSCompilerCLang64x0) {
- 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::kArch64x0;
- kCompilerBackend = new CompilerBackendCLang();
-
- for (auto index = 1UL; index < argc; ++index) {
- if (skip) {
- skip = false;
- continue;
- }
-
- if (argv[index][0] == '-') {
- if (strcmp(argv[index], "-v") == 0 ||
- strcmp(argv[index], "-version") == 0) {
- kSplashCxx();
- return kOk;
- }
-
- if (strcmp(argv[index], "-verbose") == 0) {
- kState.fVerbose = true;
-
- continue;
- }
-
- if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) {
- cc_print_help();
-
- return kOk;
- }
-
- if (strcmp(argv[index], "-dialect") == 0) {
- if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n";
-
- return kOk;
- }
-
- 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) != kOk) return -1;
- }
-
- return kOk;
-}
-
-// Last rev 8-1-24
diff --git a/Sources/AsmKit.cc b/Sources/AsmKit.cc
deleted file mode 100644
index b4af817..0000000
--- a/Sources/AsmKit.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-#include <Headers/AsmKit/AsmKit.hpp>
-#include <Headers/StdKit/ErrorID.hpp>
-
-/**
- * @file AsmKit.cc
- * @author Amlal El Mahrouss (amlal@mahrouss.com)
- * @brief Assembler Kit
- * @version 0.1
- * @date 2024-01-27
- *
- * @copyright Copyright (c) 2024, Mahrouss Logic
- *
- */
-
-#include <iostream>
-
-//! @file AsmKit.cpp
-//! @brief AssemblyKit source implementation.
-
-namespace CompilerKit {
-//! @brief Compile for specific format (ELF, PEF, ZBIN)
-Int32 AssemblyFactory::Compile(std::string& sourceFile,
- const Int32& arch) noexcept {
- if (sourceFile.length() < 1 || !fMounted) return MPCC_UNIMPLEMENTED;
-
- return fMounted->CompileToFormat(sourceFile, arch);
-}
-
-//! @brief mount assembly backend.
-void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept {
- if (mountPtr) {
- fMounted = mountPtr;
- }
-}
-
-AssemblyInterface* AssemblyFactory::Unmount() noexcept {
- auto mount_prev = fMounted;
-
- if (mount_prev) {
- fMounted = nullptr;
- }
-
- return mount_prev;
-}
-} // namespace CompilerKit
diff --git a/Sources/Detail/ReadMe.md b/Sources/Detail/ReadMe.md
deleted file mode 100644
index e9d0a2c..0000000
--- a/Sources/Detail/ReadMe.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Compiler utilities.
-
-A list of headers used to make compiler/assemblers.
diff --git a/Sources/Detail/asmutils.h b/Sources/Detail/asmutils.h
deleted file mode 100644
index 2408998..0000000
--- a/Sources/Detail/asmutils.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-#pragma once
-
-#include <Headers/AsmKit/AsmKit.hpp>
-#include <Headers/ParserKit.hpp>
-
-using namespace CompilerKit;
-
-/// @brief Get Number from lineBuffer.
-/// @param lineBuffer the lineBuffer to fetch from.
-/// @param numberKey where to seek that number.
-/// @return
-static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey)
-{
- auto pos = lineBuffer.find(numberKey) + numberKey.size();
-
- if (lineBuffer.find(",") != std::string::npos)
- lineBuffer.erase(lineBuffer.find(","), 1);
-
- while (lineBuffer[pos] == ' ')
- ++pos;
-
- switch (lineBuffer[pos + 1])
- {
- case 'x': {
- if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res)
- {
- if (errno != 0)
- {
- detail::print_error("invalid hex number: " + lineBuffer, "ppcasm");
- throw std::runtime_error("invalid_hex");
- }
- }
-
- NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16));
-
- if (kVerbose)
- {
- kStdOut << "ppcasm: found a base 16 number here: " << lineBuffer.substr(pos)
- << "\n";
- }
-
- return numOffset;
- }
- case 'b': {
- if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res)
- {
- if (errno != 0)
- {
- detail::print_error("invalid binary number:" + lineBuffer, "ppcasm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2));
-
- if (kVerbose)
- {
- kStdOut << "ppcasm: found a base 2 number here:" << lineBuffer.substr(pos)
- << "\n";
- }
-
- return numOffset;
- }
- case 'o': {
- if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res)
- {
- if (errno != 0)
- {
- detail::print_error("invalid octal number: " + lineBuffer, "ppcasm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7));
-
- if (kVerbose)
- {
- kStdOut << "ppcasm: found a base 8 number here:" << lineBuffer.substr(pos)
- << "\n";
- }
-
- return numOffset;
- }
- default: {
- if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res)
- {
- if (errno != 0)
- {
- detail::print_error("invalid hex number: " + lineBuffer, "ppcasm");
- throw std::runtime_error("invalid_hex");
- }
- }
-
- NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10));
-
- if (kVerbose)
- {
- kStdOut << "ppcasm: found a base 10 number here:" << lineBuffer.substr(pos)
- << "\n";
- }
-
- return numOffset;
- }
- }
-}
diff --git a/Sources/Detail/compilerutils.h b/Sources/Detail/compilerutils.h
deleted file mode 100644
index 038f3cf..0000000
--- a/Sources/Detail/compilerutils.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-#pragma once
-
-#include <Headers/AsmKit/AsmKit.hpp>
-#include <Headers/ParserKit.hpp>
-
-#define kZero64Section ".zero64"
-#define kCode64Section ".code64"
-#define kData64Section ".data64"
diff --git a/Sources/String.cc b/Sources/String.cc
deleted file mode 100644
index 449c933..0000000
--- a/Sources/String.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * ========================================================
- *
- * CompilerKit
- * Copyright Mahrouss Logic, all rights reserved.
- *
- * ========================================================
- */
-
-/**
- * @file String.cc
- * @author Amlal (amlal@mahrouss-logic.com)
- * @brief C++ string manipulation API.
- * @version 0.2
- * @date 2024-01-23
- *
- * @copyright Copyright (c) 2024 Mahrouss Logic
- *
- */
-
-#include <Headers/StdKit/String.hpp>
-#include <utility>
-
-namespace CompilerKit {
-CharType *StringView::Data() { return m_Data; }
-
-const CharType *StringView::CData() const { return m_Data; }
-
-SizeType StringView::Length() const { return strlen(m_Data); }
-
-bool StringView::operator==(const StringView &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 StringView::operator==(const CharType *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 StringView::operator!=(const StringView &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 StringView::operator!=(const CharType *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;
-}
-
-StringView StringBuilder::Construct(const CharType *data) {
- if (!data || *data == 0) return StringView(0);
-
- StringView view(strlen(data));
- view += data;
-
- return view;
-}
-
-const char *StringBuilder::FromInt(const char *fmt, int i) {
- if (!fmt) return ("-1");
-
- char *ret = new char[8 + string_length(fmt)];
-
- if (!ret) return ("-1");
-
- CharType result[8];
- if (!to_str(result, sizeof(int), 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 = idx; y_idx < res_len; ++y_idx) {
- ret[result_cnt] = result[y_idx];
- ++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 *fmt2) {
- if (!fmt || !fmt2) return ("?");
-
- char *ret = new char[string_length(fmt2) + string_length(fmt2)];
- 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(fmt2); ++y_idx) {
- ret[result_cnt] = fmt2[y_idx];
- ++result_cnt;
- }
-
- break;
- }
-
- ret[idx] = fmt[idx];
- }
-
- return ret;
-}
-
-StringView &StringView::operator+=(const CharType *rhs) {
- if (strlen(rhs) > this->m_Sz) {
- throw std::runtime_error("out_of_bounds: StringView");
- }
-
- memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs));
- this->m_Cur += strlen(rhs);
-
- return *this;
-}
-
-StringView &StringView::operator+=(const StringView &rhs) {
- if (rhs.m_Cur > this->m_Sz) {
- throw std::runtime_error("out_of_bounds: StringView");
- }
-
- 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/Sources/amd64-cplusplus.cc b/Sources/amd64-cplusplus.cc
deleted file mode 100644
index 60e6435..0000000
--- a/Sources/amd64-cplusplus.cc
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * ========================================================
- *
- * ccplus
- * Copyright Mahrouss Logic, all rights reserved.
- *
- * ========================================================
- */
-
-/// bugs: 0
-
-#define __PK_USE_STRUCT_INSTEAD__ 1
-
-#define kPrintF printf
-
-#define kSplashCxx() \
- kPrintF(kWhite "%s\n", "Mahrouss C++ Compiler, Copyright Mahrouss Logic.")
-
-#include <Headers/AsmKit/CPU/amd64.hpp>
-#include <Headers/ParserKit.hpp>
-#include <cstdio>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#define kOk 0
-
-/* Mahrouss Logic C++ driver */
-/* This is part of CodeTools C++ compiler. */
-/* (c) Mahrouss Logic */
-
-// @author Amlal El Mahrouss (amlel)
-// @file cc.cc
-// @brief Optimized C++ Compiler.
-
-/////////////////////
-
-// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-
-/////////////////////////////////////
-
-// INTERNAL STUFF OF THE C COMPILER
-
-/////////////////////////////////////
-
-namespace detail {
-struct CompilerRegisterMap final {
- std::string fName;
- std::string fReg;
-};
-
-// \brief Offset based struct/class
-struct CompilerStructMap final {
- std::string fName;
- std::string fReg;
-
- // offset counter
- std::size_t fOffsetsCnt;
-
- // offset array
- std::vector<std::pair<Int32, std::string>> fOffsets;
-};
-
-struct CompilerState final {
- std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList;
- std::vector<CompilerRegisterMap> kStackFrame;
- std::vector<CompilerStructMap> kStructMap;
- ParserKit::SyntaxLeafList* fSyntaxTree{nullptr};
- std::unique_ptr<std::ofstream> fOutputAssembly;
- std::string fLastFile;
- std::string fLastError;
- bool fVerbose;
-};
-} // namespace detail
-
-static detail::CompilerState kState;
-static SizeType kErrorLimit = 100;
-
-static Int32 kAcceptableErrors = 0;
-
-namespace detail {
-void print_error(std::string reason, std::string file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (file.find(".pp") != std::string::npos) {
- file.erase(file.find(".pp"), 3);
- }
-
- if (kState.fLastFile != file) {
- std::cout << kRed << "[ ccplus ] " << kWhite
- << ((file == "ccplus") ? "internal compiler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank
- << std::endl;
-
- kState.fLastFile = file;
- } else {
- std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite
- << reason << kBlank << std::endl;
- }
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-struct CompilerType {
- std::string fName;
- std::string fValue;
-};
-} // namespace detail
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// Target architecture.
-static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64;
-
-/////////////////////////////////////////
-
-// ARGUMENTS REGISTERS (R8, R15)
-
-/////////////////////////////////////////
-
-static size_t kRegisterCnt = kAsmRegisterLimit;
-static size_t kStartUsable = 8;
-static size_t kUsableLimit = 15;
-static size_t kRegisterCounter = kStartUsable;
-static std::vector<ParserKit::CompilerKeyword> kKeywords;
-
-/////////////////////////////////////////
-
-// COMPILER PARSING UTILITIES/STATES.
-
-/////////////////////////////////////////
-
-static std::vector<std::string> kFileList;
-static CompilerKit::AssemblyFactory kFactory;
-static bool kInStruct = false;
-static bool kOnWhileLoop = false;
-static bool kOnForLoop = false;
-static bool kInBraces = false;
-static size_t kBracesCount = 0UL;
-
-/* @brief C++ compiler backend for Mahrouss Logic C++ */
-class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend {
- public:
- explicit CompilerBackendCPlusPlus() = default;
- ~CompilerBackendCPlusPlus() override = default;
-
- MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus);
-
- bool Compile(const std::string& text, const char* file) override;
-
- const char* Language() override;
-};
-
-/// compiler variables
-
-static CompilerBackendCPlusPlus* kCompilerBackend = nullptr;
-static std::vector<detail::CompilerType> kCompilerVariables;
-static std::vector<std::string> kCompilerFunctions;
-
-/// detail namespaces
-
-namespace detail {
-union number_cast final {
- number_cast(UInt64 raw) : raw(raw) {}
-
- char number[8];
- UInt64 raw;
-};
-} // namespace detail
-
-const char* CompilerBackendCPlusPlus::Language() { return "C++"; }
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @name Compile
-// @brief Generate MASM from a C++ source.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerBackendCPlusPlus::Compile(const std::string& text,
- const char* file) {
- if (text.empty()) return false;
-
- // if (expr)
- // int name = expr;
- // expr;
-
- std::size_t index = 0UL;
-
- std::vector<std::pair<ParserKit::CompilerKeyword, std::size_t>> keywords_list;
-
- for (auto& keyword : kKeywords) {
- while (text.find(keyword.keyword_name) != std::string::npos) {
- keywords_list.emplace_back(std::make_pair(keyword, index));
- ++index;
- }
- }
-
- // TODO: sort keywords
-
- for (auto& keyword : keywords_list) {
- auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf();
-
- syntax_tree.fUserData = keyword.first;
- kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree);
- }
-
- return true;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * @brief C To Assembly mount-point.
- */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface {
- public:
- explicit AssemblyMountpointClang() = default;
- ~AssemblyMountpointClang() override = default;
-
- MPCC_COPY_DEFAULT(AssemblyMountpointClang);
-
- [[maybe_unused]] static Int32 Arch() noexcept {
- return CompilerKit::AssemblyFactory::kArchAMD64;
- }
-
- Int32 CompileToFormat(std::string& src, Int32 arch) override {
- if (arch != AssemblyMountpointClang::Arch()) return -1;
-
- if (kCompilerBackend == nullptr) return -1;
-
- /* @brief copy contents wihtout extension */
- std::string src_file = src.data();
- std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
- std::string dest;
-
- for (auto& ch : src_file) {
- if (ch == '.') {
- break;
- }
-
- dest += ch;
- }
-
- /* According to PEF ABI. */
-
- std::vector<const char*> exts = kAsmFileExts;
- dest += exts[3];
-
- kState.fOutputAssembly = std::make_unique<std::ofstream>(dest);
-
- auto fmt = CompilerKit::current_date();
-
- (*kState.fOutputAssembly) << "; Path: " << src_file << "\n";
- (*kState.fOutputAssembly)
- << "; Language: CodeTools assembly. (Generated from C++)\n";
- (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n";
- (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000"
- << "\n\n";
-
- ParserKit::SyntaxLeafList syntax;
-
- kState.fSyntaxTreeList.emplace_back(syntax);
- kState.fSyntaxTree =
- &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1];
-
- std::string source;
-
- while (std::getline(src_fp, source)) {
- // Compile into an AST format.
- kCompilerBackend->Compile(source.c_str(), src.data());
- }
-
- if (kAcceptableErrors > 0) return -1;
-
- return kOk;
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static void cxx_print_help() {
- kSplashCxx();
- kPrintF("%s", "No help available, see:\r\n");
- kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n");
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define kExtListCxx \
- { ".cpp", ".cxx", ".cc", ".c++", ".cp" }
-
-MPCC_MODULE(CompilerCPlusPlus) {
- bool skip = false;
-
- kFactory.Mount(new AssemblyMountpointClang());
- kCompilerBackend = new CompilerBackendCPlusPlus();
-
- for (auto index = 1UL; index < argc; ++index) {
- if (argv[index][0] == '-') {
- if (skip) {
- skip = false;
- continue;
- }
-
- if (strcmp(argv[index], "-v") == 0 ||
- strcmp(argv[index], "-version") == 0) {
- kSplashCxx();
- return kOk;
- }
-
- if (strcmp(argv[index], "-verbose") == 0) {
- kState.fVerbose = true;
-
- continue;
- }
-
- if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) {
- cxx_print_help();
-
- return kOk;
- }
-
- if (strcmp(argv[index], "-dialect") == 0) {
- if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n";
-
- return kOk;
- }
-
- if (strcmp(argv[index], "-max-errors") == 0) {
- try {
- kErrorLimit = std::strtol(argv[index + 1], nullptr, 10);
- }
- // catch anything here
- catch (...) {
- kErrorLimit = 0;
- }
-
- skip = true;
-
- continue;
- }
-
- std::string err = "Unknown option: ";
- err += argv[index];
-
- detail::print_error(err, "ccplus");
-
- continue;
- }
-
- kFileList.emplace_back(argv[index]);
-
- std::string argv_i = argv[index];
-
- std::vector exts = kExtListCxx;
- bool found = false;
-
- for (std::string ext : exts) {
- if (argv_i.find(ext) != std::string::npos) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- if (kState.fVerbose) {
- detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus");
- }
-
- return 1;
- }
-
- if (kFactory.Compile(argv_i, kMachine) != kOk) return -1;
- }
-
- return kOk;
-}
-
-// Last rev 8-1-24
diff --git a/Sources/bpp.cc b/Sources/bpp.cc
deleted file mode 100644
index 1e15366..0000000
--- a/Sources/bpp.cc
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * ========================================================
- *
- * bpp
- * Copyright Mahrouss Logic, all rights reserved.
- *
- * ========================================================
- */
-
-/// BUGS: 0
-
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/ErrorID.hpp>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-#define kMacroPrefix '%'
-
-// @author Amlal El Mahrouss (amlel)
-// @file bpp.cc
-// @brief C preprocessor.
-
-typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file,
- std::ofstream &pp_out);
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Preprocessor internal types.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-namespace details {
-enum {
- kEqual,
- kGreaterEqThan,
- kLesserEqThan,
- kGreaterThan,
- kLesserThan,
- kNotEqual,
-};
-
-struct bpp_macro_condition final {
- int32_t fType;
- std::string fTypeName;
-};
-
-struct bpp_macro final {
- std::vector<std::string> fArgs;
- std::string fName;
- std::string fValue;
-};
-
-class bpp_pragma final {
- public:
- explicit bpp_pragma() = default;
- ~bpp_pragma() = default;
-
- MPCC_COPY_DEFAULT(bpp_pragma);
-
- std::string fMacroName;
- bpp_parser_fn_t fParse;
-};
-} // namespace details
-
-static std::vector<std::string> kFiles;
-static std::vector<details::bpp_macro> kMacros;
-static std::vector<std::string> kIncludes;
-
-static std::string kWorkingDir;
-
-static std::vector<std::string> kKeywords = {
- "include", "if", "pragma", "def", "elif",
- "ifdef", "ifndef", "else", "warning", "error"};
-
-#define kKeywordCxxCnt kKeywords.size()
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @name bpp_parse_if_condition
-// @brief parse #if condition
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int32_t bpp_parse_if_condition(details::bpp_macro_condition &cond,
- details::bpp_macro &macro, bool &inactive_code,
- bool &defined, std::string &macro_str) {
- if (cond.fType == details::kEqual) {
- auto substr_macro =
- macro_str.substr(macro_str.find(macro.fName) + macro.fName.size());
-
- if (substr_macro.find(macro.fValue) != std::string::npos) {
- if (macro.fValue == "0") {
- defined = false;
- inactive_code = true;
-
- return 1;
- }
-
- defined = true;
- inactive_code = false;
-
- return 1;
- }
- } else if (cond.fType == details::kNotEqual) {
- auto substr_macro =
- macro_str.substr(macro_str.find(macro.fName) + macro.fName.size());
-
- if (substr_macro.find(macro.fName) != std::string::npos) {
- if (substr_macro.find(macro.fValue) != std::string::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());
-
- std::string number;
-
- for (auto &macro_num : kMacros) {
- if (substr_macro.find(macro_num.fName) != std::string::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 == details::kGreaterThan) {
- if (lhs < rhs) {
- defined = true;
- inactive_code = false;
-
- return 1;
- }
-
- return 0;
- }
-
- if (cond.fType == details::kGreaterEqThan) {
- if (lhs <= rhs) {
- defined = true;
- inactive_code = false;
-
- return 1;
- }
-
- return 0;
- }
-
- if (cond.fType == details::kLesserEqThan) {
- if (lhs >= rhs) {
- defined = true;
- inactive_code = false;
-
- return 1;
- }
-
- return 0;
- }
-
- if (cond.fType == details::kLesserThan) {
- if (lhs > rhs) {
- defined = true;
- inactive_code = false;
-
- return 1;
- }
-
- return 0;
- }
-
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief stores every included file here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-std::vector<std::string> kAllIncludes;
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @name bpp_parse_file
-// @brief parse file to preprocess it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) {
- std::string hdr_line;
- std::string line_after_include;
-
- bool inactive_code = false;
- bool defined = false;
-
- try {
- while (std::getline(hdr_file, hdr_line)) {
- /// BPP Documentation.
- if (hdr_line.find("@bdoc") != std::string::npos) {
- hdr_line.erase(hdr_line.find("@bdoc"));
- }
-
- if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("endif") != std::string::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 (ParserKit::find_word(hdr_line, macro.fName) &&
- hdr_line.find("%def") == std::string::npos) {
- auto value = macro.fValue;
-
- hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(),
- value);
- }
- }
-
- if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("def ") != std::string::npos) {
- auto line_after_define =
- hdr_line.substr(hdr_line.find("def ") + strlen("def "));
-
- std::string macro_value;
- std::string macro_key;
-
- std::size_t pos = 0UL;
-
- std::vector<std::string> 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;
- }
-
- std::vector<std::string> dupls;
- std::string str;
-
- line_after_define.erase(0, line_after_define.find("(") + 1);
-
- for (auto &subc : line_after_define) {
- if (subc == ',' || subc == ')') {
- if (str.empty()) continue;
-
- dupls.push_back(str);
- args.push_back(str);
-
- str.clear();
-
- continue;
- }
-
- if (isalnum(subc)) str.push_back(subc);
- }
-
- for (auto &dupl : dupls) {
- std::size_t cnt = 0;
-
- for (auto &arg : args) {
- if (dupl == arg) ++cnt;
- }
-
- if (cnt > 1) {
- auto it = std::find(args.begin(), args.end(), dupl);
-
- while (it != args.end()) {
- args.erase(it);
- it = std::find(args.begin(), args.end(), dupl);
- }
- }
- }
-
- details::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;
- }
-
- for (auto &macro : kMacros) {
- if (hdr_line.find(macro.fName) != std::string::npos) {
- std::vector<std::string> arg_values;
-
- if (macro.fArgs.size() > 0) {
- for (size_t i = 0; i < hdr_line.size(); ++i) {
- if (hdr_line[i] == '(') {
- std::string tmp_arg;
-
- for (size_t x = i; x < hdr_line.size(); x++) {
- if (hdr_line[x] == ')') break;
-
- if (hdr_line[x] == ' ') continue;
-
- if (hdr_line[i] == '\\') continue;
-
- if (hdr_line[x] == ',') {
- arg_values.push_back(tmp_arg);
- tmp_arg.clear();
- continue;
- }
-
- tmp_arg += hdr_line[x];
- }
-
- break;
- }
- }
-
- std::string symbol;
-
- for (char i : macro.fValue) {
- if (i == '(') break;
-
- if (i == '\\') continue;
-
- symbol += i;
- }
-
- hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(),
- symbol);
-
- size_t x_arg_indx = 0;
-
- for (size_t i = hdr_line.find(macro.fValue); i < hdr_line.size();
- ++i) {
- if (hdr_line.find(macro.fArgs[x_arg_indx]) == i) {
- hdr_line.replace(i, macro.fArgs[x_arg_indx].size(),
- arg_values[x_arg_indx]);
- ++x_arg_indx;
- }
- }
- } else {
- std::string symbol;
-
- for (size_t i = 0; i < macro.fValue.size(); i++) {
- if (macro.fValue[i] == ' ') continue;
-
- if (macro.fValue[i] == '\\') continue;
-
- symbol += macro.fValue[i];
- }
-
- hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(),
- symbol);
- }
-
- break;
- }
- }
-
- pp_out << hdr_line << std::endl;
-
- continue;
- }
-
- if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("ifndef") != std::string::npos) {
- auto line_after_ifndef =
- hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1);
- std::string 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) != std::string::npos) {
- found = true;
- break;
- }
- }
-
- if (found) {
- defined = false;
- inactive_code = true;
-
- continue;
- }
- } else if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("else") != std::string::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") != std::string::npos) {
- auto line_after_ifdef =
- hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1);
- std::string 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) != std::string::npos) {
- defined = true;
- inactive_code = false;
-
- break;
- }
- }
- } else if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("pragma") != std::string::npos) {
- line_after_include = hdr_line.substr(hdr_line.find("pragma once"));
-
- // search for this file
- auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(),
- line_after_include);
-
- if (it == kAllIncludes.cend()) {
- goto kIncludeFile;
- }
- } else if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("if") != std::string::npos) {
- inactive_code = true;
-
- std::vector<details::bpp_macro_condition> bpp_macro_condition_list = {
- {
- .fType = details::kEqual,
- .fTypeName = "==",
- },
- {
- .fType = details::kNotEqual,
- .fTypeName = "!=",
- },
- {
- .fType = details::kLesserThan,
- .fTypeName = "<",
- },
- {
- .fType = details::kGreaterThan,
- .fTypeName = ">",
- },
- {
- .fType = details::kLesserEqThan,
- .fTypeName = "<=",
- },
- {
- .fType = details::kGreaterEqThan,
- .fTypeName = ">=",
- },
- };
-
- int32_t good_to_go = 0;
-
- for (auto &macro_condition : bpp_macro_condition_list) {
- if (hdr_line.find(macro_condition.fTypeName) != std::string::npos) {
- for (auto &found_macro : kMacros) {
- if (hdr_line.find(found_macro.fName) != std::string::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);
- std::string 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) != std::string::npos &&
- macro_ref.fValue == "1") {
- inactive_code = false;
- defined = true;
-
- break;
- }
- }
- } else if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("warning") != std::string::npos) {
- auto line_after_warning =
- hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1);
- std::string message;
-
- for (auto &ch : line_after_warning) {
- if (ch == '\r' || ch == '\n') {
- break;
- }
-
- message += ch;
- }
-
- std::cout << "Warning: " << message << std::endl;
- } else if (hdr_line[0] == kMacroPrefix &&
- hdr_line.find("error") != std::string::npos) {
- auto line_after_warning =
- hdr_line.substr(hdr_line.find("error") + strlen("error") + 1);
- std::string 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("inc ") != std::string::npos) {
- line_after_include =
- hdr_line.substr(hdr_line.find("inc ") + strlen("inc "));
-
- kIncludeFile:
- auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(),
- line_after_include);
-
- if (it != kAllIncludes.cend()) {
- continue;
- }
-
- std::string 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 == '\'') {
- enable = true;
- continue;
- }
-
- if (enable) {
- if (not_local) {
- if (ch == '>') break;
- } else {
- if (ch == '\'') {
- break;
- }
- }
-
- path += ch;
- }
- }
-
- if (not_local) {
- bool open = false;
-
- for (auto &include : kIncludes) {
- std::string 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("bpp: no such include file: " + path);
- }
- } else {
- std::ifstream header(kWorkingDir + path);
-
- if (!header.is_open())
- throw std::runtime_error("bpp: no such include file: " + path);
-
- bpp_parse_file(header, pp_out);
- }
- } else {
- std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line)
- << "\n";
- continue;
- }
- }
- } catch (std::out_of_range &oor) {
- return;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief main entrypoint of app.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSPreprocessor) {
- try {
- bool skip = false;
- bool double_skip = false;
-
- details::bpp_macro macro_1;
- macro_1.fName = "__true";
- macro_1.fValue = "1";
-
- kMacros.push_back(macro_1);
-
- details::bpp_macro macro_0;
- macro_0.fName = "__false";
- macro_0.fValue = "0";
-
- kMacros.push_back(macro_0);
-
- details::bpp_macro macro_hcore;
- macro_hcore.fName = "__MAHROUSS__";
- macro_hcore.fValue = "1";
-
- kMacros.push_back(macro_hcore);
-
- 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], "-v") == 0) {
- printf("%s\n", "bpp v1.11, (c) Mahrouss Logic");
- return 0;
- }
-
- if (strcmp(argv[index], "-h") == 0) {
- printf("%s\n", "bpp v1.11, (c) Mahrouss Logic");
- printf("%s\n", "-working-dir <path>: set directory to working path.");
- printf("%s\n", "-include-dir <path>: add directory to include path.");
- printf("%s\n", "-def <name> <value>: def macro.");
- printf("%s\n", "-version: print the version.");
-
- return 0;
- }
-
- if (strcmp(argv[index], "-include-dir") == 0) {
- std::string inc = argv[index + 1];
-
- skip = true;
-
- kIncludes.push_back(inc);
- }
-
- if (strcmp(argv[index], "-working-dir") == 0) {
- std::string inc = argv[index + 1];
- skip = true;
- kWorkingDir = inc;
- }
-
- if (strcmp(argv[index], "-def") == 0 && argv[index + 1] != nullptr &&
- argv[index + 2] != nullptr) {
- std::string macro_key = argv[index + 1];
-
- std::string 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 += "\"";
-
- details::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 MPCC_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 0;
- } catch (const std::runtime_error &e) {
- std::cout << e.what() << '\n';
- }
-
- return 0;
-}
-
-// Last rev 8-1-24
diff --git a/Sources/coff2ae.cc b/Sources/coff2ae.cc
deleted file mode 100644
index 952be69..0000000
--- a/Sources/coff2ae.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <vector>
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief COFF To AE entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSCOFFToAE) { return 0; }
diff --git a/Sources/compile_flags.txt b/Sources/compile_flags.txt
deleted file mode 100644
index 028be9d..0000000
--- a/Sources/compile_flags.txt
+++ /dev/null
@@ -1,5 +0,0 @@
--std=c++20
--I../
--I../StdKit
--I./
--I./Detail/
diff --git a/Sources/elf2ae.cc b/Sources/elf2ae.cc
deleted file mode 100644
index 77568dc..0000000
--- a/Sources/elf2ae.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <vector>
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief COFF 2 AE entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSELFToAE) { return 0; }
diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc
deleted file mode 100644
index 4f5d885..0000000
--- a/Sources/i64asm.cc
+++ /dev/null
@@ -1,1247 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @file i64asm.cxx
-/// @author Amlal El Mahrouss
-/// @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...
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define __ASM_NEED_AMD64__ 1
-
-#define kAssemblerPragmaSymStr "#"
-#define kAssemblerPragmaSym '#'
-
-#include <Headers/AsmKit/CPU/amd64.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <algorithm>
-#include <cstdlib>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#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"
-
-#define kStdOut (std::cout << kWhite)
-#define kStdErr (std::cout << kRed)
-
-static char kOutputArch = CompilerKit::kPefArchAMD64;
-static Boolean kOutputAsBinary = false;
-
-static UInt32 kErrorLimit = 10;
-static UInt32 kAcceptableErrors = 0;
-
-constexpr auto cAMD64IPAlignment = 0x4U;
-
-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 bool kVerbose = false;
-
-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:";
-static const std::string kRelocSymbol = ":RuntimeSymbol:";
-
-// \brief forward decl.
-static bool asm_read_attributes(std::string &line);
-
-namespace detail {
-void print_error(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- kStdErr << kRed << "[ i64asm ] " << kWhite
- << ((file == "i64asm") ? "internal assembler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl;
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-void print_warning(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (!file.empty()) {
- kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl;
- }
-
- kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank
- << std::endl;
-}
-} // namespace detail
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief AMD64 assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSAssemblerAMD64) {
- //////////////// CPU OPCODES BEGIN ////////////////
-
- 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], "-version") == 0 || strcmp(argv[i], "-v") == 0) {
- kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright "
- "(c) 2024 Mahrouss Logic.\n";
- return 0;
- } else if (strcmp(argv[i], "-h") == 0) {
- kStdOut << "i64asm: AMD64 Assembler.\ni64asm: 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";
-
- return 0;
- } else if (strcmp(argv[i], "-binary") == 0) {
- kOutputAsBinary = true;
- continue;
- } else if (strcmp(argv[i], "-verbose") == 0) {
- kVerbose = true;
- continue;
- }
-
- kStdOut << "i64asm: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "i64asm: 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 << "i64asm: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAEInvalidOpcode, kAEPad);
-
- hdr.fMagic[0] = kAEMag0;
- hdr.fMagic[1] = kAEMag1;
- hdr.fSize = sizeof(CompilerKit::AEHeader);
- hdr.fArch = kOutputArch;
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- // COMPILATION LOOP
-
- /////////////////////////////////////////////////////////////////////////////////////////
-
- CompilerKit::EncoderAMD64 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, "i64asm");
- }
-
- try {
- std::filesystem::remove(object_output);
- } catch (...) {
- }
-
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "i64asm: 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 << "i64asm: At least one record is needed to write an object "
- "file.\ni64asm: Make one using `export .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 << "i64asm: 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 << "i64asm: Wrote symbol " << sym << " to file...\n";
-
- _record_hdr.fKind = kAEInvalidOpcode;
- _record_hdr.fSize = sym.size();
- _record_hdr.fOffset = record_count;
-
- ++record_count;
-
- memset(_record_hdr.fPad, kAEInvalidOpcode, 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 << "i64asm: 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 << "i64asm: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "i64asm: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "i64asm: Exit failed.\n";
-
- return -1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string &line) {
- // import is the opposite of export, it signals to the ld
- // that we need this symbol.
- if (ParserKit::find_word(line, "import")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid directive in flat binary mode.", "i64asm");
- throw std::runtime_error("invalid_import_bin");
- }
-
- auto name = line.substr(line.find("import") + strlen("import") + 1);
-
- if (name.size() == 0) {
- detail::print_error("Invalid import", "ppcasm");
- throw std::runtime_error("invalid_import");
- }
-
- 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 = kAppBytes.size();
-
- memset(kCurrentRecord.fName, 0, kAESymbolLen);
- memcpy(kCurrentRecord.fName, result.c_str(), result.size());
-
- ++kCounter;
-
- memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // export is a special keyword used by i64asm to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64 and
- // .zero64.
- else if (ParserKit::find_word(line, "export")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid directive in flat binary mode.", "i64asm");
- throw std::runtime_error("invalid_export_bin");
- }
-
- auto name = line.substr(line.find("export") + strlen("export") + 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.", "i64asm");
- throw std::runtime_error("invalid_export_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, kAEInvalidOpcode, 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 == '.') || (c == '#'));
-}
-
-bool is_valid(const 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::EncoderAMD64::CheckLine(std::string &line,
- const std::string &file) {
- std::string err_str;
-
- if (line.empty() || ParserKit::find_word(line, "import") ||
- ParserKit::find_word(line, "export") ||
- ParserKit::find_word(line, kAssemblerPragmaSymStr) ||
- ParserKit::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(line)) {
- err_str = "Line contains non valid characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!detail::algorithm::is_valid(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;
- }
- }
- }
- for (auto &opcodeAMD64 : kOpcodesAMD64) {
- if (ParserKit::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, "i64asm");
- 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 << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num = CompilerKit::NumberCast64(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num = CompilerKit::NumberCast64(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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 << "i64asm: 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 << "i64asm: 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 << "i64asm: 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 << "i64asm: 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 << "i64asm: 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, "i64asm");
- 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 << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast16 num = CompilerKit::NumberCast16(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast16 num = CompilerKit::NumberCast16(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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 << "i64asm: 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, "i64asm");
- 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 << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast8 num = CompilerKit::NumberCast8(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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, "i64asm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast8 num = CompilerKit::NumberCast8(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "i64asm: 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 << "i64asm: 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,
- const std::string &file) {
- if (ParserKit::find_word(line, "export ")) return true;
-
- struct RegMapAMD64 {
- std::string fName;
- i64_byte_t fModRM;
- };
-
- std::vector<RegMapAMD64> REGISTER_LIST{
- {.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},
- {.fName = "r8", .fModRM = 8}, {.fName = "r13", .fModRM = 9},
- {.fName = "r9", .fModRM = 10}, {.fName = "r14", .fModRM = 11},
- {.fName = "r10", .fModRM = 12}, {.fName = "r15", .fModRM = 13},
- {.fName = "r11", .fModRM = 14},
- };
-
- bool foundInstruction = false;
-
- for (auto &opcodeAMD64 : kOpcodesAMD64) {
- // strict check here
- if (ParserKit::find_word(line, opcodeAMD64.fName) &&
- detail::algorithm::is_valid(line)) {
- foundInstruction = true;
- std::string name(opcodeAMD64.fName);
-
- /// Move instruction handler.
- if (name.find("mov") != std::string::npos) {
- 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.", "i64asm");
- throw std::runtime_error("syntax_err");
- }
-
- bool onlyOneReg = true;
-
- std::vector<RegMapAMD64> currentRegList;
-
- for (auto &reg : REGISTER_LIST) {
- 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.
- /// 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 (bits == 64 || bits == 32) {
- if (!hasRBasedRegs && bits >= 32) {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
- }
-
- kAppBytes.emplace_back(0x89);
- } else if (bits == 16) {
- if (hasRBasedRegs) {
- detail::print_error(
- "Invalid combination of operands and registers.", "i64asm");
- throw std::runtime_error("comb_op_reg");
- }
-
- kAppBytes.emplace_back(0x66);
- kAppBytes.emplace_back(0x89);
- }
-
- if (currentRegList[1].fName[0] == 'r' &&
- currentRegList[0].fName[0] == 'e') {
- detail::print_error("Invalid combination of operands and registers.",
- "i64asm");
- 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.",
- "i64asm");
- 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.",
- "i64asm");
- 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.",
- "i64asm");
- 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.",
- "i64asm");
- 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.",
- "i64asm");
- 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;
- } else 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 {
- kAppBytes.emplace_back(opcodeAMD64.fOpcode);
-
- break;
- }
- }
- }
-
- if (line[0] == kAssemblerPragmaSym) {
- if (foundInstruction) {
- detail::print_error("Syntax error.", "i64asm");
- 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 << "i64asm: 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 += cAMD64IPAlignment;
-
- return true;
-}
-
-// Last rev 13-1-24
diff --git a/Sources/link.cc b/Sources/link.cc
deleted file mode 100644
index c44350a..0000000
--- a/Sources/link.cc
+++ /dev/null
@@ -1,641 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-/// @file link.cc
-/// @author Amlal El Mahrouss (amlel)
-/// @brief Mahrouss Linker.
-
-/// Last Rev: Sat Feb 24 CET 2024
-
-/// note: Do not look up for anything with .code64/.data64/.zero64!
-/// It will be loaded when program will start up!
-
-#include <Headers/StdKit/ErrorID.hpp>
-
-//! Assembler Kit
-#include <Headers/AsmKit/AsmKit.hpp>
-
-//! Preferred Executable Format
-#include <Headers/StdKit/PEF.hpp>
-#include <Headers/UUID.hpp>
-#include <filesystem>
-#include <random>
-#include <vector>
-
-//! Dist version
-#include <Headers/Version.hxx>
-
-//! Advanced Executable Object Format
-#include <Headers/StdKit/AE.hpp>
-
-//! C++ I/O headers.
-#include <fstream>
-#include <iostream>
-
-#define kLinkerVersion "Mahrouss Linker %s, (c) Mahrouss Logic 2024\n"
-
-#define StringCompare(DST, SRC) strcmp(DST, SRC)
-
-#define kPefNoCpu 0U
-#define kPefNoSubCpu 0U
-
-#define kWhite "\e[0;97m"
-#define kStdOut (std::cout << kWhite)
-
-#define kLinkerDefaultOrigin kPefBaseOrigin
-#define kLinkerId 0x5046FF
-#define kLinkerAbiContainer "Container:Abi:"
-
-enum { kStandardAbi = 0x5046 /* PF */ };
-
-static std::string kOutput;
-static Int32 kAbi = kStandardAbi;
-static Int32 kSubArch = kPefNoSubCpu;
-static Int32 kArch = CompilerKit::kPefArch64000;
-static Bool kFatBinaryEnable = false;
-static Bool kStartFound = false;
-static Bool kDuplicateSymbols = false;
-static Bool kVerbose = false;
-
-/* link 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<std::string> kObjectList;
-static std::vector<char> kObjectBytes;
-
-#define kPrintF printf
-#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion)
-
-MPCC_MODULE(NewOSLinker) {
- bool is_executable = true;
-
- /**
- * @brief parse flags and such.
- *
- */
- for (size_t i = 1; i < argc; ++i) {
- if (StringCompare(argv[i], "-h") == 0) {
- kLinkerSplash();
- kStdOut << "-version: Show program version.\n";
- kStdOut << "-verbose: Enable program trace.\n";
- kStdOut << "-shared: Output as a shared PEF.\n";
- kStdOut << "-fat-bin: Output as FAT PEF.\n";
- kStdOut << "-32x0: Output as 32x0 PEF.\n";
- kStdOut << "-64x0: Output as 64x0 PEF.\n";
- kStdOut << "-amd64: Output as AMD64 PEF.\n";
- kStdOut << "-rv64: Output as RISC-V 64 PEF.\n";
- kStdOut << "-ppc64: Output as POWER 64 PEF.\n";
- kStdOut << "-output-file: Select output file name.\n";
-
- return 0;
- } else if (StringCompare(argv[i], "-v") == 0) {
- kLinkerSplash();
- return 0;
- } else if (StringCompare(argv[i], "-fat-bin") == 0) {
- kFatBinaryEnable = true;
-
- continue;
- } else if (StringCompare(argv[i], "-64x0") == 0) {
- kArch = CompilerKit::kPefArch64000;
-
- continue;
- } else if (StringCompare(argv[i], "-amd64") == 0) {
- kArch = CompilerKit::kPefArchAMD64;
-
- continue;
- } else if (StringCompare(argv[i], "-32x0") == 0) {
- kArch = CompilerKit::kPefArch32000;
-
- continue;
- } else if (StringCompare(argv[i], "-power64") == 0) {
- kArch = CompilerKit::kPefArchPowerPC;
-
- continue;
- } else if (StringCompare(argv[i], "-verbose") == 0) {
- kVerbose = true;
-
- continue;
- } else if (StringCompare(argv[i], "-shared") == 0) {
- if (kOutput.empty()) {
- continue;
- }
-
- if (kOutput.find(kPefExt) != std::string::npos)
- kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt));
-
- kOutput += kPefDylibExt;
-
- is_executable = false;
-
- continue;
- } else if (StringCompare(argv[i], "-output-file") == 0) {
- kOutput = argv[i + 1];
- ++i;
-
- continue;
- } else {
- if (argv[i][0] == '-') {
- kStdOut << "link: unknown flag: " << argv[i] << "\n";
- return -MPCC_EXEC_ERROR;
- }
-
- kObjectList.emplace_back(argv[i]);
-
- continue;
- }
- }
-
- if (kOutput.empty()) {
- kStdOut << "link: no output filename set." << std::endl;
- return MPCC_EXEC_ERROR;
- }
-
- // sanity check.
- if (kObjectList.empty()) {
- kStdOut << "link: no input files." << std::endl;
- return MPCC_EXEC_ERROR;
- } else {
- // check for existing files, if they don't throw an error.
- for (auto &obj : kObjectList) {
- if (!std::filesystem::exists(obj)) {
- // if filesystem doesn't find file
- // -> throw error.
- kStdOut << "link: no such file: " << obj << std::endl;
- return MPCC_EXEC_ERROR;
- }
- }
- }
-
- // PEF expects a valid architecture when outputing a binary.
- if (kArch == 0) {
- kStdOut << "link: no target architecture set, can't continue." << std::endl;
- return MPCC_EXEC_ERROR;
- }
-
- CompilerKit::PEFContainer pef_container{};
-
- int32_t archs = kArch;
-
- pef_container.Count = 0UL;
- pef_container.Kind = CompilerKit::kPefKindExec;
- pef_container.SubCpu = kSubArch;
- pef_container.Linker = kLinkerId; // Mahrouss Logic 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);
-
- std::ofstream outputFc(kOutput, std::ofstream::binary);
-
- if (outputFc.bad()) {
- if (kVerbose) {
- kStdOut << "link: error: " << strerror(errno) << "\n";
- }
-
- return -MPCC_FILE_NOT_FOUND;
- }
-
- //! Read AE to convert as PEF.
-
- std::vector<CompilerKit::PEFCommandHeader> commandHdrsList;
- CompilerKit::Utils::AEReadableProtocol readProto{};
-
- for (const auto &i : kObjectList) {
- if (!std::filesystem::exists(i)) continue;
-
- CompilerKit::AEHeader hdr{};
-
- readProto.FP = std::ifstream(i, std::ifstream::binary);
- readProto.FP >> hdr;
-
- auto ae_header = hdr;
-
- if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 &&
- ae_header.fSize == sizeof(CompilerKit::AEHeader)) {
- if (ae_header.fArch != kArch) {
- if (kVerbose) kStdOut << "link: info: is this a FAT binary? : ";
-
- if (!kFatBinaryEnable) {
- if (kVerbose) kStdOut << "No.\n";
-
- kStdOut << "link: error: object " << i
- << " is a different kind of architecture and output isn't "
- "treated as a FAT binary."
- << std::endl;
-
- std::remove(kOutput.c_str());
- return -MPCC_FAT_ERROR;
- } else {
- if (kVerbose) {
- kStdOut << "Yes.\n";
- }
- }
- }
-
- // append arch type to archs varaible.
- archs |= ae_header.fArch;
- std::size_t cnt = ae_header.fCount;
-
- if (kVerbose)
- kStdOut << "link: object header found, record count: " << cnt << "\n";
-
- pef_container.Count = cnt;
-
- char_type *raw_ae_records =
- new char_type[cnt * sizeof(CompilerKit::AERecordHeader)];
- memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader));
-
- auto *ae_records = readProto.Read(raw_ae_records, cnt);
- for (size_t ae_record_index = 0; ae_record_index < cnt;
- ++ae_record_index) {
- CompilerKit::PEFCommandHeader command_header{0};
- size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize;
-
- memcpy(command_header.Name, ae_records[ae_record_index].fName,
- kPefNameLen);
-
- // check this header if it's any valid.
- if (std::string(command_header.Name).find(".code64") ==
- std::string::npos &&
- std::string(command_header.Name).find(".data64") ==
- std::string::npos &&
- std::string(command_header.Name).find(".zero64") ==
- std::string::npos) {
- if (std::string(command_header.Name).find(kPefStart) ==
- std::string::npos &&
- *command_header.Name == 0) {
- if (std::string(command_header.Name).find(kLdDefineSymbol) !=
- std::string::npos) {
- goto ld_mark_header;
- } else {
- continue;
- }
- }
- }
-
- if (std::string(command_header.Name).find(kPefStart) !=
- std::string::npos &&
- std::string(command_header.Name).find(".code64") !=
- std::string::npos) {
- kStartFound = true;
- }
-
- ld_mark_header:
- command_header.Offset = offsetOfData;
- command_header.Kind = ae_records[ae_record_index].fKind;
- command_header.Size = ae_records[ae_record_index].fSize;
- command_header.Cpu = ae_header.fArch;
- command_header.SubCpu = ae_header.fSubArch;
-
- if (kVerbose) {
- kStdOut << "link: object record: "
- << ae_records[ae_record_index].fName << " was marked.\n";
-
- kStdOut << "link: object record offset: " << command_header.Offset << "\n";
- }
-
- commandHdrsList.emplace_back(command_header);
- }
-
- delete[] raw_ae_records;
-
- std::vector<char> bytes;
- bytes.resize(ae_header.fCodeSize);
-
- readProto.FP.seekg(std::streamsize(ae_header.fStartCode));
- readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize));
-
- for (auto &byte : bytes) {
- kObjectBytes.push_back(byte);
- }
-
- readProto.FP.close();
-
- continue;
- }
-
- kStdOut << "link: not an object: " << i << std::endl;
- std::remove(kOutput.c_str());
-
- // don't continue, it is a fatal error.
- return -MPCC_EXEC_ERROR;
- }
-
- pef_container.Cpu = archs;
-
- outputFc << pef_container;
-
- if (kVerbose) {
- kStdOut << "link: wrote container header.\n";
- }
-
- outputFc.seekp(std::streamsize(pef_container.HdrSz));
-
- std::vector<std::string> not_found;
- std::vector<std::string> symbols;
-
- // step 2: check for errors (multiple symbols, undefined ones)
-
- for (auto &commandHdr : commandHdrsList) {
- // check if this symbol needs to be resolved.
- if (std::string(commandHdr.Name).find(kLdDefineSymbol) !=
- std::string::npos &&
- std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) {
- if (kVerbose)
- kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n";
-
- if (auto it = std::find(not_found.begin(), not_found.end(),
- std::string(commandHdr.Name));
- it == not_found.end()) {
- not_found.emplace_back(commandHdr.Name);
- }
- }
-
- symbols.emplace_back(commandHdr.Name);
- }
-
- // Now try to solve these symbols.
-
- for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size();
- ++not_found_idx) {
- if (auto it = std::find(not_found.begin(), not_found.end(),
- std::string(commandHdrsList[not_found_idx].Name));
- it != not_found.end()) {
- std::string symbol_imp = *it;
-
- if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) continue;
-
- // erase the lookup prefix.
- symbol_imp.erase(
- 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol));
-
- // demangle everything.
- while (symbol_imp.find('$') != std::string::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 &commandHdr : commandHdrsList) {
- if (std::string(commandHdr.Name).find(symbol_imp) !=
- std::string::npos &&
- std::string(commandHdr.Name).find(kLdDefineSymbol) ==
- std::string::npos) {
- std::string undefined_symbol = commandHdr.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)
- kStdOut << "link: found symbol: " << commandHdr.Name << "\n";
-
- break;
- }
- }
-
- ld_continue_search:
- continue;
- }
- }
-
- // step 3: check for errors (recheck if we have those symbols.)
-
- if (!kStartFound && is_executable) {
- if (kVerbose)
- kStdOut
- << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link "
- "against your compiler's runtime library.\n";
-
- kStdOut << "link: undefined entrypoint " << kPefStart
- << " for executable: " << kOutput << "\n";
- }
-
- // step 4: write all PEF commands.
-
- CompilerKit::PEFCommandHeader dateHeader{};
-
- time_t timestamp = time(nullptr);
-
- std::string timeStampStr = "Container:BuildEpoch:";
- timeStampStr += std::to_string(timestamp);
-
- strcpy(dateHeader.Name, timeStampStr.c_str());
-
- dateHeader.Flags = 0;
- dateHeader.Kind = CompilerKit::kPefZero;
- dateHeader.Offset = outputFc.tellp();
- dateHeader.Size = timeStampStr.size();
-
- commandHdrsList.push_back(dateHeader);
-
- CompilerKit::PEFCommandHeader abiHeader{};
-
- std::string abi = kLinkerAbiContainer;
-
- switch (kArch) {
- case CompilerKit::kPefArchAMD64: {
- abi += "MSFT";
- break;
- }
- case CompilerKit::kPefArchPowerPC: {
- abi += "SYSV";
- break;
- }
- case CompilerKit::kPefArch32000:
- case CompilerKit::kPefArch64000: {
- abi += "MHRA";
- break;
- }
- default: {
- abi += " IDK";
- break;
- }
- }
-
- memcpy(abiHeader.Name, abi.c_str(), abi.size());
-
- abiHeader.Size = abi.size();
- abiHeader.Offset = outputFc.tellp();
- abiHeader.Flags = 0;
- abiHeader.Kind = CompilerKit::kPefLinkerID;
-
- commandHdrsList.push_back(abiHeader);
-
- CompilerKit::PEFCommandHeader uuidHeader{};
-
- 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);
-
- memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:"));
- memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(),
- uuidStr.size());
-
- uuidHeader.Size = 16;
- uuidHeader.Offset = outputFc.tellp();
- uuidHeader.Flags = 0;
- uuidHeader.Kind = CompilerKit::kPefZero;
-
- commandHdrsList.push_back(uuidHeader);
-
- // prepare a symbol vector.
- std::vector<std::string> undefSymbols;
- std::vector<std::string> duplSymbols;
- std::vector<std::string> resolveSymbols;
-
- constexpr Int32 cPaddingOffset = 16;
-
- size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset;
-
- // Finally write down the command headers.
- // And check for any duplications
- for (size_t commandHeaderIndex = 0UL;
- commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) {
- if (std::string(commandHdrsList[commandHeaderIndex].Name)
- .find(kLdDefineSymbol) != std::string::npos &&
- std::string(commandHdrsList[commandHeaderIndex].Name)
- .find(kLdDynamicSym) == std::string::npos) {
- // ignore :UndefinedSymbol: headers, they do not contain code.
- continue;
- }
-
- std::string symbolName = commandHdrsList[commandHeaderIndex].Name;
-
- if (!symbolName.empty()) {
- undefSymbols.emplace_back(symbolName);
- }
-
- commandHdrsList[commandHeaderIndex].Offset += previousOffset;
- previousOffset += commandHdrsList[commandHeaderIndex].Size;
-
- std::string name = commandHdrsList[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) != std::string::npos &&
- name.find(".code64") != std::string::npos) {
- pef_container.Start = commandHdrsList[commandHeaderIndex].Offset;
- auto tellCurPos = outputFc.tellp();
-
- outputFc.seekp(0);
- outputFc << pef_container;
-
- outputFc.seekp(tellCurPos);
- }
-
- if (kVerbose) {
- kStdOut << "link: command header name: " <<
- name << "\n";
- kStdOut << "link: real address of command header content: " <<
- commandHdrsList[commandHeaderIndex].Offset << "\n";
- }
-
- outputFc << commandHdrsList[commandHeaderIndex];
-
- for (size_t subCommandHeaderIndex = 0UL;
- subCommandHeaderIndex < commandHdrsList.size();
- ++subCommandHeaderIndex) {
- if (subCommandHeaderIndex == commandHeaderIndex) continue;
-
- if (std::string(commandHdrsList[subCommandHeaderIndex].Name)
- .find(kLdDefineSymbol) != std::string::npos &&
- std::string(commandHdrsList[subCommandHeaderIndex].Name)
- .find(kLdDynamicSym) == std::string::npos) {
- if (kVerbose) {
- kStdOut << "link: ignore :UndefinedSymbol: command header...\n";
- }
-
- // ignore :UndefinedSymbol: headers, they do not contain code.
- continue;
- }
-
- auto &commandHdr = commandHdrsList[subCommandHeaderIndex];
-
- if (commandHdr.Name ==
- std::string(commandHdrsList[commandHeaderIndex].Name)) {
- if (std::find(duplSymbols.cbegin(), duplSymbols.cend(),
- commandHdr.Name) == duplSymbols.cend()) {
- duplSymbols.emplace_back(commandHdr.Name);
- }
-
- if (kVerbose)
- kStdOut << "link: found duplicate symbol: " << commandHdr.Name
- << "\n";
-
- kDuplicateSymbols = true;
- }
- }
- }
-
- if (!duplSymbols.empty()) {
- for (auto &symbol : duplSymbols) {
- kStdOut << "link: multiple symbols of " << symbol << ".\n";
- }
-
- std::remove(kOutput.c_str());
- return -MPCC_EXEC_ERROR;
- }
-
- // step 2.5: write program bytes.
-
- for (auto byte : kObjectBytes) {
- outputFc << byte;
- }
-
- if (kVerbose) kStdOut << "link: wrote contents of: " << kOutput << "\n";
-
- // step 3: check if we have those symbols
-
- std::vector<std::string> unrefSyms;
-
- for (auto &commandHdr : commandHdrsList) {
- if (auto it = std::find(not_found.begin(), not_found.end(),
- std::string(commandHdr.Name));
- it != not_found.end()) {
- unrefSyms.emplace_back(commandHdr.Name);
- }
- }
-
- if (!unrefSyms.empty()) {
- for (auto &unreferenced_symbol : unrefSyms) {
- kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n";
- }
- }
-
- if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) ||
- !unrefSyms.empty()) {
- if (kVerbose)
- kStdOut << "link: file: " << kOutput
- << ", is corrupt, removing file...\n";
-
- std::remove(kOutput.c_str());
- return -MPCC_EXEC_ERROR;
- }
-
- return 0;
-}
-
-// Last rev 13-1-24
diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc
deleted file mode 100644
index 44489da..0000000
--- a/Sources/ppc-cc.cc
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*
- * ========================================================
- *
- * cc
- * Copyright Mahrouss Logic, all rights reserved.
- *
- * ========================================================
- */
-
-#include <Headers/AsmKit/CPU/ppc.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/UUID.hpp>
-#include <cstdio>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <random>
-#include <string>
-#include <utility>
-#include <vector>
-
-#define kOk 0
-
-/// @author Amlal El Mahrouss (amlel)
-/// @file cc.cc
-/// @brief POWER C Compiler.
-
-/////////////////////
-
-/// ANSI ESCAPE CODES
-
-/////////////////////
-
-#define kBlank "\e[0;30m"
-#define kRed "\e[0;31m"
-#define kWhite "\e[0;97m"
-
-/////////////////////////////////////
-
-/// INTERNAL STRUCT 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<ParserKit::SyntaxLeafList> fSyntaxTreeList;
- std::vector<CompilerRegisterMap> kStackFrame;
- std::vector<CompilerStructMap> kStructMap;
- ParserKit::SyntaxLeafList *fSyntaxTree{nullptr};
- std::unique_ptr<std::ofstream> fOutputAssembly;
- std::string fLastFile;
- std::string fLastError;
- bool fVerbose;
-};
-} // namespace detail
-
-static detail::CompilerState kState;
-static SizeType kErrorLimit = 100;
-static std::string kIfFunction = "";
-static Int32 kAcceptableErrors = 0;
-
-namespace detail {
-void print_error(std::string reason, std::string file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (file.find(".pp") != std::string::npos) file.erase(file.find(".pp"), 3);
-
- if (kState.fLastFile != file) {
- std::cout << kRed << "[ cc ] " << kWhite
- << ((file == "cc") ? "internal compiler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl;
-
- kState.fLastFile = file;
- } else {
- std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite
- << reason << kBlank << std::endl;
- }
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-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 CompilerBackendCLang final : public ParserKit::CompilerBackend {
- public:
- explicit CompilerBackendCLang() = default;
- ~CompilerBackendCLang() override = default;
-
- MPCC_COPY_DEFAULT(CompilerBackendCLang);
-
- std::string Check(const char *text, const char *file);
- bool Compile(const std::string &text, const char *file) override;
-
- const char *Language() override { return "POWER C"; }
-};
-
-static CompilerBackendCLang *kCompilerBackend = 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.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-bool CompilerBackendCLang::Compile(const std::string &text, const char *file) {
- std::string textBuffer = 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 < textBuffer.size(); ++text_index) {
- auto syntaxLeaf = ParserKit::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 = textBuffer.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 (textBuffer.find('(') != std::string::npos) {
- syntaxLeaf.fUserValue = buf;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- }
-
- typeFound = true;
- break;
- }
- }
-
- break;
- }
-
- match_type += substr[y];
- }
- }
-
- if (textBuffer[text_index] == '{') {
- if (kInStruct) {
- continue;
- }
-
- kInBraces = true;
- ++kBracesCount;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- }
-
- // return keyword handler
- if (textBuffer[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 < textBuffer.size();
- ++return_index) {
- if (textBuffer[return_index] != return_keyword[index]) {
- for (size_t value_index = return_index;
- value_index < textBuffer.size(); ++value_index) {
- if (textBuffer[value_index] == ';') break;
-
- value += textBuffer[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 += " import";
- value += tmp;
- }
-
- syntaxLeaf.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("import") != std::string::npos)
- value.erase(value.find("import"), strlen("import"));
-
- bool found = false;
-
- for (auto &reg : kState.kStackFrame) {
- if (value.find(reg.fName) != std::string::npos) {
- found = true;
- syntaxLeaf.fUserValue += reg.fReg;
- break;
- }
- }
-
- if (!found) syntaxLeaf.fUserValue += "r0";
- }
-
- syntaxLeaf.fUserValue += "\n\tblr";
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- break;
- }
- }
-
- if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') {
- auto expr = textBuffer.substr(text_index + 2);
- textBuffer.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 = "__MPCC_IF_PROC_";
- kIfFunction += std::to_string(time_off._Raw);
-
- syntaxLeaf.fUserValue =
- "\tcmpw "
- "r10, r11";
-
- syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction +
- " \ndword export .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 (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') {
- if (fnFound) continue;
- if (kIfFound) continue;
-
- if (textBuffer[text_index] == ';' && kInStruct) continue;
-
- if (textBuffer.find("typedef ") != std::string::npos) continue;
-
- if (textBuffer[text_index] == '=' && kInStruct) {
- detail::print_error(
- "assignement of value inside a struct " + textBuffer, file);
- continue;
- }
-
- if (textBuffer[text_index] == ';' && kInStruct) {
- bool space_found_ = false;
- std::string sym;
-
- for (auto &ch : textBuffer) {
- 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 (textBuffer[text_index] == '=' && kInStruct) {
- continue;
- }
-
- if (textBuffer[text_index + 1] == '=' ||
- textBuffer[text_index - 1] == '!' ||
- textBuffer[text_index - 1] == '<' ||
- textBuffer[text_index - 1] == '>') {
- continue;
- }
-
- std::string substr;
-
- if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) {
- if (textBuffer.find("*") != std::string::npos) {
- if (textBuffer.find("=") > textBuffer.find("*"))
- substr += "\tli ";
- else
- substr += "\tli ";
- } else {
- substr += "\tli ";
- }
- } else if (textBuffer.find('=') != std::string::npos && !kInBraces) {
- substr += "stw export .data64 ";
- }
-
- int first_encountered = 0;
-
- std::string str_name;
-
- for (size_t text_index_2 = 0; text_index_2 < textBuffer.size();
- ++text_index_2) {
- if (textBuffer[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 < textBuffer.size(); ++text_index_2) {
- if (textBuffer[text_index_2] == '\"') break;
-
- substr += textBuffer[text_index_2];
- }
- }
-
- if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}')
- continue;
-
- if (textBuffer[text_index_2] == ';') {
- break;
- }
-
- if (textBuffer[text_index_2] == ' ' ||
- textBuffer[text_index_2] == '\t') {
- if (first_encountered != 2) {
- if (textBuffer[text_index] != '=' &&
- substr.find("export .data64") == std::string::npos &&
- !kInStruct)
- substr += "export .data64 ";
- }
-
- ++first_encountered;
-
- continue;
- }
-
- if (textBuffer[text_index_2] == '=') {
- if (!kInBraces) {
- substr.replace(substr.find("export .data64"),
- strlen("export .data64"), "export .zero64 ");
- }
-
- substr += ",";
- continue;
- }
-
- substr += textBuffer[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"), "import ");
-
- if (substr.find("export .data64") != std::string::npos)
- substr.erase(substr.find("export .data64"), strlen("export .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 (textBuffer[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});
-
- syntaxLeaf.fUserValue +=
- "\n\tli " + reg + substr.substr(substr.find(','));
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- }
-
- // function handler.
-
- if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) {
- std::string substr;
- std::string args_buffer;
- std::string args;
-
- bool type_crossed = false;
-
- for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size();
- ++idx) {
- if (textBuffer[idx] == ',') continue;
-
- if (textBuffer[idx] == ' ') continue;
-
- if (textBuffer[idx] == ')') break;
- }
-
- for (char substr_first_index : textBuffer) {
- 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 : textBuffer) {
- 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\tblr\n";
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- fnFound = true;
- } else {
- syntaxLeaf.fUserValue.clear();
-
- syntaxLeaf.fUserValue += "export .code64 ";
-
- syntaxLeaf.fUserValue += substr;
- syntaxLeaf.fUserValue += "\n";
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- fnFound = true;
- }
-
- kCompilerFunctions.push_back(textBuffer);
- }
-
- if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') {
- textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), "");
-
- for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) {
- if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ')
- textBuffer.erase(_text_i, 1);
- }
-
- syntaxLeaf.fUserValue += "dec ";
- syntaxLeaf.fUserValue += textBuffer;
-
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
- break;
- }
-
- if (textBuffer[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 = ParserKit::SyntaxLeafList::SyntaxLeaf();
- syntaxLeaf.fUserValue = "\n";
- kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
-
- return true;
-}
-
-static bool kShouldHaveBraces = false;
-static std::string kFnName;
-
-std::string CompilerBackendCLang::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 imports a variable.
- // so that's why it's not declare upper.
- if (ParserKit::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 (ParserKit::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 && !ParserKit::find_word(ln, "|") &&
- !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") &&
- !ParserKit::find_word(ln, "&&") && !ParserKit::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 : public CompilerKit::AssemblyInterface {
- public:
- explicit AssemblyMountpointCLang() = default;
- ~AssemblyMountpointCLang() override = default;
-
- MPCC_COPY_DEFAULT(AssemblyMountpointCLang);
-
- [[maybe_unused]] static Int32 Arch() noexcept {
- return CompilerKit::AssemblyFactory::kArchPowerPC;
- }
-
- Int32 CompileToFormat(std::string &src, Int32 arch) override {
- if (arch != AssemblyMountpointCLang::Arch()) return -1;
-
- if (kCompilerBackend == nullptr) return -1;
-
- /* @brief copy contents wihtout extension */
- std::string src_file = src.data();
- std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
- std::string dest;
-
- for (auto &ch : src_file) {
- if (ch == '.') {
- break;
- }
-
- dest += ch;
- }
-
- /* According to PEF ABI. */
- std::vector<const char *> exts = kAsmFileExts;
- dest += exts[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";
-
- ParserKit::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 = kCompilerBackend->Check(line_src.c_str(), src.data());
- err.empty()) {
- kCompilerBackend->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 (ParserKit::find_word(leaf.fUserValue, access_ident)) {
- for (auto &struc : kState.kStructMap) {
- /// TODO:
- }
- }
- }
-
- for (auto &keyword : keywords) {
- if (ParserKit::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 (ParserKit::find_word(leaf.fUserValue, needle)) {
- if (leaf.fUserValue.find("import ") != std::string::npos) {
- std::string range = "import ";
- 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 kOk;
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#include <Version.hxx>
-
-#define kPrintF printf
-#define kSplashCxx() \
- kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion)
-
-static void cc_print_help() { kSplashCxx(); }
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define kExt ".c"
-
-MPCC_MODULE(NewOSCompilerCLangPowerPC) {
- 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;
- kCompilerBackend = new CompilerBackendCLang();
-
- for (auto index = 1UL; index < argc; ++index) {
- if (skip) {
- skip = false;
- continue;
- }
-
- if (argv[index][0] == '-') {
- if (strcmp(argv[index], "-v") == 0 ||
- strcmp(argv[index], "-version") == 0) {
- kSplashCxx();
- return kOk;
- }
-
- if (strcmp(argv[index], "-verbose") == 0) {
- kState.fVerbose = true;
-
- continue;
- }
-
- if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) {
- cc_print_help();
-
- return kOk;
- }
-
- if (strcmp(argv[index], "-dialect") == 0) {
- if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n";
-
- return kOk;
- }
-
- 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) != kOk) return -1;
- }
-
- return kOk;
-}
-
-// Last rev 8-1-24
diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc
deleted file mode 100644
index fcf0a5d..0000000
--- a/Sources/ppcasm.cc
+++ /dev/null
@@ -1,977 +0,0 @@
-/* -------------------------------------------
-
- Copyright Mahrouss Logic
-
-------------------------------------------- */
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @file ppcasm.cxx
-/// @author Amlal El Mahrouss
-/// @brief POWER Assembler.
-
-/// REMINDER: when dealing with an undefined symbol use (string
-/// size):LinkerFindSymbol:(string) so that li will look for it.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-#define __ASM_NEED_PPC__ 1
-
-#include <Headers/AsmKit/CPU/ppc.hpp>
-#include <Headers/ParserKit.hpp>
-#include <Headers/StdKit/AE.hpp>
-#include <Headers/StdKit/PEF.hpp>
-#include <Headers/Version.hxx>
-#include <algorithm>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#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"
-
-#define kStdOut (std::cout << kWhite)
-#define kStdErr (std::cout << kRed)
-
-static CharType kOutputArch = CompilerKit::kPefArchPowerPC;
-static Boolean kOutputAsBinary = false;
-
-constexpr auto cPowerIPAlignment = 0x4U;
-
-static UInt32 kErrorLimit = 10;
-static UInt32 kAcceptableErrors = 0;
-
-static std::size_t kCounter = 1UL;
-
-static std::uintptr_t kOrigin = kPefBaseOrigin;
-static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel;
-
-static bool kVerbose = false;
-
-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);
-
-namespace detail {
-void print_error(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- kStdErr << kRed << "[ ppcasm ] " << kWhite
- << ((file == "ppcasm") ? "internal assembler error "
- : ("in file, " + file))
- << kBlank << std::endl;
- kStdErr << kRed << "[ ppcasm ] " << kWhite << reason << kBlank << std::endl;
-
- if (kAcceptableErrors > kErrorLimit) std::exit(3);
-
- ++kAcceptableErrors;
-}
-
-void print_warning(std::string reason, const std::string &file) noexcept {
- if (reason[0] == '\n') reason.erase(0, 1);
-
- if (!file.empty()) {
- kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl;
- }
-
- kStdOut << kYellow << "[ ppcasm ] " << kWhite << reason << kBlank
- << std::endl;
-}
-} // namespace detail
-
-/// Do not move it on top! it uses the assembler detail namespace!
-#include <asmutils.h>
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-/// @brief POWER assembler entrypoint, the program/module starts here.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-MPCC_MODULE(NewOSAssemblerPowerPC) {
- for (size_t i = 1; i < argc; ++i) {
- if (argv[i][0] == '-') {
- if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) {
- kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: "
- "Copyright (c) "
- "2024 Mahrouss Logic.\n";
- return 0;
- } else if (strcmp(argv[i], "-h") == 0) {
- kStdOut << "ppcasm: POWER Assembler.\nppcasm: 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";
-
- return 0;
- } else if (strcmp(argv[i], "-binary") == 0) {
- kOutputAsBinary = true;
- continue;
- } else if (strcmp(argv[i], "-verbose") == 0) {
- kVerbose = true;
- continue;
- }
-
- kStdOut << "ppcasm: ignore " << argv[i] << "\n";
- continue;
- }
-
- if (!std::filesystem::exists(argv[i])) {
- kStdOut << "ppcasm: 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 << "ppcasm: error: " << strerror(errno) << "\n";
- }
- }
-
- std::string line;
-
- CompilerKit::AEHeader hdr{0};
-
- memset(hdr.fPad, kAEInvalidOpcode, 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, "ppcasm");
- }
-
- std::filesystem::remove(object_output);
- goto asm_fail_exit;
- }
- }
-
- if (!kOutputAsBinary) {
- if (kVerbose) {
- kStdOut << "ppcasm: 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 << "ppcasm: At least one record is needed to write an object "
- "file.\nppcasm: Make one using `export .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 << "ppcasm: 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 << "ppcasm: Wrote symbol " << sym << " to file...\n";
-
- _record_hdr.fKind = kAEInvalidOpcode;
- _record_hdr.fSize = sym.size();
- _record_hdr.fOffset = record_count;
-
- ++record_count;
-
- memset(_record_hdr.fPad, kAEInvalidOpcode, 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 << "ppcasm: 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 << "ppcasm: Wrote file with program in it.\n";
-
- file_ptr_out.flush();
- file_ptr_out.close();
-
- if (kVerbose) kStdOut << "ppcasm: Exit succeeded.\n";
-
- return 0;
- }
-
-asm_fail_exit:
-
- if (kVerbose) kStdOut << "ppcasm: Exit failed.\n";
-
- return -1;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-// @brief Check for attributes
-// returns true if any was found.
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool asm_read_attributes(std::string &line) {
- // import is the opposite of export, it signals to the li
- // that we need this symbol.
- if (ParserKit::find_word(line, "import")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid import directive in flat binary mode.",
- "ppcasm");
- throw std::runtime_error("invalid_import_bin");
- }
-
- auto name = line.substr(line.find("import") + strlen("import") + 1);
-
- if (name.size() == 0) {
- detail::print_error("Invalid import", "ppcasm");
- throw std::runtime_error("invalid_import");
- }
-
- 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, kAEInvalidOpcode, kAEPad);
-
- kRecords.emplace_back(kCurrentRecord);
-
- return true;
- }
- // export is a special keyword used by ppcasm to tell the AE output stage to
- // mark this section as a header. it currently supports .code64, .data64.,
- // .zero64
- else if (ParserKit::find_word(line, "export")) {
- if (kOutputAsBinary) {
- detail::print_error("Invalid export directive in flat binary mode.",
- "ppcasm");
- throw std::runtime_error("invalid_export_bin");
- }
-
- auto name = line.substr(line.find("export") + strlen("export"));
-
- 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, kAEInvalidOpcode, 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(const 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,
- const std::string &file) {
- std::string err_str;
-
- if (line.empty() || ParserKit::find_word(line, "import") ||
- ParserKit::find_word(line, "export") ||
- line.find('#') != std::string::npos || ParserKit::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(line)) {
- err_str = "Line contains non alphanumeric characters.\nhere -> ";
- err_str += line;
- }
- }
-
- return err_str;
- }
-
- if (!detail::algorithm::is_valid(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 &opcodePPC : kOpcodesPowerPC) {
- if (ParserKit::find_word(line, opcodePPC.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(), opcodePPC.name);
- it == filter_inst.cend()) {
- if (ParserKit::find_word(line, opcodePPC.name)) {
- if (!isspace(
- line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) {
- err_str += "\nMissing space between ";
- err_str += opcodePPC.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, "ppcasm");
- 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 << "ppcasm: 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, "ppcasm");
- throw std::runtime_error("invalid_bin");
- }
- }
-
- CompilerKit::NumberCast64 num(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
-
- if (kVerbose) {
- kStdOut << "ppcasm: 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, "ppcasm");
- throw std::runtime_error("invalid_octal");
- }
- }
-
- CompilerKit::NumberCast64 num(
- strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
-
- if (kVerbose) {
- kStdOut << "ppcasm: 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 << "ppcasm: 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,
- const std::string &file) {
- if (ParserKit::find_word(line, "export")) return true;
- if (!detail::algorithm::is_valid(line)) return true;
-
- for (auto &opcodePPC : kOpcodesPowerPC) {
- // strict check here
- if (ParserKit::find_word(line, opcodePPC.name)) {
- std::string name(opcodePPC.name);
- std::string jump_label, cpy_jump_label;
- std::vector<size_t> found_registers_index;
-
- // check funct7 type.
- switch (opcodePPC.ops->type) {
- default: {
- NumberCast32 num(opcodePPC.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 = opcodePPC.name;
- std::size_t register_sum = 0;
-
- NumberCast64 num(opcodePPC.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 << "ppcasm: Found register: " << register_syntax
- << "\n";
- kStdOut << "ppcasm: 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 (opcodePPC.ops->type != GREG) {
- // remember! register to register!
- if (found_some_count == 1) {
- detail::print_error(
- "Unrecognized register found.\ntip: each ppcasm 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