diff options
| author | Amlal EL Mahrouss <amlalelmahrouss@icloud.com> | 2024-07-28 06:25:47 +0200 |
|---|---|---|
| committer | Amlal EL Mahrouss <amlalelmahrouss@icloud.com> | 2024-07-28 06:25:47 +0200 |
| commit | 00df8fa52de0a5a379bfd36b34d4502251ceec72 (patch) | |
| tree | 945ba7a529f616e9c88f8c5932e32958eaddb82c /Sources | |
| parent | 60a8ac37cd3be6b96488d1f2df0b50d36cbaf991 (diff) | |
[META] Refactor codebase.
Signed-off-by: Amlal EL Mahrouss <amlalelmahrouss@icloud.com>
Diffstat (limited to 'Sources')
| -rw-r--r-- | Sources/32asm.cxx | 52 | ||||
| -rw-r--r-- | Sources/64asm.cxx | 954 | ||||
| -rw-r--r-- | Sources/64x0-cc.cxx | 1627 | ||||
| -rw-r--r-- | Sources/AssemblyFactory.cxx | 59 | ||||
| -rw-r--r-- | Sources/Detail/ReadMe.md | 3 | ||||
| -rw-r--r-- | Sources/Detail/asmutils.hxx | 111 | ||||
| -rw-r--r-- | Sources/Detail/compilerutils.hxx | 14 | ||||
| -rw-r--r-- | Sources/String.cxx | 200 | ||||
| -rw-r--r-- | Sources/bpp.cxx | 899 | ||||
| -rw-r--r-- | Sources/coff2ae.cxx | 23 | ||||
| -rw-r--r-- | Sources/compile_flags.txt | 5 | ||||
| -rw-r--r-- | Sources/cplusplus.cxx | 1025 | ||||
| -rw-r--r-- | Sources/elf2ae.cxx | 22 | ||||
| -rw-r--r-- | Sources/i64asm.cxx | 1484 | ||||
| -rw-r--r-- | Sources/link.cxx | 741 | ||||
| -rw-r--r-- | Sources/power-as.cxx | 976 | ||||
| -rw-r--r-- | Sources/power-cc.cxx | 1645 |
17 files changed, 0 insertions, 9840 deletions
diff --git a/Sources/32asm.cxx b/Sources/32asm.cxx deleted file mode 100644 index 23111bc..0000000 --- a/Sources/32asm.cxx +++ /dev/null @@ -1,52 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 32asm.cxx -// @author ZKA Technologies -// @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 <NDKKit/AsmKit/CPU/32x0.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/NFC/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. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/64asm.cxx b/Sources/64asm.cxx deleted file mode 100644 index 0a92157..0000000 --- a/Sources/64asm.cxx +++ /dev/null @@ -1,954 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 64asm.cxx -// @author Amlal EL Mahrouss -// @brief 64x000 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 <NDKKit/AsmKit/CPU/64x0.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/NFC/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. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_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) " - "ZKA Technologies.\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 (CompilerKit::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", "power-as"); - 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 (CompilerKit::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() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(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 (CompilerKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + - strlen(opcode64x0.fName)])) { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "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 (CompilerKit::find_word(line, "export ")) return true; - - for (auto &opcode64x0 : kOpcodes64x0) { - // strict check here - if (CompilerKit::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 == "sub") { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - if (found_some > 0 && name == "pop") { - detail::print_error( - "invalid combination for opcode 'pop'.\ntip: it expects " - "nothing.\nline: " + - line, - file); - throw std::runtime_error("invalid_comb_op_pop"); - } - } - default: - break; - } - - // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { - auto where_string = name; - - // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || - name == "sta") - where_string = ","; - - jump_label = line; - - auto found_sym = false; - - while (jump_label.find(where_string) != std::string::npos) { - jump_label = jump_label.substr(jump_label.find(where_string) + - where_string.size()); - - while (jump_label.find(" ") != std::string::npos) { - jump_label.erase(jump_label.find(" "), 1); - } - - if (jump_label[0] != kAsmRegisterPrefix[0] && - !isdigit(jump_label[1])) { - if (found_sym) { - detail::print_error( - "invalid combination of opcode and operands.\nhere -> " + - jump_label, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } else { - // death trap installed. - found_sym = true; - } - } - } - - cpy_jump_label = jump_label; - - // replace any spaces with $ - if (jump_label[0] == ' ') { - while (jump_label.find(' ') != std::string::npos) { - if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; - - jump_label.erase(jump_label.find(' '), 1); - } - } - - if (!this->WriteNumber(0, jump_label)) { - // sta expects this: sta 0x000000, r0 - if (name == "sta") { - detail::print_error( - "invalid combination of opcode and operands.\nHere ->" + line, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } - } else { - if (name == "sta" && - cpy_jump_label.find("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.cxx b/Sources/64x0-cc.cxx deleted file mode 100644 index 4adf7f8..0000000 --- a/Sources/64x0-cc.cxx +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: ? -/// TODO: - -#include <NDKKit/AsmKit/CPU/64x0.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/UUID.hpp> -#include <filesystem> -#include <cstdio> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -/* C driver */ -/* This is part of the NDK. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file 64x0-cc.cxx -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kOk (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail -{ - // \brief 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<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - 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 CompilerKit::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 = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = 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 += "sub "; - 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 = CompilerKit::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 (CompilerKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (CompilerKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCCInterface); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCCInterface::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"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = 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", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("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 != "sub") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <Version.hpp> - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "ZKA C Driver, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_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 AssemblyCCInterface()); - 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/AssemblyFactory.cxx b/Sources/AssemblyFactory.cxx deleted file mode 100644 index 9f1b768..0000000 --- a/Sources/AssemblyFactory.cxx +++ /dev/null @@ -1,59 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include <NDKKit/AsmKit/AsmKit.hpp> -#include <NDKKit/NFC/ErrorID.hpp> - -/** - * @file AssemblyFactory.cxx - * @author amlal (amlal@zeta.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, ZKA Technologies - * - */ - -#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; - } - } - - ///! @brief Unmount assembler. - 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.hxx b/Sources/Detail/asmutils.hxx deleted file mode 100644 index abb7f82..0000000 --- a/Sources/Detail/asmutils.hxx +++ /dev/null @@ -1,111 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include <NDKKit/AsmKit/AsmKit.hpp> -#include <NDKKit/Parser.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, "asm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) - { - kStdOut << "asm: 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, "asm"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "asm: 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, "asm"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "asm: 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, "asm"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) - { - kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - } -} diff --git a/Sources/Detail/compilerutils.hxx b/Sources/Detail/compilerutils.hxx deleted file mode 100644 index fd2b6d2..0000000 --- a/Sources/Detail/compilerutils.hxx +++ /dev/null @@ -1,14 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#pragma once - -#include <NDKKit/AsmKit/AsmKit.hpp> -#include <NDKKit/Parser.hpp> - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" diff --git a/Sources/String.cxx b/Sources/String.cxx deleted file mode 100644 index f69f9b9..0000000 --- a/Sources/String.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/** - * @file String.cxx - * @author Amlal (amlal@mahrouss-logic.com) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) ZKA Technologies - * - */ - -#include <NDKKit/NFC/String.hpp> - -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"); - - auto ret_len = 8 + string_length(fmt); - char *ret = new char[ret_len]; - - if (!ret) return ("-1"); - - memset(ret, 0, ret_len); - - 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 *fmtRight) { - if (!fmt || !fmtRight) return ("?"); - - char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; - if (!ret) return ("?"); - - for (SizeType idx = 0; idx < string_length(fmt); ++idx) { - if (fmt[idx] == '%') { - SizeType result_cnt = idx; - - for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { - ret[result_cnt] = fmtRight[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; -} - -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/bpp.cxx b/Sources/bpp.cxx deleted file mode 100644 index 9a2943c..0000000 --- a/Sources/bpp.cxx +++ /dev/null @@ -1,899 +0,0 @@ -/* - * ======================================================== - * - * bpp - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/ErrorID.hpp> -#include <algorithm> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <vector> - -#define kMacroPrefix '%' - -/// @author Amlal El Mahrouss (amlel) -/// @file bpp.cxx -/// @brief 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 ¯o, bool &inactive_code, - bool &defined, std::string ¯o_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 ¯o_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 (CompilerKit::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 ¯o : 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 ¯o_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 ¯o_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 ¯o_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 ¯o_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. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_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], "/version") == 0) { - printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); - return 0; - } - - if (strcmp(argv[index], "/help") == 0) { - printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) ZKA Technologies"); - 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."); - printf("%s\n", "/help: show help."); - - 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 1; -} - -// Last rev 8-1-24 diff --git a/Sources/coff2ae.cxx b/Sources/coff2ae.cxx deleted file mode 100644 index c9ea8c0..0000000 --- a/Sources/coff2ae.cxx +++ /dev/null @@ -1,23 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/NFC/PEF.hpp> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <vector> - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file coff2ae.cxx -/// @brief COFF To AE, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/compile_flags.txt b/Sources/compile_flags.txt deleted file mode 100644 index 6ec6b8a..0000000 --- a/Sources/compile_flags.txt +++ /dev/null @@ -1,5 +0,0 @@ --std=c++20 --I../ --I../Headers --I./ --I./Detail/ diff --git a/Sources/cplusplus.cxx b/Sources/cplusplus.cxx deleted file mode 100644 index ae4a300..0000000 --- a/Sources/cplusplus.cxx +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * ======================================================== - * - * cplusplus - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -/// bugs: 0 - -#define __PK_USE_STRUCT_INSTEAD__ 1 - -#define kPrintF printf - -#define kOk (0) - -#define kSplashCxx() \ - kPrintF(kWhite "%s\n", "ZKA C++ Compiler Driver, (c) 2024 ZKA Electronics, all rights reserved.") - -// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } - -#include <NDKKit/AsmKit/CPU/amd64.hpp> -#include <NDKKit/Parser.hpp> -#include <UUID.hpp> - -#include <cctype> -#include <cstdio> -#include <fstream> -#include <iostream> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -/* ZKA C++ driver */ -/* This is part of NDK. */ -/* (c) ZKA Technologies */ - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cxx -/// @brief Optimized C++ Compiler. -/// @todo Throw error for scoped inside scoped variables when they get referenced outside. -/// @todo Add class/struct/enum support. - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNALS OF THE C COMPILER - -///////////////////////////////////// - -/// @internal -namespace detail -{ - 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<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; - -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - 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 << "[ cplusplus ] " << kWhite - << ((file == "cplusplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } - else - { - std::cout << kRed << "[ cplusplus ] [ " << 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<CompilerKit::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 the ZKA C++ driver */ -class CompilerBackendCPlusPlus final : public CompilerKit::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; -}; - -/// @internal compiler variables - -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; -static std::vector<detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; - -static std::vector<std::string> kRegisterMap; - -static std::vector<std::string> cRegisters = { - "rbx", - "rsi", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "xmm12", - "xmm13", - "xmm14", - "xmm15", -}; - -/// @brief The PEF calling convention (caller must save rax, rbp) -/// @note callee must return via **rax**. -static std::vector<std::string> cRegistersCall = { - "rcx", - "rdx", - "r8", - "r9", - "xmm8", - "xmm9", - "xmm10", - "xmm11", -}; - -static size_t kLevelFunction = 0UL; - -/// detail namespaces - -const char* CompilerBackendCPlusPlus::Language() -{ - return "ZKA C++"; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @name Compile -/// @brief Generate MASM assembly 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<CompilerKit::CompilerKeyword, std::size_t>> keywords_list; - - bool found = false; - static bool commentBlock = false; - - for (auto& keyword : kKeywords) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - switch (keyword.keyword_kind) - { - case CompilerKit::eKeywordKindCommentMultiLineStart: { - commentBlock = true; - return true; - } - case CompilerKit::eKeywordKindCommentMultiLineEnd: { - commentBlock = false; - break; - } - case CompilerKit::eKeywordKindCommentInline: { - break; - } - default: - break; - } - - if (text[text.find(keyword.keyword_name) - 1] == '+' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) - 1] == '-' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) + 1] == '=' && - keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - - found = true; - } - } - - if (!found && !commentBlock) - { - for (size_t i = 0; i < text.size(); i++) - { - if (isalnum(text[i])) - { - detail::print_error("syntax error: " + text, file); - return false; - } - } - } - - for (auto& keyword : keywords_list) - { - auto syntax_tree = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - switch (keyword.first.keyword_kind) - { - case CompilerKit::KeywordKind::eKeywordKindIf: { - auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); - - if (expr.find(">=") != std::string::npos) - { - auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); - auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - - size_t i = right.size() - 1; - - try - { - while (!std::isalnum(right[i])) - { - right.erase(i, 1); - --i; - } - - right.erase(0, i); - } - catch (...) - { - right.erase(0, i); - } - - i = left.size() - 1; - try - { - - while (!std::isalnum(left[i])) - { - left.erase(i, 1); - --i; - } - - left.erase(0, i); - } - catch (...) - { - left.erase(0, i); - } - - if (!isdigit(left[0]) || - !isdigit(right[0])) - { - auto indexRight = 0UL; - - auto& valueOfVar = !isdigit(left[0]) ? left : right; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - - syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + "," + cRegisters[indexRight + 1] + "\n"; - - goto done_iterarting_on_if; - } - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + ", " + cRegisters[indexRight + 1] + "\n"; - - break; - } - } - - done_iterarting_on_if: - - std::string fnName = text; - fnName.erase(fnName.find(keyword.first.keyword_name)); - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue += "jge offset [rsp + 4]\n"; - } - - break; - } - case CompilerKit::KeywordKind::eKeywordKindFunctionStart: { - if (text.ends_with(";")) - { - break; - } - - for (auto& ch : text) - { - if (isdigit(ch)) - { - goto dont_accept; - } - } - - goto accept; - - dont_accept: - return true; - - accept: - std::string fnName = text; - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; - - ++kLevelFunction; - } - case CompilerKit::KeywordKind::eKeywordKindFunctionEnd: { - if (text.ends_with(";")) - break; - - --kLevelFunction; - - if (kRegisterMap.size() > cRegisters.size()) - { - --kLevelFunction; - } - - if (kLevelFunction < 1) - kRegisterMap.clear(); - break; - } - case CompilerKit::KeywordKind::eKeywordKindEndInstr: - case CompilerKit::KeywordKind::eKeywordKindVariableInc: - case CompilerKit::KeywordKind::eKeywordKindVariableDec: - case CompilerKit::KeywordKind::eKeywordKindVariableAssign: { - std::string valueOfVar = ""; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - valueOfVar = text.substr(text.find("+=") + 2); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - valueOfVar = text.substr(text.find("-=") + 2); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - { - valueOfVar = text.substr(text.find("=") + 1); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - break; - } - - while (valueOfVar.find(";") != std::string::npos && - keyword.first.keyword_kind != CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - valueOfVar.erase(valueOfVar.find(";")); - } - - std::string varName = text; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - varName.erase(varName.find("+=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - varName.erase(varName.find("-=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) - { - varName.erase(varName.find("=")); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - varName.erase(varName.find(";")); - } - - static bool typeFound = false; - - for (auto& keyword : kKeywords) - { - if (keyword.keyword_kind == CompilerKit::eKeywordKindType) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - if (text[text.find(keyword.keyword_name)] == ' ') - { - typeFound = false; - continue; - } - - typeFound = true; - } - } - } - - std::string instr = "mov "; - - if (typeFound) - { - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - detail::print_error("Can't increment variable when it's being created.", file); - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - detail::print_error("Can't decrement variable when it's being created.", file); - } - - if (kRegisterMap.size() > cRegisters.size()) - { - ++kLevelFunction; - } - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - goto done; - } - - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - break; - } - - if (((int)indexRight - 1) < 0) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - } - - done: - kRegisterMap.push_back(varName); - } - else - { - if (kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindTypePtr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) - { - instr = "add "; - } - else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) - { - instr = "sub "; - } - - std::string varErrCpy = varName; - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - while (valueOfVar.find(" ") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find(" "), 1); - } - - while (valueOfVar.find("\t") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find("\t"), 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != varName) - continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != varName) - { - syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - continue; - } - - syntax_tree.fUserValue = instr + cRegisters[indexRight - 1] + ", " + valueOfVar + "\n"; - break; - } - - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + varErrCpy, file); - } - } - - break; - } - case CompilerKit::KeywordKind::eKeywordKindReturn: { - auto pos = text.find("return") + strlen("return") + 1; - std::string subText = text.substr(pos); - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (subText[0] != '\"' && - subText[0] != '\'') - { - if (!isdigit(subText[0])) - { - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != subText) - continue; - - syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg] + "\r\nret\n"; - break; - } - - if (syntax_tree.fUserValue.empty()) - { - detail::print_error("Variable not declared: " + subText, file); - } - } - else - { - syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; - } - } - else - { - syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; - syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; - } - - break; - } - default: - break; - } - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } - -_MpccOkay: - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface -{ -public: - explicit AssemblyCPlusPlusInterface() = default; - ~AssemblyCPlusPlusInterface() override = default; - - MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); - - [[maybe_unused]] - static Int32 Arch() noexcept - { - return CompilerKit::AssemblyFactory::kArchAMD64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCPlusPlusInterface::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); - - const char* cExts[] = kAsmFileExts; - - std::string dest = src_file; - dest += cExts[4]; - - if (dest.empty()) - { - dest = "CXX-NDK-"; - - 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); - - auto gen = uuids::uuid_random_generator(generator); - - auto id = gen(); - dest += uuids::to_string(id); - } - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: AMD64 assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; - (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" - << "\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string source; - - while (std::getline(src_fp, source)) - { - // Compile into an object file. - kCompilerBackend->Compile(source.c_str(), src.c_str()); - } - - for (auto& ast : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << ast.fUserValue; - } - - if (kAcceptableErrors > 0) - return -1; - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static void cxx_print_help() -{ - kSplashCxx(); - kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { \ - ".cpp", ".cxx", ".cc", ".c++", ".cp" \ - } - -NDK_MODULE(CompilerCPlusPlus) -{ - bool skip = false; - - kKeywords.push_back({.keyword_name = "if", .keyword_kind = CompilerKit::eKeywordKindIf}); - kKeywords.push_back({.keyword_name = "else", .keyword_kind = CompilerKit::eKeywordKindElse}); - kKeywords.push_back({.keyword_name = "else if", .keyword_kind = CompilerKit::eKeywordKindElseIf}); - - kKeywords.push_back({.keyword_name = "class", .keyword_kind = CompilerKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "struct", .keyword_kind = CompilerKit::eKeywordKindClass}); - kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = CompilerKit::eKeywordKindNamespace}); - kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = CompilerKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "using", .keyword_kind = CompilerKit::eKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = CompilerKit::eKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = CompilerKit::eKeywordKindBodyEnd}); - kKeywords.push_back({.keyword_name = "auto", .keyword_kind = CompilerKit::eKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "bool", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "short", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "char", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "long", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "float", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "double", .keyword_kind = CompilerKit::eKeywordKindType}); - kKeywords.push_back({.keyword_name = "void", .keyword_kind = CompilerKit::eKeywordKindType}); - - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = CompilerKit::eKeywordKindVariablePtr}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); - - kKeywords.push_back({.keyword_name = "(", .keyword_kind = CompilerKit::eKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = CompilerKit::eKeywordKindFunctionEnd}); - kKeywords.push_back({.keyword_name = "=", .keyword_kind = CompilerKit::eKeywordKindVariableAssign}); - kKeywords.push_back({.keyword_name = "+=", .keyword_kind = CompilerKit::eKeywordKindVariableInc}); - kKeywords.push_back({.keyword_name = "-=", .keyword_kind = CompilerKit::eKeywordKindVariableDec}); - kKeywords.push_back({.keyword_name = "const", .keyword_kind = CompilerKit::eKeywordKindConstant}); - kKeywords.push_back({.keyword_name = "*", .keyword_kind = CompilerKit::eKeywordKindPtr}); - kKeywords.push_back({.keyword_name = "->", .keyword_kind = CompilerKit::eKeywordKindPtrAccess}); - kKeywords.push_back({.keyword_name = ".", .keyword_kind = CompilerKit::eKeywordKindAccess}); - kKeywords.push_back({.keyword_name = ",", .keyword_kind = CompilerKit::eKeywordKindArgSeparator}); - kKeywords.push_back({.keyword_name = ";", .keyword_kind = CompilerKit::eKeywordKindEndInstr}); - kKeywords.push_back({.keyword_name = ":", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "public:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "private:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "final", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "return", .keyword_kind = CompilerKit::eKeywordKindReturn}); - kKeywords.push_back({.keyword_name = "/*", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "*/", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "//", .keyword_kind = CompilerKit::eKeywordKindCommentInline}); - kKeywords.push_back({.keyword_name = "==", .keyword_kind = CompilerKit::eKeywordKindEq}); - kKeywords.push_back({.keyword_name = "!=", .keyword_kind = CompilerKit::eKeywordKindNotEq}); - kKeywords.push_back({.keyword_name = ">=", .keyword_kind = CompilerKit::eKeywordKindGreaterEq}); - kKeywords.push_back({.keyword_name = "<=", .keyword_kind = CompilerKit::eKeywordKindLessEq}); - - kFactory.Mount(new AssemblyCPlusPlusInterface()); - 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, "cplusplus"); - - 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", "cplusplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) - return -1; - } - - return kOk; -} - -// Last rev 8-1-24 -// diff --git a/Sources/elf2ae.cxx b/Sources/elf2ae.cxx deleted file mode 100644 index 451c706..0000000 --- a/Sources/elf2ae.cxx +++ /dev/null @@ -1,22 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/NFC/PEF.hpp> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <vector> - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief COFF 2 AE entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/Sources/i64asm.cxx b/Sources/i64asm.cxx deleted file mode 100644 index ed77988..0000000 --- a/Sources/i64asm.cxx +++ /dev/null @@ -1,1484 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @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 <NDKKit/AsmKit/CPU/amd64.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/NFC/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 - -#include <asmutils.hxx> - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_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 Driver.\ni64asm: v1.10\ni64asm: Copyright " - "(c) ZKA Technologies.\n"; - return 0; - } - else if (strcmp(argv[i], "/h") == 0) - { - kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " - "ZKA Technologies.\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 (CompilerKit::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", "power-as"); - 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 (CompilerKit::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() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - CompilerKit::find_word(line, kAssemblerPragmaSymStr) || - CompilerKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) - { - if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - // now check the line for validity - if (!detail::algorithm::is_valid(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 (CompilerKit::find_word(line, opcodeAMD64.fName)) - { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - detail::print_error("invalid hex number: " + jump_label, "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 (CompilerKit::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 (CompilerKit::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. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') - { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } - else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (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: " + line, "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.cxx b/Sources/link.cxx deleted file mode 100644 index d59c982..0000000 --- a/Sources/link.cxx +++ /dev/null @@ -1,741 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -/// @file link.cxx -/// @author Amlal EL Mahrouss (amlel) -/// @brief ZKA Technologies 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 <NDKKit/NFC/ErrorID.hpp> - -//! Assembler Kit -#include <NDKKit/AsmKit/AsmKit.hpp> - -//! Preferred Executable Format -#include <NDKKit/NFC/PEF.hpp> -#include <NDKKit/UUID.hpp> -#include <filesystem> -#include <random> -#include <vector> - -//! Dist version -#include <NDKKit/Version.hpp> - -//! Advanced Executable Object Format -#include <NDKKit/NFC/AE.hpp> - -//! C++ I/O headers. -#include <fstream> -#include <iostream> - -#define kLinkerVersion "ZKA Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\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 -{ - eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ - eABINewOSKrnl = 0x5046, /* PF (NewOSKrnl) */ - eABIMTL = 0x4650, /* FP (MTL firmware) */ - eABIInvalid = 1, -}; - -static std::string kOutput = ""; -static Int32 kAbi = eABINewOSKrnl; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArchInvalid; -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) - -NDK_MODULE(NewOSLinker) -{ - bool is_executable = true; - - /** - * @brief parse flags and such. - * - */ - for (size_t i = 1; i < argc; ++i) - { - if (StringCompare(argv[i], "/help") == 0) - { - kLinkerSplash(); - kStdOut << "/version: Show linker version.\n"; - kStdOut << "/help: Show linker help.\n"; - kStdOut << "/verbose: Enable linker trace.\n"; - kStdOut << "/shared: Output as a shared PEF.\n"; - kStdOut << "/fat-bin: Output as a FAT PEF.\n"; - kStdOut << "/32x0: Output as a 32x0 PEF.\n"; - kStdOut << "/64x0: Output as a 64x0 PEF.\n"; - kStdOut << "/amd64: Output as a AMD64 PEF.\n"; - kStdOut << "/rv64: Output as a RISC-V PEF.\n"; - kStdOut << "/power64: Output as a POWER PEF.\n"; - kStdOut << "/arm64: Output as a ARM64 PEF.\n"; - kStdOut << "/output-file: Select the output file name.\n"; - - return 0; - } - else if (StringCompare(argv[i], "/version") == 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], "/arm64") == 0) - { - kArch = CompilerKit::kPefArchARM64; - - 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 - { - namespace fs = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) - { - if (!fs::exists(obj)) - { - // if filesystem doesn't find file - // -> throw error. - 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; // ZKA Technologies 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/power-as.cxx b/Sources/power-as.cxx deleted file mode 100644 index 8a6b7ef..0000000 --- a/Sources/power-as.cxx +++ /dev/null @@ -1,976 +0,0 @@ -/* ------------------------------------------- - - Copyright ZKA Technologies - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file power-as.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 <NDKKit/NFC/ErrorID.hpp> -#include <NDKKit/AsmKit/CPU/ppc.hpp> -#include <NDKKit/NFC/PEF.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/NFC/AE.hpp> -#include <NDKKit/Version.hpp> -#include <filesystem> -#include <algorithm> -#include <iostream> -#include <fstream> -#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) - -constexpr auto cPowerIPAlignment = 0x4U; - -static CharType kOutputArch = CompilerKit::kPefArchPowerPC; -static Boolean kOutputAsBinary = false; - -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 << "[ power-as ] " << kWhite - << ((file == "power-as") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ power-as ] " << 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 << "[ power-as ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail - -/// Do not move it on top! it uses the assembler detail namespace! -#include <asmutils.hxx> - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NDK_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 << "power-as: POWER64 Assembler Driver.\npower-as: " << kDistVersion << "\npower-as: " - "Copyright (c) " - "ZKA Technologies.\n"; - return 0; - } else if (strcmp(argv[i], "/h") == 0) { - kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: Copyright (c) 2024 " - "ZKA Technologies.\n"; - kStdOut << "/version,/v: print program version.\n"; - kStdOut << "/verbose: print verbose output.\n"; - kStdOut << "/binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "/binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "/verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "power-as: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "power-as: 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 << "power-as: 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, "power-as"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "power-as: 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 << "power-as: At least one record is needed to write an object " - "file.\npower-as: 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 &record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) - kStdOut << "power-as: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) - kStdOut << "power-as: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAEInvalidOpcode; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "power-as: 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 << "power-as: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "power-as: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "power-as: Exit failed.\n"; - - return MPCC_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @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 (CompilerKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid import directive in flat binary mode.", - "power-as"); - 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", "power-as"); - 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 power-as to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid export directive in flat binary mode.", - "power-as"); - 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() || CompilerKit::find_word(line, "import") || - CompilerKit::find_word(line, "export") || - line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!detail::algorithm::is_valid(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 (CompilerKit::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 (CompilerKit::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, "power-as"); - 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 << "power-as: 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, "power-as"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "power-as: 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, "power-as"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "power-as: 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 << "power-as: 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 (CompilerKit::find_word(line, "export")) return true; - if (!detail::algorithm::is_valid(line)) return true; - - for (auto &opcodePPC : kOpcodesPowerPC) { - // strict check here - if (CompilerKit::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 << "power-as: Found register: " << register_syntax - << "\n"; - kStdOut << "power-as: 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 power-as register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - detail::print_error( - "invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/power-cc.cxx b/Sources/power-cc.cxx deleted file mode 100644 index 4c07a04..0000000 --- a/Sources/power-cc.cxx +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright ZKA Technologies, all rights reserved. - * - * ======================================================== - */ - -#include <NDKKit/AsmKit/CPU/ppc.hpp> -#include <NDKKit/Parser.hpp> -#include <NDKKit/UUID.hpp> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> -#include <cstdio> - -#define kOk 0 - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cxx -/// @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<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept - { - 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 CompilerKit::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 = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) - { - auto substr = 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 = CompilerKit::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 (CompilerKit::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) - { - if (CompilerKit::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : 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"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = 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 (CompilerKit::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("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.hpp> - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) - -static void cc_print_help() -{ - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NDK_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 |
