summaryrefslogtreecommitdiffhomepage
path: root/dev/LibCompiler
diff options
context:
space:
mode:
authorAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-12-27 07:39:05 +0100
committerAmlal El Mahrouss <amlal.elmahrouss@icloud.com>2024-12-27 07:39:05 +0100
commitf61c814a0a95e98529c96361c992f1a8ea24688a (patch)
tree0c5fcb7976f5753149e0b8cc3b974a318e013f61 /dev/LibCompiler
parentc2046f25120d8c39b36cb81459f3370c8a5f1fa3 (diff)
META: Refactor source code.
Signed-off-by: Amlal El Mahrouss <amlal.elmahrouss@icloud.com>
Diffstat (limited to 'dev/LibCompiler')
-rw-r--r--dev/LibCompiler/AAL/AssemblyInterface.h227
-rw-r--r--dev/LibCompiler/AAL/CPU/32x0.h97
-rw-r--r--dev/LibCompiler/AAL/CPU/64x0.h106
-rw-r--r--dev/LibCompiler/AAL/CPU/amd64.h56
-rw-r--r--dev/LibCompiler/AAL/CPU/arm64.h26
-rw-r--r--dev/LibCompiler/AAL/CPU/power64.h1929
-rw-r--r--dev/LibCompiler/Defines.h172
-rw-r--r--dev/LibCompiler/Macros.h33
-rw-r--r--dev/LibCompiler/NFC/AE.h143
-rw-r--r--dev/LibCompiler/NFC/ErrorID.h22
-rw-r--r--dev/LibCompiler/NFC/ErrorOr.h61
-rw-r--r--dev/LibCompiler/NFC/PEF.h144
-rw-r--r--dev/LibCompiler/NFC/Ref.h103
-rw-r--r--dev/LibCompiler/NFC/String.h90
-rw-r--r--dev/LibCompiler/NFC/XCOFF.h41
-rw-r--r--dev/LibCompiler/Parser.h177
-rw-r--r--dev/LibCompiler/ReadMe.md7
-rw-r--r--dev/LibCompiler/UUID.h983
-rw-r--r--dev/LibCompiler/Version.h15
-rw-r--r--dev/LibCompiler/src/Assembler32x0.cc50
-rw-r--r--dev/LibCompiler/src/Assembler64x0.cc1117
-rw-r--r--dev/LibCompiler/src/AssemblerAMD64.cc1481
-rw-r--r--dev/LibCompiler/src/AssemblerPower.cc1096
-rw-r--r--dev/LibCompiler/src/AssemblyFactory.cc59
-rw-r--r--dev/LibCompiler/src/CCompiler64x0.cc1596
-rw-r--r--dev/LibCompiler/src/CCompilerPower64.cc1616
-rw-r--r--dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc1091
-rw-r--r--dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc1070
-rw-r--r--dev/LibCompiler/src/Detail/AsmUtils.h116
-rw-r--r--dev/LibCompiler/src/Detail/ClUtils.h14
-rw-r--r--dev/LibCompiler/src/Detail/ReadMe.md3
-rw-r--r--dev/LibCompiler/src/DynamicLinker64PEF.cc774
-rw-r--r--dev/LibCompiler/src/String.cc256
33 files changed, 14771 insertions, 0 deletions
diff --git a/dev/LibCompiler/AAL/AssemblyInterface.h b/dev/LibCompiler/AAL/AssemblyInterface.h
new file mode 100644
index 0000000..245aee9
--- /dev/null
+++ b/dev/LibCompiler/AAL/AssemblyInterface.h
@@ -0,0 +1,227 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Macros.h>
+#include <LibCompiler/Defines.h>
+#include <LibCompiler/NFC/String.h>
+
+#define ASSEMBLY_INTERFACE : public LibCompiler::AssemblyInterface
+
+namespace LibCompiler
+{
+ /// @brief Assembly to binary generator class.
+ /// @note This interface creates according to the CPU target of the child class.
+ class AssemblyInterface
+ {
+ public:
+ explicit AssemblyInterface() = default;
+ virtual ~AssemblyInterface() = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(AssemblyInterface);
+
+ /// @brief compile to object file.
+ /// @note Example C++ -> MASM -> AE object.
+ virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0;
+ };
+
+ /// @brief Simple assembly factory
+ class AssemblyFactory final
+ {
+ public:
+ explicit AssemblyFactory() = default;
+ ~AssemblyFactory() = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(AssemblyFactory);
+
+ public:
+ enum
+ {
+ kArchAMD64,
+ kArch32x0,
+ kArch64x0,
+ kArchRISCV,
+ kArchPowerPC,
+ kArchUnknown,
+ };
+
+ Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept;
+
+ void Mount(AssemblyInterface* mountPtr) noexcept;
+ AssemblyInterface* Unmount() noexcept;
+
+ private:
+ AssemblyInterface* fMounted{nullptr};
+ };
+
+ union NumberCastBase
+ {
+ NumberCastBase() = default;
+ ~NumberCastBase() = default;
+ };
+
+ union NumberCast64 final
+ {
+ NumberCast64() = default;
+ explicit NumberCast64(UInt64 raw)
+ : raw(raw)
+ {
+ }
+
+ ~NumberCast64()
+ {
+ raw = 0;
+ }
+
+ CharType number[8];
+ UInt64 raw;
+ };
+
+ union NumberCast32 final
+ {
+ NumberCast32() = default;
+ explicit NumberCast32(UInt32 raw)
+ : raw(raw)
+ {
+ }
+
+ ~NumberCast32()
+ {
+ raw = 0;
+ }
+
+ CharType number[4];
+ UInt32 raw;
+ };
+
+ union NumberCast16 final
+ {
+ NumberCast16() = default;
+ explicit NumberCast16(UInt16 raw)
+ : raw(raw)
+ {
+ }
+
+ ~NumberCast16()
+ {
+ raw = 0;
+ }
+
+ CharType number[2];
+ UInt16 raw;
+ };
+
+ union NumberCast8 final
+ {
+ NumberCast8() = default;
+ explicit NumberCast8(UInt8 raw)
+ : raw(raw)
+ {
+ }
+
+ ~NumberCast8()
+ {
+ raw = 0;
+ }
+
+ CharType number;
+ UInt8 raw;
+ };
+
+ class EncoderInterface
+ {
+ public:
+ explicit EncoderInterface() = default;
+ virtual ~EncoderInterface() = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(EncoderInterface);
+
+ virtual std::string CheckLine(std::string& line, const std::string& file) = 0;
+ virtual bool WriteLine(std::string& line, const std::string& file) = 0;
+ virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0;
+ };
+
+#ifdef __ASM_NEED_AMD64__
+
+ class EncoderAMD64 final : public EncoderInterface
+ {
+ public:
+ explicit EncoderAMD64() = default;
+ ~EncoderAMD64() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(EncoderAMD64);
+
+ virtual std::string CheckLine(std::string& line,
+ const std::string& file) override;
+ virtual bool WriteLine(std::string& line, const std::string& file) override;
+ virtual bool WriteNumber(const std::size_t& pos,
+ std::string& from_what) override;
+
+ virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what);
+ virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what);
+ virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what);
+ };
+
+#endif // __ASM_NEED_AMD64__
+
+#ifdef __ASM_NEED_64x0__
+
+ class Encoder64x0 final : public EncoderInterface
+ {
+ public:
+ explicit Encoder64x0() = default;
+ ~Encoder64x0() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(Encoder64x0);
+
+ virtual std::string CheckLine(std::string& line,
+ const std::string& file) override;
+ virtual bool WriteLine(std::string& line, const std::string& file) override;
+ virtual bool WriteNumber(const std::size_t& pos,
+ std::string& from_what) override;
+ };
+
+#endif // __ASM_NEED_64x0__
+
+#ifdef __ASM_NEED_32x0__
+
+ class Encoder32x0 final : public EncoderInterface
+ {
+ public:
+ explicit Encoder32x0() = default;
+ ~Encoder32x0() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(Encoder32x0);
+
+ virtual std::string CheckLine(std::string& line,
+ const std::string& file) override;
+ virtual bool WriteLine(std::string& line, const std::string& file) override;
+ virtual bool WriteNumber(const std::size_t& pos,
+ std::string& from_what) override;
+ };
+
+#endif // __ASM_NEED_32x0__
+
+#ifdef __ASM_NEED_PPC__
+
+ class EncoderPowerPC final : public EncoderInterface
+ {
+ public:
+ explicit EncoderPowerPC() = default;
+ ~EncoderPowerPC() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(EncoderPowerPC);
+
+ virtual std::string CheckLine(std::string& line,
+ const std::string& file) override;
+ virtual bool WriteLine(std::string& line, const std::string& file) override;
+ virtual bool WriteNumber(const std::size_t& pos,
+ std::string& from_what) override;
+ };
+
+#endif // __ASM_NEED_32x0__
+} // namespace LibCompiler
diff --git a/dev/LibCompiler/AAL/CPU/32x0.h b/dev/LibCompiler/AAL/CPU/32x0.h
new file mode 100644
index 0000000..828ef8d
--- /dev/null
+++ b/dev/LibCompiler/AAL/CPU/32x0.h
@@ -0,0 +1,97 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+// @brief 32x0 support.
+// @file CPU/32x0.hpp
+
+#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \
+ {.fName = __NAME, \
+ .fOpcode = __OPCODE, \
+ .fFunct3 = __FUNCT3, \
+ .fFunct7 = __FUNCT7},
+
+#define kAsmImmediate 0x01
+#define kAsmSyscall 0x02
+#define kAsmJump 0x03
+#define kAsmNoArgs 0x04
+
+#define kAsmByte 0
+#define kAsmHWord 1
+#define kAsmWord 2
+
+struct CpuCode32x0
+{
+ const char fName[32];
+ uint8_t fOpcode;
+ uint8_t fSize;
+ uint8_t fFunct3;
+ uint8_t fFunct7;
+};
+
+#define kAsmDWordStr ".dword" /* 64 bit */
+#define kAsmWordStr ".word" /* 32-bit */
+#define kAsmHWordStr ".half" /* 16-bit */
+#define kAsmByteStr ".byte" /* 8-bit */
+
+inline std::vector<CpuCode32x0> kOpcodes32x0 = {
+ kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C)
+ kAsmOpcodeDecl("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C)
+ kAsmOpcodeDecl("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C)
+ kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C)
+ kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C)
+ kAsmOpcodeDecl("lea", 0b0111011, 0b010,
+ kAsmImmediate) // setup stack and call, store address to CR (1C).
+ kAsmOpcodeDecl("ret", 0b0111011, 0b110,
+ kAsmImmediate) // return from procedure (2C).
+ kAsmOpcodeDecl("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C)
+ kAsmOpcodeDecl("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C)
+ kAsmOpcodeDecl("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C)
+};
+
+// \brief 64x0 register prefix
+// example: r32, r0
+// r32 -> sp
+// r0 -> hw zero
+
+#define kAsmRegisterPrefix "r"
+#define kAsmRegisterLimit 16
+#define kAsmPcRegister 17
+#define kAsmCrRegister 18
+#define kAsmSpRegister 5
+
+/* return address register */
+#define kAsmRetRegister 19
+
+/////////////////////////////////////////////////////////////////////////////
+
+// SYSTEM CALL ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | OFF |
+
+// IMMEDIATE ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF |
+// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG |
+// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF |
+
+// REG TO REG ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 |
+
+////////////////////////////////
+
+// LOAD/CALL INTERRUPTS
+
+// SET A HANDLER IN ADDRESS: TODO: find one
+// DISABLE INTERRUPTS
+// PROCESS INTERRUPT
+// ENABLE INTERRUPTS
+
+////////////////////////////////
diff --git a/dev/LibCompiler/AAL/CPU/64x0.h b/dev/LibCompiler/AAL/CPU/64x0.h
new file mode 100644
index 0000000..a057805
--- /dev/null
+++ b/dev/LibCompiler/AAL/CPU/64x0.h
@@ -0,0 +1,106 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+#include <vector>
+
+// @brief 64x0 support.
+// @file CPU/64x0.hpp
+
+#define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \
+ {.fName = __NAME, \
+ .fOpcode = __OPCODE, \
+ .fFunct3 = __FUNCT3, \
+ .fFunct7 = __FUNCT7},
+
+#define kAsmImmediate 0x01
+#define kAsmRegToReg 0x02
+#define kAsmSyscall 0x03
+#define kAsmJump 0x04
+#define kAsmNoArgs 0x00
+
+typedef char e64k_character_t;
+typedef uint8_t e64k_num_t;
+
+struct CpuOpcode64x0
+{
+ const e64k_character_t fName[32];
+ e64k_num_t fOpcode;
+ e64k_num_t fFunct3;
+ e64k_num_t fFunct7;
+};
+
+inline std::vector<CpuOpcode64x0> kOpcodes64x0 = {
+ kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
+ kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation.
+ kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111,
+ kAsmJump) // jump to linked return register
+ kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111,
+ kAsmJump) // jump from return register.
+ kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg)
+ kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg)
+ kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg)
+ kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg)
+ kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg)
+ kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg)
+ kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg)
+ kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate)
+ kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate)
+ // add/sub without carry flag
+ kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate)
+ kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate)
+ // add/sub with carry flag
+ kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate)
+ kAsmOpcodeDecl("subc", 0b0101011, 0b111, kAsmImmediate)
+ kAsmOpcodeDecl("sc", 0b1110011, 0b00, kAsmSyscall)};
+
+// \brief 64x0 register prefix
+// example: r32, r0
+// r32 -> sp
+// r0 -> hw zero
+
+#define kAsmFloatZeroRegister 0
+#define kAsmZeroRegister 0
+
+#define kAsmRegisterPrefix "r"
+#define kAsmRegisterLimit 30
+#define kAsmPcRegister 17
+#define kAsmCrRegister 18
+#define kAsmSpRegister 5
+
+/* return address register */
+#define kAsmRetRegister 19
+
+/////////////////////////////////////////////////////////////////////////////
+
+// SYSTEM CALL/JUMP ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | OFF |
+
+// IMMEDIATE ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF |
+// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG |
+// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF |
+
+// REG TO REG ADDRESSING
+
+// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 |
+
+////////////////////////////////
+
+// LOAD/CALL INTERRUPTS
+
+// SET A HANDLER IN ADDRESS:
+// DISABLE INTERRUPTS
+// PROCESS INTERRUPT
+// ENABLE INTERRUPTS
+
+////////////////////////////////
diff --git a/dev/LibCompiler/AAL/CPU/amd64.h b/dev/LibCompiler/AAL/CPU/amd64.h
new file mode 100644
index 0000000..219968a
--- /dev/null
+++ b/dev/LibCompiler/AAL/CPU/amd64.h
@@ -0,0 +1,56 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+// @brief AMD64 support.
+// @file CPU/amd64.hpp
+
+#define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE},
+
+typedef char i64_character_t;
+typedef uint8_t i64_byte_t;
+typedef uint16_t i64_hword_t;
+typedef uint32_t i64_word_t;
+
+struct CpuOpcodeAMD64
+{
+ std::string fName;
+ i64_byte_t fPrefixBytes[4];
+ i64_hword_t fOpcode;
+ i64_hword_t fModReg;
+ i64_word_t fDisplacment;
+ i64_word_t fImmediate;
+};
+
+/// these two are edge cases
+#define kAsmIntOpcode 0xCC
+#define kasmIntOpcodeAlt 0xCD
+
+#define kAsmJumpOpcode 0x0F80
+#define kJumpLimit 30
+#define kJumpLimitStandard 0xE3
+#define kJumpLimitStandardLimit 0xEB
+
+inline std::vector<CpuOpcodeAMD64> kOpcodesAMD64 = {
+ kAsmOpcodeDecl("int", 0xCD)
+ kAsmOpcodeDecl("into", 0xCE)
+ kAsmOpcodeDecl("intd", 0xF1)
+ kAsmOpcodeDecl("int3", 0xC3)
+ kAsmOpcodeDecl("iret", 0xCF)
+ kAsmOpcodeDecl("retf", 0xCB)
+ kAsmOpcodeDecl("retn", 0xC3)
+ kAsmOpcodeDecl("ret", 0xC3)
+ kAsmOpcodeDecl("sti", 0xfb)
+ kAsmOpcodeDecl("cli", 0xfa)
+ kAsmOpcodeDecl("hlt", 0xf4)
+ kAsmOpcodeDecl("nop", 0x90)
+ kAsmOpcodeDecl("mov", 0x48)
+ kAsmOpcodeDecl("call", 0xFF)};
+
+#define kAsmRegisterLimit 15
diff --git a/dev/LibCompiler/AAL/CPU/arm64.h b/dev/LibCompiler/AAL/CPU/arm64.h
new file mode 100644
index 0000000..f2a14ce
--- /dev/null
+++ b/dev/LibCompiler/AAL/CPU/arm64.h
@@ -0,0 +1,26 @@
+/* -------------------------------------------
+
+Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+/// @brief ARM64 encoding support.
+/// @file CPU/arm64.hpp
+
+struct CpuOpcodeArm64;
+
+/// @brief ARM64 opcode header.
+struct CpuOpcodeArm64 final
+{
+ uint8_t fOpcode; // opcode
+ uint8_t fRegisterLeft; // left register index
+ uint8_t fRegisterRight; // right register index
+ bool fRegisterLeftHooked;
+ bool fRegisterRightHooked;
+ uint32_t fImmediateValue; // immediate 32-bit value
+ bool fImmediateValueHooked;
+};
diff --git a/dev/LibCompiler/AAL/CPU/power64.h b/dev/LibCompiler/AAL/CPU/power64.h
new file mode 100644
index 0000000..74e0966
--- /dev/null
+++ b/dev/LibCompiler/AAL/CPU/power64.h
@@ -0,0 +1,1929 @@
+/* -------------------------------------------
+
+ Some modifications are copyrighted under:
+ Theater Quality Incorporated
+
+ Original author:
+ Apple Inc
+
+------------------------------------------- */
+
+#pragma once
+
+#include <cstdint>
+
+/// @note Based of:
+/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html
+
+/*
+ * These defines are use in the cpus field of the instructions. If the field
+ * is zero it can execute on all cpus. The defines are or'ed together. This
+ * information is used to set the cpusubtype in the resulting object file.
+ */
+#define CPU601 0x1
+#define IMPL64 0x2
+#define OPTIONAL 0x4
+#define VMX 0x8
+#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */
+#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */
+
+enum optype
+{
+ NONE, /* no operand */
+ JBSR, /* jbsr pseudo op */
+ PCREL, /* PC relative (branch offset) */
+ BADDR, /* Branch address (sign extended absolute address) */
+ D, /* 16 bit displacement */
+ DS, /* 14 bit displacement (double word) */
+ SI, /* signed 16 bit immediate */
+ UI, /* unsigned 16 bit immediate */
+ HI, /* high 16 bit immediate (with truncation) */
+ GREG, /* general register */
+ G0REG, /* general register r1-r31 or 0 */
+ FREG, /* float register */
+ VREG, /* vector register */
+ SGREG, /* segment register */
+ SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */
+ BCND, /* branch condition opcode */
+ CRF, /* condition register field */
+ CRFONLY, /* condition register field only no expression allowed */
+ sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */
+ mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */
+ NUM, /* number */
+ SNUM, /* signed number */
+ NUM0, /* number (where 1<<width is the same as 0) */
+ MBE, /* mask defined by MB and ME fields */
+ FXM, /* 8-bit mask with only one bit set */
+ ZERO /* the number zero */
+};
+
+struct op
+{
+ uint32_t offset : 5;
+ uint32_t width : 5;
+ enum optype type : 6;
+};
+
+struct CpuOpcodePPC
+{
+ uint32_t opcode;
+ const char* name; // c++ wants the string to be const, it makes sense here.
+ struct op ops[5];
+ uint32_t cpus;
+};
+
+#define kOpcodePPCCount (1073U)
+
+inline CpuOpcodePPC kOpcodesPowerPC[] = {
+ {0x38000000, "addi", {{21, 5, GREG}, {16, 5, G0REG}, {0, 16, SI}}},
+ {0x38000000, "li", {{21, 5, GREG}, {0, 16, SI}}},
+ {0x3c000000, "addis", {{21, 5, GREG}, {16, 5, G0REG}, {0, 16, HI}}},
+ {0x3c000000, "lis", {{21, 5, GREG}, {0, 16, HI}}},
+ {0x30000000, "addic", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x34000000, "addic.", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x7c000214, "add", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000215, "add.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000614, "addo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000615, "addo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000014, "addc", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000015, "addc.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000414, "addco", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000415, "addco.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000114, "adde", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000115, "adde.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000514, "addeo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000515, "addeo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c0001d4, "addme", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0001d5, "addme.", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0005d4, "addmeo", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0005d5, "addmeo.", {{21, 5, GREG}, {16, 5, GREG}}},
+
+ {0x7c000194, "addze", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000195, "addze.", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000594, "addzeo", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000595, "addzeo.", {{21, 5, GREG}, {16, 5, GREG}}},
+
+ {0x70000000, "andi.", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x74000000, "andis.", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x7c000038, "and", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000039, "and.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000078, "andc", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000079, "andc.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x48000000, "b", {{2, 24, PCREL}}},
+ {0x48000002, "ba", {{2, 24, BADDR}}},
+ {0x48000001, "bl", {{2, 24, PCREL}}},
+ {0x48000003, "bla", {{2, 24, BADDR}}},
+
+ {0x48000001, "jbsr", {{0, 0, JBSR}, {2, 24, PCREL}}},
+ {0x48000000, "jmp", {{0, 0, JBSR}, {2, 24, PCREL}}},
+
+ {0x40000000, "bc", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, PCREL}}},
+ {0x40000002, "bca", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, BADDR}}},
+ {0x40000001, "bcl", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, PCREL}}},
+ {0x40000003, "bcla", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, BADDR}}},
+
+ {0x4c000420, "bcctr", {{21, 5, NUM}, {16, 5, NUM}}},
+ {0x4c000420, "bcctr", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}},
+ {0x4c000421, "bcctrl", {{21, 5, NUM}, {16, 5, NUM}}},
+ {0x4c000421, "bcctrl", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}},
+ {0x4c000020, "bclr", {{21, 5, NUM}, {16, 5, NUM}}},
+ {0x4c000020, "bclr", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}},
+ {0x4c000021, "bclrl", {{21, 5, NUM}, {16, 5, NUM}}},
+ {0x4c000021, "bclrl", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}},
+
+ /* Basic branch mnemonics (assember extended mnemonics) */
+ /* { 0x42800000, "b", {{2,14,PCREL}} }, overlaps */
+ /* { 0x42800001, "bl", {{2,14,PCREL}} }, overlaps */
+ {0x41800000, "bt", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x41800001, "btl", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40800000, "bf", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40800001, "bfl", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x42000000, "bdnz", {{2, 14, PCREL}}},
+ {0x42000001, "bdnzl", {{2, 14, PCREL}}},
+ {0x41000000, "bdnzt", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x41000001, "bdnztl", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40000000, "bdnzf", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40000001, "bdnzfl", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x42400000, "bdz", {{2, 14, PCREL}}},
+ {0x42400001, "bdzl", {{2, 14, PCREL}}},
+ {0x41400000, "bdzt", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x41400001, "bdztl", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40400000, "bdzf", {{16, 5, BCND}, {2, 14, PCREL}}},
+ {0x40400001, "bdzfl", {{16, 5, BCND}, {2, 14, PCREL}}},
+
+ /* { 0x42800002, "ba", {{2,14,BADDR}} }, overlaps */
+ /* { 0x42800003, "bla", {{2,14,BADDR}} }, overlaps */
+ {0x41800002, "bta", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x41800003, "btla", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40800002, "bfa", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40800003, "bfla", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x42000002, "bdnza", {{2, 14, BADDR}}},
+ {0x42000003, "bdnzla", {{2, 14, BADDR}}},
+ {0x41000002, "bdnzta", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x41000003, "bdnztla", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40000002, "bdnzfa", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40000003, "bdnzfla", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x42400002, "bdza", {{2, 14, BADDR}}},
+ {0x42400003, "bdzla", {{2, 14, BADDR}}},
+ {0x41400002, "bdzta", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x41400003, "bdztla", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40400002, "bdzfa", {{16, 5, BCND}, {2, 14, BADDR}}},
+ {0x40400003, "bdzfla", {{16, 5, BCND}, {2, 14, BADDR}}},
+
+ {
+ 0x4e800020,
+ "blr",
+ },
+ {0x4e800020, "blr", {{11, 2, NUM}}},
+ {
+ 0x4e800021,
+ "blrl",
+ },
+ {0x4e800021, "blrl", {{11, 2, NUM}}},
+ {0x4d800020, "btlr", {{16, 5, BCND}}},
+ {0x4d800020, "btlr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4d800021, "btlrl", {{16, 5, BCND}}},
+ {0x4d800021, "btlrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c800020, "bflr", {{16, 5, BCND}}},
+ {0x4c800020, "bflr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c800021, "bflrl", {{16, 5, BCND}}},
+ {0x4c800021, "bflrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {
+ 0x4e000020,
+ "bdnzlr",
+ },
+ {0x4e000020, "bdnzlr", {{11, 2, NUM}}},
+ {
+ 0x4e000021,
+ "bdnzlrl",
+ },
+ {0x4e000021, "bdnzlrl", {{11, 2, NUM}}},
+ {0x4d000020, "bdnztlr", {{16, 5, BCND}}},
+ {0x4d000020, "bdnztlr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4d000021, "bdnztlrl", {{16, 5, BCND}}},
+ {0x4d000021, "bdnztlrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c000020, "bdnzflr", {{16, 5, BCND}}},
+ {0x4c000020, "bdnzflr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c000021, "bdnzflrl", {{16, 5, BCND}}},
+ {0x4c000021, "bdnzflrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {
+ 0x4e400020,
+ "bdzlr",
+ },
+ {0x4e400020, "bdzlr", {{11, 2, NUM}}},
+ {
+ 0x4e400021,
+ "bdzlrl",
+ },
+ {0x4e400021, "bdzlrl", {{11, 2, NUM}}},
+ {0x4d400020, "bdztlr", {{16, 5, BCND}}},
+ {0x4d400020, "bdztlr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4d400021, "bdztlrl", {{16, 5, BCND}}},
+ {0x4d400021, "bdztlrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c400020, "bdzflr", {{16, 5, BCND}}},
+ {0x4c400020, "bdzflr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c400021, "bdzflrl", {{16, 5, BCND}}},
+ {0x4c400021, "bdzflrl", {{16, 5, BCND}, {11, 2, NUM}}},
+
+ {0x4c000420, "bctr", {{21, 5, NUM}, {16, 5, NUM}}},
+ {
+ 0x4e800420,
+ "bctr",
+ },
+ {0x4e800420, "bctr", {{11, 2, NUM}}},
+ {0x4c000421, "bctrl", {{21, 5, NUM}, {16, 5, NUM}}},
+ {
+ 0x4e800421,
+ "bctrl",
+ },
+ {0x4e800421, "bctrl", {{11, 2, NUM}}},
+ {0x4d800420, "btctr", {{16, 5, BCND}}},
+ {0x4d800420, "btctr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4d800421, "btctrl", {{16, 5, BCND}}},
+ {0x4d800421, "btctrl", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c800420, "bfctr", {{16, 5, BCND}}},
+ {0x4c800420, "bfctr", {{16, 5, BCND}, {11, 2, NUM}}},
+ {0x4c800421, "bfctrl", {{16, 5, BCND}}},
+ {0x4c800421, "bfctrl", {{16, 5, BCND}, {11, 2, NUM}}},
+
+ /* branch mnemonics incorporating conditions (assember extended mnemonics)
+ */
+ {0x41800000, "blt", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41800000, "blt", {{2, 14, PCREL}}},
+ {0x41800001, "bltl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41800001, "bltl", {{2, 14, PCREL}}},
+ {0x40810000, "ble", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40810000, "ble", {{2, 14, PCREL}}},
+ {0x40810001, "blel", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40810001, "blel", {{2, 14, PCREL}}},
+ {0x41820000, "beq", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41820000, "beq", {{2, 14, PCREL}}},
+ {0x41820001, "beql", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41820001, "beql", {{2, 14, PCREL}}},
+ {0x40800000, "bge", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40800000, "bge", {{2, 14, PCREL}}},
+ {0x40800001, "bgel", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40800001, "bgel", {{2, 14, PCREL}}},
+ {0x41810000, "bgt", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41810000, "bgt", {{2, 14, PCREL}}},
+ {0x41810001, "bgtl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41810001, "bgtl", {{2, 14, PCREL}}},
+ {0x40800000, "bnl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40800000, "bnl", {{2, 14, PCREL}}},
+ {0x40800001, "bnll", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40800001, "bnll", {{2, 14, PCREL}}},
+ {0x40820000, "bne", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40820000, "bne", {{2, 14, PCREL}}},
+ {0x40820001, "bnel", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40820001, "bnel", {{2, 14, PCREL}}},
+ {0x40810000, "bng", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40810000, "bng", {{2, 14, PCREL}}},
+ {0x40810001, "bngl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40810001, "bngl", {{2, 14, PCREL}}},
+ {0x41830000, "bso", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41830000, "bso", {{2, 14, PCREL}}},
+ {0x41830001, "bsol", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41830001, "bsol", {{2, 14, PCREL}}},
+ {0x40830000, "bns", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40830000, "bns", {{2, 14, PCREL}}},
+ {0x40830001, "bnsl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40830001, "bnsl", {{2, 14, PCREL}}},
+ {0x41830000, "bun", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41830000, "bun", {{2, 14, PCREL}}},
+ {0x41830001, "bunl", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x41830001, "bunl", {{2, 14, PCREL}}},
+ {0x40830000, "bnu", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40830000, "bnu", {{2, 14, PCREL}}},
+ {0x40830001, "bnul", {{16, 5, CRF}, {2, 14, PCREL}}},
+ {0x40830001, "bnul", {{2, 14, PCREL}}},
+
+ {0x41800002, "blta", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41800002, "blta", {{2, 14, BADDR}}},
+ {0x41800003, "bltla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41800003, "bltla", {{2, 14, BADDR}}},
+ {0x40810002, "blea", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40810002, "blea", {{2, 14, BADDR}}},
+ {0x40810003, "blela", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40810003, "blela", {{2, 14, BADDR}}},
+ {0x41820002, "beqa", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41820002, "beqa", {{2, 14, BADDR}}},
+ {0x41820003, "beqla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41820003, "beqla", {{2, 14, BADDR}}},
+ {0x40800002, "bgea", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40800002, "bgea", {{2, 14, BADDR}}},
+ {0x40800003, "bgela", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40800003, "bgela", {{2, 14, BADDR}}},
+ {0x41810002, "bgta", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41810002, "bgta", {{2, 14, BADDR}}},
+ {0x41810003, "bgtla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41810003, "bgtla", {{2, 14, BADDR}}},
+ {0x40800002, "bnla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40800002, "bnla", {{2, 14, BADDR}}},
+ {0x40800003, "bnlla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40800003, "bnlla", {{2, 14, BADDR}}},
+ {0x40820002, "bnea", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40820002, "bnea", {{2, 14, BADDR}}},
+ {0x40820003, "bnela", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40820003, "bnela", {{2, 14, BADDR}}},
+ {0x40810002, "bnga", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40810002, "bnga", {{2, 14, BADDR}}},
+ {0x40810003, "bngla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40810003, "bngla", {{2, 14, BADDR}}},
+ {0x41830002, "bsoa", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41830002, "bsoa", {{2, 14, BADDR}}},
+ {0x41830003, "bsola", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41830003, "bsola", {{2, 14, BADDR}}},
+ {0x40830002, "bnsa", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40830002, "bnsa", {{2, 14, BADDR}}},
+ {0x40830003, "bnsla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40830003, "bnsla", {{2, 14, BADDR}}},
+ {0x41830002, "buna", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41830002, "buna", {{2, 14, BADDR}}},
+ {0x41830003, "bunla", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x41830003, "bunla", {{2, 14, BADDR}}},
+ {0x40830002, "bnua", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40830002, "bnua", {{2, 14, BADDR}}},
+ {0x40830003, "bnula", {{16, 5, CRF}, {2, 14, BADDR}}},
+ {0x40830003, "bnula", {{2, 14, BADDR}}},
+
+ {0x4d800020, "bltlr", {{16, 5, CRF}}},
+ {0x4d800020, "bltlr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d800020,
+ "bltlr",
+ },
+ {0x4d800021, "bltlrl", {{16, 5, CRF}}},
+ {0x4d800021, "bltlrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d800021,
+ "bltlrl",
+ },
+ {0x4c810020, "blelr", {{16, 5, CRF}}},
+ {0x4c810020, "blelr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810020,
+ "blelr",
+ },
+ {0x4c810021, "blelrl", {{16, 5, CRF}}},
+ {0x4c810021, "blelrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810021,
+ "blelrl",
+ },
+ {0x4d820020, "beqlr", {{16, 5, CRF}}},
+ {0x4d820020, "beqlr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d820020,
+ "beqlr",
+ },
+ {0x4d820021, "beqlrl", {{16, 5, CRF}}},
+ {0x4d820021, "beqlrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d820021,
+ "beqlrl",
+ },
+ {0x4c800020, "bgelr", {{16, 5, CRF}}},
+ {0x4c800020, "bgelr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800020,
+ "bgelr",
+ },
+ {0x4c800021, "bgelrl", {{16, 5, CRF}}},
+ {0x4c800021, "bgelrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800021,
+ "bgelrl",
+ },
+ {0x4d810020, "bgtlr", {{16, 5, CRF}}},
+ {0x4d810020, "bgtlr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d810020,
+ "bgtlr",
+ },
+ {0x4d810021, "bgtlrl", {{16, 5, CRF}}},
+ {0x4d810021, "bgtlrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d810021,
+ "bgtlrl",
+ },
+ {0x4c800020, "bnllr", {{16, 5, CRF}}},
+ {0x4c800020, "bnllr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800020,
+ "bnllr",
+ },
+ {0x4c800021, "bnllrl", {{16, 5, CRF}}},
+ {0x4c800021, "bnllrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800021,
+ "bnllrl",
+ },
+ {0x4c820020, "bnelr", {{16, 5, CRF}}},
+ {0x4c820020, "bnelr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c820020,
+ "bnelr",
+ },
+ {0x4c820021, "bnelrl", {{16, 5, CRF}}},
+ {0x4c820021, "bnelrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c820021,
+ "bnelrl",
+ },
+ {0x4c810020, "bnglr", {{16, 5, CRF}}},
+ {0x4c810020, "bnglr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810020,
+ "bnglr",
+ },
+ {0x4c810021, "bnglrl", {{16, 5, CRF}}},
+ {0x4c810021, "bnglrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810021,
+ "bnglrl",
+ },
+ {0x4d830020, "bsolr", {{16, 5, CRF}}},
+ {0x4d830020, "bsolr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830020,
+ "bsolr",
+ },
+ {0x4d830021, "bsolrl", {{16, 5, CRF}}},
+ {0x4d830021, "bsolrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830021,
+ "bsolrl",
+ },
+ {0x4c830020, "bnslr", {{16, 5, CRF}}},
+ {0x4c830020, "bnslr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830020,
+ "bnslr",
+ },
+ {0x4c830021, "bnslrl", {{16, 5, CRF}}},
+ {0x4c830021, "bnslrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830021,
+ "bnslrl",
+ },
+ {0x4d830020, "bunlr", {{16, 5, CRF}}},
+ {0x4d830020, "bunlr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830020,
+ "bunlr",
+ },
+ {0x4d830021, "bunlrl", {{16, 5, CRF}}},
+ {0x4d830021, "bunlrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830021,
+ "bunlrl",
+ },
+ {0x4c830020, "bnulr", {{16, 5, CRF}}},
+ {0x4c830020, "bnulr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830020,
+ "bnulr",
+ },
+ {0x4c830021, "bnulrl", {{16, 5, CRF}}},
+ {0x4c830021, "bnulrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830021,
+ "bnulrl",
+ },
+
+ {0x4d800420, "bltctr", {{16, 5, CRF}}},
+ {0x4d800420, "bltctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d800420,
+ "bltctr",
+ },
+ {0x4d800421, "bltctrl", {{16, 5, CRF}}},
+ {0x4d800421, "bltctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d800421,
+ "bltctrl",
+ },
+ {0x4c810420, "blectr", {{16, 5, CRF}}},
+ {0x4c810420, "blectr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810420,
+ "blectr",
+ },
+ {0x4c810421, "blectrl", {{16, 5, CRF}}},
+ {0x4c810421, "blectrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810421,
+ "blectrl",
+ },
+ {0x4d820420, "beqctr", {{16, 5, CRF}}},
+ {0x4d820420, "beqctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d820420,
+ "beqctr",
+ },
+ {0x4d820421, "beqctrl", {{16, 5, CRF}}},
+ {0x4d820421, "beqctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d820421,
+ "beqctrl",
+ },
+ {0x4c800420, "bgectr", {{16, 5, CRF}}},
+ {0x4c800420, "bgectr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800420,
+ "bgectr",
+ },
+ {0x4c800421, "bgectrl", {{16, 5, CRF}}},
+ {0x4c800421, "bgectrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800421,
+ "bgectrl",
+ },
+ {0x4d810420, "bgtctr", {{16, 5, CRF}}},
+ {0x4d810420, "bgtctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d810420,
+ "bgtctr",
+ },
+ {0x4d810421, "bgtctrl", {{16, 5, CRF}}},
+ {0x4d810421, "bgtctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d810421,
+ "bgtctrl",
+ },
+ {0x4c800420, "bnlctr", {{16, 5, CRF}}},
+ {0x4c800420, "bnlctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800420,
+ "bnlctr",
+ },
+ {0x4c800421, "bnlctrl", {{16, 5, CRF}}},
+ {0x4c800421, "bnlctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c800421,
+ "bnlctrl",
+ },
+ {0x4c820420, "bnectr", {{16, 5, CRF}}},
+ {0x4c820420, "bnectr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c820420,
+ "bnectr",
+ },
+ {0x4c820421, "bnectrl", {{16, 5, CRF}}},
+ {0x4c820421, "bnectrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c820421,
+ "bnectrl",
+ },
+ {0x4c810420, "bngctr", {{16, 5, CRF}}},
+ {0x4c810420, "bngctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810420,
+ "bngctr",
+ },
+ {0x4c810421, "bngctrl", {{16, 5, CRF}}},
+ {0x4c810421, "bngctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c810421,
+ "bngctrl",
+ },
+ {0x4d830420, "bsoctr", {{16, 5, CRF}}},
+ {0x4d830420, "bsoctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830420,
+ "bsoctr",
+ },
+ {0x4d830421, "bsoctrl", {{16, 5, CRF}}},
+ {0x4d830421, "bsoctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830421,
+ "bsoctrl",
+ },
+ {0x4c830420, "bnsctr", {{16, 5, CRF}}},
+ {0x4c830420, "bnsctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830420,
+ "bnsctr",
+ },
+ {0x4c830421, "bnsctrl", {{16, 5, CRF}}},
+ {0x4c830421, "bnsctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830421,
+ "bnsctrl",
+ },
+ {0x4d830420, "bunctr", {{16, 5, CRF}}},
+ {0x4d830420, "bunctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830420,
+ "bunctr",
+ },
+ {0x4d830421, "bunctrl", {{16, 5, CRF}}},
+ {0x4d830421, "bunctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4d830421,
+ "bunctrl",
+ },
+ {0x4c830420, "bnuctr", {{16, 5, CRF}}},
+ {0x4c830420, "bnuctr", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830420,
+ "bnuctr",
+ },
+ {0x4c830421, "bnuctrl", {{16, 5, CRF}}},
+ {0x4c830421, "bnuctrl", {{16, 5, CRF}, {11, 2, NUM}}},
+ {
+ 0x4c830421,
+ "bnuctrl",
+ },
+
+ {0x2c000000, "cmpi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000,
+ "cmpi",
+ {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000, "cmpi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000,
+ "cmpi",
+ {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000, "cmpwi", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000, "cmpwi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c000000, "cmpwi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c200000, "cmpdi", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x2c200000, "cmpdi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x2c200000, "cmpdi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+
+ {0x7c000000, "cmp", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000,
+ "cmp",
+ {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000, "cmp", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000,
+ "cmp",
+ {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000, "cmpw", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000, "cmpw", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000000, "cmpw", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200000, "cmpd", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200000, "cmpd", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200000, "cmpd", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x28000000, "cmpli", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000,
+ "cmpli",
+ {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000, "cmpli", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000,
+ "cmpli",
+ {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000, "cmplwi", {{16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000, "cmplwi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28000000, "cmplwi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28200000, "cmpldi", {{16, 5, GREG}, {0, 16, UI}}},
+ {0x28200000, "cmpldi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}},
+ {0x28200000, "cmpldi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}},
+
+ {0x7c000040, "cmpl", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040,
+ "cmpl",
+ {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040, "cmpl", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040,
+ "cmpl",
+ {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040, "cmplw", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040, "cmplw", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000040, "cmplw", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200040, "cmpld", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200040, "cmpld", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200040, "cmpld", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000034, "cntlzw", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c000035, "cntlzw.", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c000074, "cntlzd", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64},
+ {0x7c000075, "cntlzd.", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64},
+
+ {0x4c000202, "crand", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000102, "crandc", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000242, "creqv", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c0001c2, "crnand", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000042, "crnor", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000382, "cror", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000342, "crorc", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+ {0x4c000182, "crxor", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}},
+
+ {0x7c0003d2, "divd", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c0003d3,
+ "divd.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0007d2,
+ "divdo",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0007d3,
+ "divdo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c000392,
+ "divdu",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c000393,
+ "divdu.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c000792,
+ "divduo",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c000793,
+ "divduo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c0003d6, "divw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0003d7, "divw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0007d6, "divwo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0007d7, "divwo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000396, "divwu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000397, "divwu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000796, "divwuo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000797, "divwuo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000238, "eqv", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000239, "eqv.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000774, "extsb", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c000775, "extsb.", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c000734, "extsh", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c000735, "extsh.", {{16, 5, GREG}, {21, 5, GREG}}},
+ {0x7c0007b4, "extsw", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64},
+ {0x7c0007b5, "extsw.", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64},
+
+ {0xfc00002a, "fadd", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00002b, "fadd.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec00002a, "fadds", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec00002b, "fadds.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000028, "fsub", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000029, "fsub.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec000028, "fsubs", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec000029, "fsubs.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000032, "fmul", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}},
+ {0xfc000033, "fmul.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}},
+ {0xec000032, "fmuls", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}},
+ {0xec000033, "fmuls.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}},
+ {0xfc000024, "fdiv", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000025, "fdiv.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec000024, "fdivs", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xec000025, "fdivs.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}},
+
+ {0xfc00003a,
+ "fmadd",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00003b,
+ "fmadd.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003a,
+ "fmadds",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003b,
+ "fmadds.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000038,
+ "fmsub",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000039,
+ "fmsub.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec000038,
+ "fmsubs",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec000039,
+ "fmsubs.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00003e,
+ "fnmadd",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00003f,
+ "fnmadd.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003e,
+ "fnmadds",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003f,
+ "fnmadds.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00003c,
+ "fnmsub",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00003d,
+ "fnmsub.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003c,
+ "fnmsubs",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xec00003d,
+ "fnmsubs.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+
+ {0xfc000090, "fmr", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000091, "fmr.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000210, "fabs", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000211, "fabs.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000050, "fneg", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000051, "fneg.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000110, "fnabs", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000111, "fnabs.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xec000030, "fres", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xec000031, "fres.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000018, "frsp", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000019, "frsp.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000034, "frsqrte", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000035, "frsqrte.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00002e,
+ "fsel",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00002f,
+ "fsel.",
+ {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00002c, "fsqrt", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970},
+ {0xfc00002d, "fsqrt.", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970},
+ {0xec00002c, "fsqrts", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970},
+ {0xec00002d, "fsqrts.", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970},
+ {0xfc00065c, "fctid", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+ {0xfc00065d, "fctid.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+ {0xfc00065e, "fctidz", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+ {0xfc00065f, "fctidz.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+ {0xfc00001c, "fctiw", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00001d, "fctiw.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00001e, "fctiwz", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00001f, "fctiwz.", {{21, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00069c, "fcfid", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+ {0xfc00069d, "fcfid.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64},
+
+ {0xfc000000, "fcmpu", {{21, 5, CRFONLY}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000000, "fcmpu", {{23, 3, NUM}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000040, "fcmpo", {{21, 5, CRFONLY}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc000040, "fcmpo", {{23, 3, NUM}, {16, 5, FREG}, {11, 5, FREG}}},
+ {0xfc00048e, "mffs", {{21, 5, FREG}}},
+ {0xfc00048f, "mffs.", {{21, 5, FREG}}},
+ {0xfc000080, "mcrfs", {{21, 5, CRFONLY}, {18, 5, NUM}}},
+ {0xfc000080, "mcrfs", {{23, 3, NUM}, {18, 5, NUM}}},
+ {0xfc00010c, "mtfsfi", {{23, 3, NUM}, {12, 4, NUM}}},
+ {0xfc00010d, "mtfsfi.", {{23, 3, NUM}, {12, 4, NUM}}},
+ {0xfc00058e, "mtfsf", {{17, 8, NUM}, {11, 5, FREG}}},
+ {0xfc00058f, "mtfsf.", {{17, 8, NUM}, {11, 5, FREG}}},
+ {0xfc00008c, "mtfsb0", {{21, 5, NUM}}},
+ {0xfc00008d, "mtfsb0.", {{21, 5, NUM}}},
+ {0xfc00004c, "mtfsb1", {{21, 5, NUM}}},
+ {0xfc00004d, "mtfsb1.", {{21, 5, NUM}}},
+
+ {0x88000000, "lbz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c0000ae, "lbzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x8c000000, "lbzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c0000ee, "lbzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xa0000000, "lhz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c00022e, "lhzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0xa4000000, "lhzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c00026e, "lhzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xa8000000, "lha", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c0002ae, "lhax", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0xac000000, "lhau", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c0002ee, "lhaux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x80000000, "lwz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x7c00002e, "lwzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x84000000, "lwzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c00006e, "lwzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xe8000002, "lwa", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64},
+ {0x7c0002aa,
+ "lwax",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0002ea,
+ "lwaux",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0xe8000000, "ld", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64},
+ {0x7c00002a, "ldx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64},
+ {0xe8000001, "ldu", {{21, 5, GREG}, {2, 14, DS}, {16, 5, GREG}}, IMPL64},
+ {0x7c00006a, "ldux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+
+ {0xb8000000, "lmw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xbc000000, "stmw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+
+ {0x7c00062c, "lhbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00042c, "lwbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00042a, "lswx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c000028, "lwarx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0000a8,
+ "ldarx",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c00022a,
+ "lscbx",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ CPU601},
+ {0x7c00022b,
+ "lscbx.",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c0004aa, "lswi", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, NUM0}}},
+
+ {0xc0000000, "lfs", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xc4000000, "lfsu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c00042e, "lfsx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00046e, "lfsux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xc8000000, "lfd", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xcc000000, "lfdu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c0004ae, "lfdx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0004ee, "lfdux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x38000000, "la", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+
+ {0x4c000000, "mcrf", {{21, 5, CRFONLY}, {16, 5, CRFONLY}}},
+ {0x4c000000, "mcrf", {{23, 3, NUM}, {18, 3, NUM}}},
+
+ {0x7c0002a6, "mfspr", {{21, 5, GREG}, {11, 10, SPREG}}},
+ {0x7c0003a6, "mtspr", {{11, 10, SPREG}, {21, 5, GREG}}},
+ {0x7c000120, "mtcrf", {{12, 8, FXM}, {21, 5, GREG}}},
+ {0x7c000120, "mtocrf", {{12, 8, FXM}, {21, 5, GREG}}},
+ {0x7c000400, "mcrxr", {{21, 5, CRFONLY}}},
+ {0x7c000400, "mcrxr", {{23, 3, NUM}}},
+ {0x7c000026, "mfcr", {{21, 5, GREG}}},
+ {0x7c100026, "mfcr", {{21, 5, GREG}, {12, 8, FXM}}},
+ {0x7c100026, "mfocrf", {{21, 5, GREG}, {12, 8, FXM}}},
+
+ /* Move to/from spr mnemonics (assember extended mnemonics) */
+ {0x7c0102a6, "mfxer", {{21, 5, GREG}}},
+ {0x7c0802a6, "mflr", {{21, 5, GREG}}},
+ {0x7c0902a6, "mfctr", {{21, 5, GREG}}},
+ {0x7c0103a6, "mtxer", {{21, 5, GREG}}},
+ {0x7c0803a6, "mtlr", {{21, 5, GREG}}},
+ {0x7c0903a6, "mtctr", {{21, 5, GREG}}},
+ {0x7c0002a6, "mfmq", {{21, 5, GREG}}},
+ {0x7c0502a6, "mfrtcl", {{21, 5, GREG}}},
+ {0x7c0402a6, "mfrtcu", {{21, 5, GREG}}},
+ {0x7c0003a6, "mtmq", {{21, 5, GREG}}},
+ {0x7c1503a6, "mtrtcl", {{21, 5, GREG}}},
+ {0x7c1403a6, "mtrtcu", {{21, 5, GREG}}},
+
+#ifdef NRW_COMPILER
+ {0x7c0001d6, "mull", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0001d7, "mull.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0005d6, "mullo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0005d7, "mullo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+#endif /* NRW_COMPILER */
+ {0x7c0001d6, "mullw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0001d7, "mullw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0005d6, "mullwo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0005d7, "mullwo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000092,
+ "mulhd",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c000093,
+ "mulhd.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+#ifdef NRW_COMPILER
+ {0x7c000096, "mulwd", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000097, "mulwd.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+#endif /* NRW_COMPILER */
+ {0x7c000096, "mulhw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000097, "mulhw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000012,
+ "mulhdu",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c000013,
+ "mulhdu.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c000016, "mulhwu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000017, "mulhwu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c0001d2,
+ "mulld",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0001d3,
+ "mulld.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0005d2,
+ "mulldo",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c0005d3,
+ "mulldo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c0003b8, "nand", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0003b9, "nand.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c0000d0, "neg", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0000d1, "neg.", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0004d0, "nego", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0004d1, "nego.", {{21, 5, GREG}, {16, 5, GREG}}},
+
+ {0x7c0000f8, "nor", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c0000f9, "nor.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ /* Miscellaneous mnemonics (assember extended mnemonics) */
+ {
+ 0x60000000,
+ "nop",
+ },
+
+ {0x60000000, "ori", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x60000000, "ori", {{16, 5, ZERO}, {21, 5, ZERO}, {0, 16, ZERO}}},
+ {0x64000000, "oris", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x7c000378, "or", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000379, "or.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ /// @brief Move register
+ {0x7c000378, "mr", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000338, "orc", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000339, "orc.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ {0x78000000,
+ "rldicl",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000001,
+ "rldicl.",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000004,
+ "rldicr",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000005,
+ "rldicr.",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000008,
+ "rldic",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000009,
+ "rldic.",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x7800000c,
+ "rldimi",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x7800000d,
+ "rldimi.",
+ {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}},
+ IMPL64},
+ {0x78000010,
+ "rldcl",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}},
+ IMPL64},
+ {0x78000011,
+ "rldcl.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}},
+ IMPL64},
+ {0x78000012,
+ "rldcr",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}},
+ IMPL64},
+ {0x78000013,
+ "rldcr.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}},
+ IMPL64},
+
+ {0x54000000,
+ "rlwinm",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}},
+ {0x54000001,
+ "rlwinm.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}},
+ {0x5c000000,
+ "rlwnm",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}},
+ {0x5c000001,
+ "rlwnm.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}},
+ {0x50000000,
+ "rlwimi",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}},
+ {0x50000001,
+ "rlwimi.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}},
+
+ {
+ 0x44000002,
+ "sc",
+ },
+ {0x4c000024, "rfid", {{0}}, IMPL64 | OPTIONAL},
+
+ {0x7c000030, "slw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000031, "slw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000036, "sld", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c000037, "sld.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64},
+
+ {0x7c000430, "srw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000431, "srw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000436, "srd", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c000437, "srd.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64},
+
+ {0x7c000670, "srawi", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}},
+ {0x7c000671, "srawi.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}},
+ {0x7c000674, "sradi", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}}, IMPL64},
+ {0x7c000675, "sradi.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}}, IMPL64},
+
+ {0x7c000630, "sraw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000631, "sraw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000634, "srad", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c000635,
+ "srad.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x98000000, "stb", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x9c000000, "stbu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c0001ae, "stbx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0001ee, "stbux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xb0000000, "sth", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xb4000000, "sthu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c00032e, "sthx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00036e, "sthux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x90000000, "stw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0x94000000, "stwu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c00012e, "stwx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00016e, "stwux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xf8000000, "std", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64},
+ {0xf8000001, "stdu", {{21, 5, GREG}, {2, 14, DS}, {16, 5, GREG}}, IMPL64},
+ {0x7c00012a,
+ "stdx",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ IMPL64},
+ {0x7c00016a,
+ "stdux",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c00072c, "sthbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00052c, "stwbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00052a, "stswx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00012d, "stwcx.", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0001ad,
+ "stdcx.",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ IMPL64},
+
+ {0x7c0005aa, "stswi", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, NUM0}}},
+
+ {
+ 0x7c0007ae,
+ "stfiwx",
+ {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ },
+
+ {0xd0000000, "stfs", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xd4000000, "stfsu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c00052e, "stfsx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00056e, "stfsux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0xd8000000, "stfd", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}},
+ {0xdc000000, "stfdu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}},
+ {0x7c0005ae, "stfdx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0005ee, "stfdux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x20000000, "subfic", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x7c000050, "sub", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000051, "sub.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000450, "subo", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000451, "subo.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000050, "subf", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000051, "subf.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000450, "subfo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000451, "subfo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000010, "subc", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000011, "subc.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000410, "subco", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000411, "subco.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000010, "subfc", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000011, "subfc.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000410, "subfco", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000411, "subfco.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c000110, "subfe", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000111, "subfe.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000510, "subfeo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000511, "subfeo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}},
+
+ {0x7c0001d0, "subfme", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0001d1, "subfme.", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0005d0, "subfmeo", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c0005d1, "subfmeo.", {{21, 5, GREG}, {16, 5, GREG}}},
+
+ {0x7c000190, "subfze", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000191, "subfze.", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000590, "subfzeo", {{21, 5, GREG}, {16, 5, GREG}}},
+ {0x7c000591, "subfzeo.", {{21, 5, GREG}, {16, 5, GREG}}},
+
+ {
+ 0x7c0004ac,
+ "sync",
+ },
+ {0x7c0004ac, "sync", {{21, 2, NUM}}},
+ {
+ 0x7c2004ac,
+ "lwsync",
+ },
+ {
+ 0x7c4004ac,
+ "ptesync",
+ },
+
+ {0x08000000, "tdi", {{21, 5, NUM}, {16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x0a000000, "tdlti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x0a800000, "tdlei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08800000, "tdeqi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x09800000, "tdgei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x09000000, "tdgti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x09800000, "tdnli", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x0b000000, "tdnei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x0a800000, "tdngi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08400000, "tdllti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08c00000, "tdllei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08a00000, "tdlgei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08200000, "tdlgti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08a00000, "tdlnli", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+ {0x08c00000, "tdlngi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64},
+
+ {0x7c000088, "td", {{21, 5, NUM}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7e000088, "tdlt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7e800088, "tdle", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c800088, "tdeq", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7d800088, "tdge", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7d000088, "tdgt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7d800088, "tdnl", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7f000088, "tdne", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7e800088, "tdng", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c400088, "tdllt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7cc00088, "tdlle", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7ca00088, "tdlge", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7c200088, "tdlgt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7ca00088, "tdlnl", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+ {0x7cc00088, "tdlng", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64},
+
+ {0x0c000000, "twi", {{21, 5, NUM}, {16, 5, GREG}, {0, 16, SI}}},
+ {0x0e000000, "twlti", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0e800000, "twlei", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0c800000, "tweqi", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0d800000, "twgei", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0d000000, "twgti", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0d800000, "twnli", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0f000000, "twnei", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0e800000, "twngi", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0c400000, "twllti", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0cc00000, "twllei", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0ca00000, "twlgei", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0c200000, "twlgti", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0ca00000, "twlnli", {{16, 5, GREG}, {0, 16, SI}}},
+ {0x0cc00000, "twlngi", {{16, 5, GREG}, {0, 16, SI}}},
+
+ {0x7c000008, "tw", {{21, 5, NUM}, {16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000008, "tw", {{21, 5, NUM}, {16, 5, ZERO}, {11, 5, ZERO}}},
+ {0x7e000008, "twlt", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7e800008, "twle", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c800008, "tweq", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7d800008, "twge", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7d000008, "twgt", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7d800008, "twnl", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7f000008, "twne", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7e800008, "twng", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c400008, "twllt", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7cc00008, "twlle", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7ca00008, "twlge", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7c200008, "twlgt", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7ca00008, "twlnl", {{16, 5, GREG}, {11, 5, GREG}}},
+ {0x7cc00008, "twlng", {{16, 5, GREG}, {11, 5, GREG}}},
+ {
+ 0x7fe00008,
+ "trap",
+ },
+
+ {0x68000000, "xori", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x6c000000, "xoris", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}},
+ {0x7c000278, "xor", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000279, "xor.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}},
+
+ /* Cache Management Instructions (from book II) */
+ {0x7c0007ac, "icbi", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {
+ 0x4c00012c,
+ "isync",
+ },
+ {0x7c00022c, "dcbt", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {
+ 0x7c00022c,
+ "dcbt",
+ {{16, 5, G0REG}, {11, 5, GREG}, {21, 4, NUM}},
+ },
+ {0x7c0001ec, "dcbtst", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00022c,
+ "dcbt128",
+ {{16, 5, G0REG}, {11, 5, GREG}, {21, 4, NUM}},
+ IMPL64 | OPTIONAL},
+ {0x7c0007ec, "dcbz", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c2007ec, "dcbzl", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c2007ec, "dcbz128", {{16, 5, G0REG}, {11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c00006c, "dcbst", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0000ac, "dcbf", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c00026c,
+ "eciwx",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ OPTIONAL | CPU970},
+ {0x7c00036c,
+ "ecowx",
+ {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}},
+ OPTIONAL | CPU970},
+ {
+ 0x7c0006ac,
+ "eieio",
+ },
+ /* Instructions (from book III) */
+ {
+ 0x4c000064,
+ "rfi",
+ },
+ {0x7c000124, "mtmsr", {{21, 5, GREG}}},
+ {0x7c000164, "mtmsrd", {{21, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c000164, "mtmsrd", {{21, 5, GREG}, {16, 1, NUM}}, IMPL64 | OPTIONAL},
+ {0x7c0000a6, "mfmsr", {{21, 5, GREG}}},
+ {0x7c0005ec, "dcba", {{16, 5, G0REG}, {11, 5, GREG}}, OPTIONAL},
+ {0x7c0003ac, "dcbi", {{16, 5, G0REG}, {11, 5, GREG}}},
+ {0x7c0001a4, "mtsr", {{16, 4, SGREG}, {21, 5, GREG}}},
+ {0x7c0004a6, "mfsr", {{21, 5, GREG}, {16, 4, SGREG}}},
+ {0x7c0001e4, "mtsrin", {{21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000526, "mfsrin", {{21, 5, GREG}, {11, 5, GREG}}},
+ {0x7c000364, "slbie", {{11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c0003e4, "slbia", {{0}}, IMPL64 | OPTIONAL},
+ {0x7c000324, "slbmte", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c0006a6, "slbmfev", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c000726, "slbmfee", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c000264, "tlbie", {{11, 5, GREG}}, OPTIONAL | CPU970},
+ {0x7c000264,
+ "tlbie",
+ {{11, 5, GREG}, {21, 1, NUM}},
+ IMPL64 | OPTIONAL | CPU970},
+ {0x7c000224, "tlbiel", {{11, 5, GREG}}, IMPL64 | OPTIONAL},
+ {0x7c0002e4, "tlbia", {{0}}, OPTIONAL | CPU970},
+ {0x7c00046c, "tlbsync", {{0}}, OPTIONAL | CPU970},
+ {0x7c1c43a6, "mttbl", {{21, 5, GREG}}},
+ {0x7c1d43a6, "mttbu", {{21, 5, GREG}}},
+ {0x7c0002e6, "mftb", {{21, 5, GREG}, {11, 10, SPREG}}},
+ {0x7c0c42e6, "mftb", {{21, 5, GREG}}},
+ {0x7c0d42e6, "mftbu", {{21, 5, GREG}}},
+ {0x00000200, "attn", {{11, 15, NUM}}, OPTIONAL | CPU970},
+
+ /* Instructions (from book IV) */
+ {0x24000000, "dozi", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}, CPU601},
+ {0x7c000210, "doz", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000211, "doz.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000610, "dozo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000611,
+ "dozo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c0002d0, "abs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0002d1, "abs.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0006d0, "abso", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0006d1, "abso.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+
+ {0x7c0003d0, "nabs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0003d1, "nabs.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0007d0, "nabso", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+ {0x7c0007d1, "nabso.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+
+ {0x1c000000, "mulli", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}},
+
+ {0x7c0000d6, "mul", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0000d7, "mul.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0004d6, "mulo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0004d7,
+ "mulo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c000296, "div", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000297, "div.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000696, "divo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000697,
+ "divo.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c0002d6, "divs", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0002d7,
+ "divs.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+ {0x7c0006d6,
+ "divso",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+ {0x7c0006d7,
+ "divso.",
+ {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x58000000,
+ "rlmi",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}},
+ CPU601},
+ {0x58000001,
+ "rlmi.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}},
+ CPU601},
+
+ {0x7c000432, "rrib", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000433,
+ "rrib.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c00003a,
+ "maskg",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+ {0x7c00003b,
+ "maskg.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c00043a,
+ "maskir",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+ {0x7c00043b,
+ "maskir.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c000130, "slq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000131, "slq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+
+ {0x7c000530, "srq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000531, "srq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+
+ {0x7c000170, "sliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+ {0x7c000171, "sliq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+
+ {0x7c000570, "sriq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+ {0x7c000571, "sriq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+
+ {0x7c0001f0, "slliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+ {0x7c0001f1,
+ "slliq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}},
+ CPU601},
+
+ {0x7c0005f0, "srliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+ {0x7c0005f1,
+ "srliq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}},
+ CPU601},
+
+ {0x7c0001b0, "sllq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0001b1,
+ "sllq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c0005b0, "srlq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0005b1,
+ "srlq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c000132, "sle", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000133, "sle.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+
+ {0x7c000532, "sre", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000533, "sre.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+
+ {0x7c0001b2, "sleq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0001b3,
+ "sleq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c0005b2, "sreq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c0005b3,
+ "sreq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c000770, "sraiq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601},
+ {0x7c000771,
+ "sraiq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}},
+ CPU601},
+
+ {0x7c000730, "sraq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000731,
+ "sraq.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ {0x7c000732, "srea", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601},
+ {0x7c000733,
+ "srea.",
+ {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}},
+ CPU601},
+
+ /* Added from the POWER 601 book */
+ {0x7c000426, "clcs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601},
+
+ /* Added from the POWER 603 book.
+ * These are really 603 specific instructions but we mark them as OPTIONAL
+ * so that the -force_cpusubtype_ALL flag as to be used. This makes it so
+ * only 601 instructions will cause the cputype to be set to other an ALL.
+ */
+ {0x7c0007a4, "tlbld", {{11, 5, GREG}}, OPTIONAL},
+ {0x7c0007e4, "tlbli", {{11, 5, GREG}}, OPTIONAL},
+
+ /* VMX Instructions */
+ {0x7c00000e, "lvebx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c00004e, "lvehx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c00008e, "lvewx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c0000ce, "lvx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c0002ce, "lvxl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+
+ {0x7c00010e, "stvebx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c00014e, "stvehx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c00018e, "stvewx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c0001ce, "stvx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c0003ce, "stvxl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+
+ {0x7c00000c, "lvsl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+ {0x7c00004c, "lvsr", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX},
+
+ {0x10000644, "mtvscr", {{11, 5, VREG}}, VMX},
+ {0x10000604, "mfvscr", {{21, 5, VREG}}, VMX},
+
+ {0x7c0002ac, "dst", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX},
+ {0x7e0002ac, "dstt", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX},
+ {0x7c0002ec, "dstst", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX},
+ {0x7e0002ec, "dststt", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX},
+ {0x7c00066c, "dss", {{21, 2, NUM}}, VMX},
+ {0x7e00066c, "dssall", {{0}}, VMX},
+
+ {0x10000000, "vaddubm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000200, "vaddubs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000300, "vaddsbs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000040, "vadduhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000240, "vadduhs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000340, "vaddshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000080, "vadduwm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000280, "vadduws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000380, "vaddsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000000a, "vaddfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000180, "vaddcuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000400, "vsububm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000600, "vsububs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000700, "vsubsbs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000440, "vsubuhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000640, "vsubuhs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000740, "vsubshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000480, "vsubuwm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000680, "vsubuws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000780, "vsubsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000004a, "vsubfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000580, "vsubcuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000008, "vmuloub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000108, "vmulosb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000048, "vmulouh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000148, "vmulosh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000208, "vmuleub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000308, "vmulesb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000248, "vmuleuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000348, "vmulesh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000020,
+ "vmhaddshs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000021,
+ "vmhraddshs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000022,
+ "vmladduhm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x1000002e,
+ "vmaddfp",
+ {{21, 5, VREG}, {16, 5, VREG}, {6, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x10000024,
+ "vmsumubm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000025,
+ "vmsummbm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000026,
+ "vmsumuhm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000027,
+ "vmsumuhs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000028,
+ "vmsumshm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+ {0x10000029,
+ "vmsumshs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+
+ {0x10000788, "vsumsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000688,
+ "vsum2sws",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x10000608,
+ "vsum4ubs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000708,
+ "vsum4sbs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000648,
+ "vsum4shs",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x10000402, "vavgub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000442, "vavguh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000482, "vavguw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000502, "vavgsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000542, "vavgsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000582, "vavgsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000404, "vand", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000484, "vor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100004c4, "vxor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000444, "vandc", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000504, "vnor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000004, "vrlb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000044, "vrlh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000084, "vrlw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000104, "vslb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000144, "vslh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000184, "vslw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100001c4, "vsl", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000204, "vsrb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000304, "vsrab", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000244, "vsrh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000344, "vsrah", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000284, "vsrw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000384, "vsraw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100002c4, "vsr", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000206,
+ "vcmpgtub",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000606,
+ "vcmpgtub.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000306,
+ "vcmpgtsb",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000706,
+ "vcmpgtsb.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000246,
+ "vcmpgtuh",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000646,
+ "vcmpgtuh.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000346,
+ "vcmpgtsh",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000746,
+ "vcmpgtsh.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000286,
+ "vcmpgtuw",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000686,
+ "vcmpgtuw.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000386,
+ "vcmpgtsw",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000786,
+ "vcmpgtsw.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x100002c6,
+ "vcmpgtfp",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x100006c6,
+ "vcmpgtfp.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x10000006,
+ "vcmpequb",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000406,
+ "vcmpequb.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000046,
+ "vcmpequh",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000446,
+ "vcmpequh.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000086,
+ "vcmpequw",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x10000486,
+ "vcmpequw.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x100000c6,
+ "vcmpeqfp",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x100004c6,
+ "vcmpeqfp.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x100001c6,
+ "vcmpgefp",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+ {0x100005c6,
+ "vcmpgefp.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x100003c6, "vcmpbfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100007c6,
+ "vcmpbfp.",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x1000002a,
+ "vsel",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+
+ {0x1000000e, "vpkuhum", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000008e, "vpkuhus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000010e, "vpkshus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000018e, "vpkshss", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000004e, "vpkuwum", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100000ce, "vpkuwus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000014e, "vpkswus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100001ce, "vpkswss", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000030e, "vpkpx", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000020e, "vupkhsb", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000024e, "vupkhsh", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000034e, "vupkhpx", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000028e, "vupklsb", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100002ce, "vupklsh", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100003ce, "vupklpx", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000000c, "vmrghb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000004c, "vmrghh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000008c, "vmrghw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000010c, "vmrglb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000014c, "vmrglh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000018c, "vmrglw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000020c, "vspltb", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+ {0x1000024c, "vsplth", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+ {0x1000028c, "vspltw", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+
+ {0x1000030c, "vspltisb", {{21, 5, VREG}, {16, 5, SNUM}}, VMX},
+ {0x1000034c, "vspltish", {{21, 5, VREG}, {16, 5, SNUM}}, VMX},
+ {0x1000038c, "vspltisw", {{21, 5, VREG}, {16, 5, SNUM}}, VMX},
+
+ {0x1000002b,
+ "vperm",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}},
+ VMX},
+
+ {0x1000002c,
+ "vsldoi",
+ {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 4, NUM}},
+ VMX},
+
+ {0x1000040c, "vslo", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000044c, "vsro", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000002, "vmaxub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000102, "vmaxsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000042, "vmaxuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000142, "vmaxsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000082, "vmaxuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000182, "vmaxsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000040a, "vmaxfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x10000202, "vminub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000302, "vminsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000242, "vminuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000342, "vminsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000282, "vminuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x10000382, "vminsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000044a, "vminfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000010a, "vrefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000014a, "vrsqrtefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100001ca, "vlogefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000018a, "vexptefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000002f,
+ "vnmsubfp",
+ {{21, 5, VREG}, {16, 5, VREG}, {6, 5, VREG}, {11, 5, VREG}},
+ VMX},
+
+ {0x1000020a, "vrfin", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000024a, "vrfiz", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x1000028a, "vrfip", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+ {0x100002ca, "vrfim", {{21, 5, VREG}, {11, 5, VREG}}, VMX},
+
+ {0x1000038a, "vctuxs", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+ {0x100003ca, "vctsxs", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+
+ {0x1000030a, "vcfux", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+ {0x1000034a, "vcfsx", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX},
+
+ {0, ""} /* end of table marker */
+};
+
+#define kAsmFloatZeroRegister 0
+#define kAsmZeroRegister 0
+
+#define kAsmRegisterPrefix "r"
+#define kAsmRegisterLimit 31
+#define kAsmPcRegister 17
+#define kAsmCrRegister 18
+#define kAsmSpRegister 5
+
+/* return address register */
+#define kAsmRetRegister 19
diff --git a/dev/LibCompiler/Defines.h b/dev/LibCompiler/Defines.h
new file mode 100644
index 0000000..ceb6c45
--- /dev/null
+++ b/dev/LibCompiler/Defines.h
@@ -0,0 +1,172 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#ifndef __TOOLCHAINKIT_DEFINES_H__
+#define __TOOLCHAINKIT_DEFINES_H__
+
+#ifndef Yes
+#define Yes true
+#endif // ifndef Yes
+
+#ifndef No
+#define No false
+#endif // ifndef No
+
+#ifndef YES
+#define YES true
+#endif // ifndef YES
+
+#ifndef NO
+#define NO false
+#endif // ifndef NO
+
+#define SizeType size_t
+
+#define VoidPtr void*
+#define voidPtr VoidPtr
+
+#define UIntPtr uintptr_t
+
+#define Int64 int64_t
+#define UInt64 uint64_t
+
+#define Int32 int
+#define UInt32 unsigned
+
+#define Bool bool
+
+#define Int16 int16_t
+#define UInt16 uint16_t
+
+#define Int8 int8_t
+#define UInt8 uint8_t
+
+#define CharType char
+#define Boolean bool
+
+#include <filesystem>
+#include <cstdint>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <utility>
+#include <cctype>
+#include <cstdio>
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+#include <vector>
+#include <new>
+
+#define nullPtr std::nullptr_t
+
+#define MUST_PASS(E) assert(E)
+
+#ifndef __FORCE_STRLEN
+#define __FORCE_STRLEN 1
+
+#define string_length(len) strlen(len)
+#endif
+
+#ifndef __FORCE_MEMCPY
+#define __FORCE_MEMCPY 1
+
+#define rt_copy_memory(dst, src, len) memcpy(dst, src, len)
+#endif
+
+#define TOOLCHAINKIT_COPY_DELETE(KLASS) \
+ KLASS& operator=(const KLASS&) = delete; \
+ KLASS(const KLASS&) = delete;
+
+#define TOOLCHAINKIT_COPY_DEFAULT(KLASS) \
+ KLASS& operator=(const KLASS&) = default; \
+ KLASS(const KLASS&) = default;
+
+#define TOOLCHAINKIT_MOVE_DELETE(KLASS) \
+ KLASS& operator=(KLASS&&) = delete; \
+ KLASS(KLASS&&) = delete;
+
+#define TOOLCHAINKIT_MOVE_DEFAULT(KLASS) \
+ KLASS& operator=(KLASS&&) = default; \
+ KLASS(KLASS&&) = default;
+
+#define TK_IMPORT_C extern "C"
+#define TK_IMPORT extern
+
+#include <ctime>
+#include <fstream>
+#include <string>
+#include <vector>
+
+namespace LibCompiler
+{
+ inline constexpr int kBaseYear = 1900;
+
+ typedef std::string String;
+
+ inline String current_date() noexcept
+ {
+ auto time_data = time(nullptr);
+ auto time_struct = gmtime(&time_data);
+
+ String fmt = std::to_string(kBaseYear + time_struct->tm_year);
+
+ fmt += "-";
+ fmt += std::to_string(time_struct->tm_mon + 1);
+ fmt += "-";
+ fmt += std::to_string(time_struct->tm_mday);
+
+ return fmt;
+ }
+
+ inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept
+ {
+ if (limit == 0)
+ return false;
+
+ Int32 copy_limit = limit;
+ Int32 cnt = 0;
+ Int32 ret = base;
+
+ while (limit != 1)
+ {
+ ret = ret % 10;
+ str[cnt] = ret;
+
+ ++cnt;
+ --limit;
+ --ret;
+ }
+
+ str[copy_limit] = '\0';
+ return true;
+ }
+
+ using String = std::basic_string<CharType>;
+} // namespace LibCompiler
+
+#define PACKED __attribute__((packed))
+
+typedef char char_type;
+
+#define kObjectFileExt ".obj"
+#define kBinaryFileExt ".bin"
+
+#define kAsmFileExts \
+ { \
+ ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" \
+ }
+
+#define kAsmFileExtsMax 7
+
+#define TOOLCHAINKIT_MODULE(name) extern "C" int name(int argc, char** argv)
+
+#ifdef MSVC
+#pragma scalar_storage_order big - endian
+#endif // ifdef MSVC
+
+#endif /* ifndef __TOOLCHAINKIT_DEFINES_H__ */
diff --git a/dev/LibCompiler/Macros.h b/dev/LibCompiler/Macros.h
new file mode 100644
index 0000000..91ad8de
--- /dev/null
+++ b/dev/LibCompiler/Macros.h
@@ -0,0 +1,33 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+/// @brief provide support for Macros.hpp header.
+
+#ifndef _MACROS_H_
+#define _MACROS_H_
+
+#define TOOLCHAINKIT_COPY_DELETE(KLASS) \
+ KLASS& operator=(const KLASS&) = delete; \
+ KLASS(const KLASS&) = delete;
+
+#define TOOLCHAINKIT_COPY_DEFAULT(KLASS) \
+ KLASS& operator=(const KLASS&) = default; \
+ KLASS(const KLASS&) = default;
+
+#define TOOLCHAINKIT_MOVE_DELETE(KLASS) \
+ KLASS& operator=(KLASS&&) = delete; \
+ KLASS(KLASS&&) = delete;
+
+#define TOOLCHAINKIT_MOVE_DEFAULT(KLASS) \
+ KLASS& operator=(KLASS&&) = default; \
+ KLASS(KLASS&&) = default;
+
+/// @note xxxx is the error placeholder, in hexadecimal.
+#define TOOLCHAINKIT_ERROR_PREFIX_CXX "CXXxxxx"
+#define TOOLCHAINKIT_ERROR_PREFIX_CL "CLxxxx"
+#define TOOLCHAINKIT_ERROR_PREFIX_ASM "ASMxxxx"
+
+#endif /* ifndef _MACROS_H_ */
diff --git a/dev/LibCompiler/NFC/AE.h b/dev/LibCompiler/NFC/AE.h
new file mode 100644
index 0000000..962a7c3
--- /dev/null
+++ b/dev/LibCompiler/NFC/AE.h
@@ -0,0 +1,143 @@
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+#define kAEMag0 'A'
+#define kAEMag1 'E'
+
+#define kAESymbolLen (255)
+#define kAEPad (8)
+#define kAEMagLen (2)
+#define kAENullType (0x00)
+
+// Advanced Executable File Format for MetroLink.
+// Reloctable by offset is the default strategy.
+// You can also relocate at runtime but that's up to the operating system
+// loader.
+
+namespace LibCompiler
+{
+ // @brief Advanced Executable Header
+ // One thing to keep in mind.
+ // This object format, is reloctable.
+ typedef struct AEHeader final
+ {
+ CharType fMagic[kAEMagLen];
+ CharType fArch;
+ CharType fSubArch;
+ SizeType fCount;
+ CharType fSize;
+ SizeType fStartCode;
+ SizeType fCodeSize;
+ CharType fPad[kAEPad];
+ } PACKED AEHeader, *AEHeaderPtr;
+
+ // @brief Advanced Executable Record.
+ // Could be data, code or bss.
+ // fKind must be filled with PEF fields.
+
+ typedef struct AERecordHeader final
+ {
+ CharType fName[kAESymbolLen];
+ SizeType fKind;
+ SizeType fSize;
+ SizeType fFlags;
+ UIntPtr fOffset;
+ CharType fPad[kAEPad];
+ } PACKED AERecordHeader, *AERecordHeaderPtr;
+
+ enum
+ {
+ kKindRelocationByOffset = 0x23f,
+ kKindRelocationAtRuntime = 0x34f,
+ };
+} // namespace LibCompiler
+
+// provide operator<< for AE
+
+inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::AEHeader& container)
+{
+ fp.write((char*)&container, sizeof(LibCompiler::AEHeader));
+
+ return fp;
+}
+
+inline std::ofstream& operator<<(std::ofstream& fp,
+ LibCompiler::AERecordHeader& container)
+{
+ fp.write((char*)&container, sizeof(LibCompiler::AERecordHeader));
+
+ return fp;
+}
+
+inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::AEHeader& container)
+{
+ fp.read((char*)&container, sizeof(LibCompiler::AEHeader));
+ return fp;
+}
+
+inline std::ifstream& operator>>(std::ifstream& fp,
+ LibCompiler::AERecordHeader& container)
+{
+ fp.read((char*)&container, sizeof(LibCompiler::AERecordHeader));
+ return fp;
+}
+
+namespace LibCompiler::Utils
+{
+ /**
+ * @brief AE Reader protocol
+ *
+ */
+ class AEReadableProtocol final
+ {
+ public:
+ std::ifstream FP;
+
+ public:
+ explicit AEReadableProtocol() = default;
+ ~AEReadableProtocol() = default;
+
+ TOOLCHAINKIT_COPY_DELETE(AEReadableProtocol);
+
+ /**
+ * @brief Read AE Record headers.
+ *
+ * @param raw the containing buffer
+ * @param sz it's size (1 = one AERecordHeader, 2 two AERecordHeader(s))
+ * @return AERecordHeaderPtr
+ */
+ AERecordHeaderPtr Read(char* raw, std::size_t sz)
+ {
+ if (!raw)
+ return nullptr;
+
+ return this->_Read<AERecordHeader>(raw, sz * sizeof(AERecordHeader));
+ }
+
+ private:
+ /**
+ * @brief Implementation of Read for raw classes.
+ *
+ * @tparam TypeClass The class to read.
+ * @param raw the buffer
+ * @param sz the size
+ * @return TypeClass* the returning class.
+ */
+ template <typename TypeClass>
+ TypeClass* _Read(char* raw, std::size_t sz)
+ {
+ FP.read(raw, std::streamsize(sz));
+ return reinterpret_cast<TypeClass*>(raw);
+ }
+ };
+} // namespace LibCompiler::Utils
diff --git a/dev/LibCompiler/NFC/ErrorID.h b/dev/LibCompiler/NFC/ErrorID.h
new file mode 100644
index 0000000..e41410e
--- /dev/null
+++ b/dev/LibCompiler/NFC/ErrorID.h
@@ -0,0 +1,22 @@
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+#include <LibCompiler/NFC/ErrorOr.h>
+
+#define TOOLCHAINKIT_EXEC_ERROR -30
+#define TOOLCHAINKIT_FILE_NOT_FOUND -31
+#define TOOLCHAINKIT_DIR_NOT_FOUND -32
+#define TOOLCHAINKIT_FILE_EXISTS -33
+#define TOOLCHAINKIT_TOO_LONG -34
+#define TOOLCHAINKIT_INVALID_DATA -35
+#define TOOLCHAINKIT_UNIMPLEMENTED -36
+#define TOOLCHAINKIT_FAT_ERROR -37
diff --git a/dev/LibCompiler/NFC/ErrorOr.h b/dev/LibCompiler/NFC/ErrorOr.h
new file mode 100644
index 0000000..18bac3f
--- /dev/null
+++ b/dev/LibCompiler/NFC/ErrorOr.h
@@ -0,0 +1,61 @@
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+#include <LibCompiler/NFC/Ref.h>
+
+namespace LibCompiler
+{
+ using ErrorT = UInt32;
+
+ template <typename T>
+ class ErrorOr final
+ {
+ public:
+ ErrorOr() = default;
+ ~ErrorOr() = default;
+
+ public:
+ explicit ErrorOr(Int32 err)
+ : mId(err)
+ {
+ }
+
+ explicit ErrorOr(nullPtr Null)
+ {
+ }
+
+ explicit ErrorOr(T Class)
+ : mRef(Class)
+ {
+ }
+
+ ErrorOr& operator=(const ErrorOr&) = default;
+ ErrorOr(const ErrorOr&) = default;
+
+ Ref<T> Leak()
+ {
+ return mRef;
+ }
+
+ operator bool()
+ {
+ return mRef;
+ }
+
+ private:
+ Ref<T> mRef;
+ Int32 mId{0};
+ };
+
+ using ErrorOrAny = ErrorOr<voidPtr>;
+
+} // namespace LibCompiler
diff --git a/dev/LibCompiler/NFC/PEF.h b/dev/LibCompiler/NFC/PEF.h
new file mode 100644
index 0000000..aec3c64
--- /dev/null
+++ b/dev/LibCompiler/NFC/PEF.h
@@ -0,0 +1,144 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+// @file PEF.hpp
+// @brief Preferred Executable Format
+
+#define kPefMagic "Joy!"
+#define kPefMagicFat "yoJ!"
+
+#define kPefExt ".o"
+#define kPefDylibExt ".dylib"
+#define kPefLibExt ".lib"
+#define kPefObjectExt ".obj"
+#define kPefDebugExt ".dbg"
+#define kPefDriverExt ".sys"
+
+#define kPefZero128 ".zero128"
+#define kPefCode128 ".code128"
+#define kPefData128 ".data128"
+
+#define kPefZero64 ".zero64"
+#define kPefCode64 ".code64"
+#define kPefData64 ".data64"
+
+#define kPefMagicLen (5)
+
+#define kPefVersion (3)
+#define kPefNameLen (255)
+
+#define kPefBaseOrigin (0x40000000)
+
+#define kPefStart "__ImageStart"
+
+namespace LibCompiler
+{
+ enum
+ {
+ kPefArchStart = 99,
+ kPefArchIntel86S = 100,
+ kPefArchAMD64,
+ kPefArchRISCV,
+ kPefArch64000, /* 64x0 RISC architecture. */
+ kPefArch32000,
+ kPefArchPowerPC, /* 64-bit POWER architecture. */
+ kPefArchARM64,
+ kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1,
+ kPefArchInvalid = 0xFF,
+ };
+
+ enum
+ {
+ kPefSubArchAMD,
+ kPefSubArchIntel,
+ kPefSubArchARM,
+ kPefSubArchGeneric,
+ kPefSubArchIBM,
+ };
+
+ enum
+ {
+ kPefKindExec = 1, /* .o */
+ kPefKindDylib = 2, /* .dylib */
+ kPefKindObject = 4, /* .obj */
+ kPefKindDebug = 5, /* .dbg */
+ kPefKindDriver = 6,
+ kPefKindCount,
+ };
+
+ /* PEF container */
+ typedef struct PEFContainer final
+ {
+ CharType Magic[kPefMagicLen];
+ UInt32 Linker;
+ UInt32 Version;
+ UInt32 Kind;
+ UInt32 Abi;
+ UInt32 Cpu;
+ UInt32 SubCpu; /* Cpu specific information */
+ UIntPtr Start; /* Origin of code */
+ SizeType HdrSz; /* Size of header */
+ SizeType Count; /* container header count */
+ } PACKED PEFContainer;
+
+ /* First PEFCommandHeader starts after PEFContainer */
+ /* Last container is __exec_end */
+
+ /* PEF executable section and commands. */
+
+ typedef struct PEFCommandHeader final
+ {
+ CharType Name[kPefNameLen]; /* container name */
+ UInt32 Cpu; /* container cpu */
+ UInt32 SubCpu; /* container sub-cpu */
+ UInt32 Flags; /* container flags */
+ UInt16 Kind; /* container kind */
+ UIntPtr Offset; /* file offset */
+ SizeType Size; /* file size */
+ } PACKED PEFCommandHeader;
+
+ enum
+ {
+ kPefCode = 0xC,
+ kPefData = 0xD,
+ kPefZero = 0xE,
+ kPefLinkerID = 0x1,
+ kPefCount = 4,
+ kPefInvalid = 0xFF,
+ };
+} // namespace LibCompiler
+
+inline std::ofstream& operator<<(std::ofstream& fp,
+ LibCompiler::PEFContainer& container)
+{
+ fp.write((char*)&container, sizeof(LibCompiler::PEFContainer));
+ return fp;
+}
+
+inline std::ofstream& operator<<(std::ofstream& fp,
+ LibCompiler::PEFCommandHeader& container)
+{
+ fp.write((char*)&container, sizeof(LibCompiler::PEFCommandHeader));
+ return fp;
+}
+
+inline std::ifstream& operator>>(std::ifstream& fp,
+ LibCompiler::PEFContainer& container)
+{
+ fp.read((char*)&container, sizeof(LibCompiler::PEFContainer));
+ return fp;
+}
+
+inline std::ifstream& operator>>(std::ifstream& fp,
+ LibCompiler::PEFCommandHeader& container)
+{
+ fp.read((char*)&container, sizeof(LibCompiler::PEFCommandHeader));
+ return fp;
+}
diff --git a/dev/LibCompiler/NFC/Ref.h b/dev/LibCompiler/NFC/Ref.h
new file mode 100644
index 0000000..f76f676
--- /dev/null
+++ b/dev/LibCompiler/NFC/Ref.h
@@ -0,0 +1,103 @@
+
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+
+namespace LibCompiler
+{
+ // @author EL Mahrouss Amlal
+ // @brief Reference holder class, refers to a pointer of data in static memory.
+ template <typename T>
+ class Ref final
+ {
+ public:
+ explicit Ref() = default;
+
+ ~Ref()
+ {
+ if (m_Strong)
+ {
+ (*m_Class).~T();
+ }
+ }
+
+ TOOLCHAINKIT_COPY_DEFAULT(Ref);
+
+ public:
+ explicit Ref(T cls, const Bool& strong = false)
+ : m_Class(&cls), m_Strong(strong)
+ {
+ }
+
+ Ref& operator=(T ref)
+ {
+ *m_Class = ref;
+ return *this;
+ }
+
+ public:
+ T* operator->() const
+ {
+ return m_Class;
+ }
+
+ T& Leak()
+ {
+ return *m_Class;
+ }
+
+ T operator*()
+ {
+ return *m_Class;
+ }
+
+ Bool IsStrong() const
+ {
+ return m_Strong;
+ }
+
+ operator bool()
+ {
+ return *m_Class;
+ }
+
+ private:
+ T* m_Class{nullptr};
+ Bool m_Strong{false};
+ };
+
+ // @author EL Mahrouss Amlal
+ // @brief Non null Reference holder class, refers to a pointer of data in static memory.
+ template <typename T>
+ class NonNullRef final
+ {
+ public:
+ explicit NonNullRef() = delete;
+
+ explicit NonNullRef(T* ref)
+ : m_Ref(ref, true)
+ {
+ }
+
+ Ref<T>& operator->()
+ {
+ MUST_PASS(m_Ref);
+ return m_Ref;
+ }
+
+ NonNullRef& operator=(const NonNullRef<T>& ref) = delete;
+ NonNullRef(const NonNullRef<T>& ref) = default;
+
+ private:
+ Ref<T> m_Ref{nullptr};
+ };
+} // namespace LibCompiler
diff --git a/dev/LibCompiler/NFC/String.h b/dev/LibCompiler/NFC/String.h
new file mode 100644
index 0000000..958da8e
--- /dev/null
+++ b/dev/LibCompiler/NFC/String.h
@@ -0,0 +1,90 @@
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#pragma once
+
+#include <LibCompiler/Defines.h>
+#include <LibCompiler/NFC/ErrorOr.h>
+
+namespace LibCompiler
+{
+ /**
+ * @brief StringView class, contains a C string and manages it.
+ * @note No need to manage it it's getting deleted by default.
+ */
+
+ class StringView final
+ {
+ public:
+ explicit StringView() = delete;
+
+ explicit StringView(SizeType Sz) noexcept
+ : m_Sz(Sz)
+ {
+ m_Data = new CharType[Sz];
+ assert(m_Data);
+ }
+
+ ~StringView() noexcept
+ {
+ if (m_Data)
+ {
+ memset(m_Data, 0, m_Sz);
+ delete[] m_Data;
+
+ m_Data = nullptr;
+ }
+ }
+
+ TOOLCHAINKIT_COPY_DEFAULT(StringView);
+
+ CharType* Data();
+ const CharType* CData() const;
+ SizeType Length() const;
+
+ bool operator==(const CharType* rhs) const;
+ bool operator!=(const CharType* rhs) const;
+
+ bool operator==(const StringView& rhs) const;
+ bool operator!=(const StringView& rhs) const;
+
+ StringView& operator+=(const CharType* rhs);
+ StringView& operator+=(const StringView& rhs);
+
+ operator bool()
+ {
+ return m_Data && m_Data[0] != 0;
+ }
+
+ bool operator!()
+ {
+ return !m_Data || m_Data[0] == 0;
+ }
+
+ private:
+ CharType* m_Data{nullptr};
+ SizeType m_Sz{0};
+ SizeType m_Cur{0};
+
+ friend class StringBuilder;
+ };
+
+ /**
+ * @brief StringBuilder class
+ * @note These results shall call delete[] after they're used.
+ */
+ struct StringBuilder final
+ {
+ static StringView Construct(const CharType* data);
+ static const char* FromInt(const char* fmt, int n);
+ static const char* FromBool(const char* fmt, bool n);
+ static const char* Format(const char* fmt, const char* from);
+ static bool Equals(const char* lhs, const char* rhs);
+ };
+} // namespace LibCompiler
diff --git a/dev/LibCompiler/NFC/XCOFF.h b/dev/LibCompiler/NFC/XCOFF.h
new file mode 100644
index 0000000..0594855
--- /dev/null
+++ b/dev/LibCompiler/NFC/XCOFF.h
@@ -0,0 +1,41 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+ File: XCOFF.hpp
+ Purpose: XCOFF for NewOS.
+
+ Revision History:
+
+ 04/07/24: Added file (amlel)
+
+------------------------------------------- */
+
+#ifndef __XCOFF__
+#define __XCOFF__
+
+#include <LibCompiler/Defines.h>
+
+#define kXCOFF64Magic 0x01F7
+
+#define kXCOFFRelFlg 0x0001
+#define kXCOFFExecutable 0x0002
+#define kXCOFFLnno 0x0004
+#define kXCOFFLSyms 0x0008
+
+namespace LibCompiler
+{
+ /// @brief XCoff identification header.
+ typedef struct XCoffFileHeader
+ {
+ UInt16 fMagic;
+ UInt16 fTarget;
+ UInt16 fNumSecs;
+ UInt32 fTimeDat;
+ UIntPtr fSymPtr;
+ UInt32 fNumSyms;
+ UInt16 fOptHdr; // ?: Number of bytes in optional header
+ } XCoffFileHeader;
+} // namespace LibCompiler
+
+#endif // ifndef __XCOFF__
diff --git a/dev/LibCompiler/Parser.h b/dev/LibCompiler/Parser.h
new file mode 100644
index 0000000..35e0c45
--- /dev/null
+++ b/dev/LibCompiler/Parser.h
@@ -0,0 +1,177 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/AAL/AssemblyInterface.h>
+
+namespace LibCompiler
+{
+ inline auto kInvalidFrontend = "NoLang";
+
+ /// @brief Compiler backend, implements a frontend, such as C, C++...
+ /// See Toolchain, for some examples.
+ class ICompilerFrontend
+ {
+ public:
+ explicit ICompilerFrontend() = default;
+ virtual ~ICompilerFrontend() = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(ICompilerFrontend);
+
+ // NOTE: cast this to your user defined ast.
+ typedef void* AstType;
+
+ //! @brief Compile a syntax tree ouf of the text.
+ //! Also takes the source file name for metadata.
+
+ virtual bool Compile(const std::string text, const std::string file) = 0;
+
+ //! @brief What language are we dealing with?
+ virtual const char* Language()
+ {
+ return kInvalidFrontend;
+ }
+
+ virtual bool IsValid()
+ {
+ return strcmp(this->Language(), kInvalidFrontend);
+ }
+ };
+
+ struct SyntaxLeafList;
+ struct SyntaxLeafList;
+ struct CompilerKeyword;
+
+ /// we want to do that because to separate keywords.
+ enum KeywordKind
+ {
+ eKeywordKindNamespace,
+ eKeywordKindFunctionStart,
+ eKeywordKindFunctionEnd,
+ eKeywordKindVariable,
+ eKeywordKindVariablePtr,
+ eKeywordKindType,
+ eKeywordKindTypePtr,
+ eKeywordKindExpressionBegin,
+ eKeywordKindExpressionEnd,
+ eKeywordKindArgSeparator,
+ eKeywordKindBodyStart,
+ eKeywordKindBodyEnd,
+ eKeywordKindClass,
+ eKeywordKindPtrAccess,
+ eKeywordKindAccess,
+ eKeywordKindIf,
+ eKeywordKindElse,
+ eKeywordKindElseIf,
+ eKeywordKindVariableAssign,
+ eKeywordKindVariableDec,
+ eKeywordKindVariableInc,
+ eKeywordKindConstant,
+ eKeywordKindTypedef,
+ eKeywordKindEndInstr,
+ eKeywordKindSpecifier,
+ eKeywordKindInvalid,
+ eKeywordKindReturn,
+ eKeywordKindCommentInline,
+ eKeywordKindCommentMultiLineStart,
+ eKeywordKindCommentMultiLineEnd,
+ eKeywordKindEq,
+ eKeywordKindNotEq,
+ eKeywordKindGreaterEq,
+ eKeywordKindLessEq,
+ eKeywordKindPtr,
+ };
+
+ /// \brief Compiler keyword information struct.
+ struct CompilerKeyword
+ {
+ std::string keyword_name;
+ KeywordKind keyword_kind = eKeywordKindInvalid;
+ };
+ struct SyntaxLeafList final
+ {
+ struct SyntaxLeaf final
+ {
+ Int32 fUserType;
+#ifdef TK_USE_STRUCTS
+ CompilerKeyword fUserData;
+#else
+ std::string fUserData;
+#endif
+
+ std::string fUserValue;
+ struct SyntaxLeaf* fNext;
+ };
+
+ std::vector<SyntaxLeaf> fLeafList;
+ SizeType fNumLeafs;
+
+ size_t SizeOf()
+ {
+ return fNumLeafs;
+ }
+ std::vector<SyntaxLeaf>& Get()
+ {
+ return fLeafList;
+ }
+ SyntaxLeaf& At(size_t index)
+ {
+ return fLeafList[index];
+ }
+ };
+
+ /// find the perfect matching word in a haystack.
+ /// \param haystack base string
+ /// \param needle the string we search for.
+ /// \return if we found it or not.
+ inline bool find_word(const std::string& haystack,
+ const std::string& needle) noexcept
+ {
+ auto index = haystack.find(needle);
+
+ // check for needle validity.
+ if (index == std::string::npos)
+ return false;
+
+ // declare lambda
+ auto not_part_of_word = [&](int index) {
+ if (std::isspace(haystack[index]) || std::ispunct(haystack[index]))
+ return true;
+
+ if (index <= 0 || index >= haystack.size())
+ return true;
+
+ return false;
+ };
+
+ return not_part_of_word(index - 1) && not_part_of_word(index + needle.size());
+ }
+
+ /// find a word within strict conditions and returns a range of it.
+ /// \param haystack
+ /// \param needle
+ /// \return position of needle.
+ inline std::size_t find_word_range(const std::string& haystack,
+ const std::string& needle) noexcept
+ {
+ auto index = haystack.find(needle);
+
+ // check for needle validity.
+ if (index == std::string::npos)
+ return false;
+
+ if (!isalnum((haystack[index + needle.size() + 1])) &&
+ !isdigit(haystack[index + needle.size() + 1]) &&
+ !isalnum((haystack[index - needle.size() - 1])) &&
+ !isdigit(haystack[index - needle.size() - 1]))
+ {
+ return index;
+ }
+
+ return false;
+ }
+} // namespace LibCompiler
diff --git a/dev/LibCompiler/ReadMe.md b/dev/LibCompiler/ReadMe.md
new file mode 100644
index 0000000..4bc01b8
--- /dev/null
+++ b/dev/LibCompiler/ReadMe.md
@@ -0,0 +1,7 @@
+# NDK Compiler DLL.
+
+## Compiler, Assembler and Linker DLL.
+
+This contains a set of tools necessary to compile a ZKA program.
+
+###### Copyright (C) 2024 Theater Quality Inc, all rights reserved.
diff --git a/dev/LibCompiler/UUID.h b/dev/LibCompiler/UUID.h
new file mode 100644
index 0000000..74584b4
--- /dev/null
+++ b/dev/LibCompiler/UUID.h
@@ -0,0 +1,983 @@
+#ifndef STDUUID_H
+#define STDUUID_H
+
+#include <array>
+#include <atomic>
+#include <chrono>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+#include <iterator>
+#include <memory>
+#include <numeric>
+#include <optional>
+#include <random>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <type_traits>
+
+#ifdef __cplusplus
+
+#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+#define LIBUUID_CPP20_OR_GREATER
+#endif
+
+#endif
+
+#ifdef LIBUUID_CPP20_OR_GREATER
+#include <span>
+#else
+#include <gsl/span>
+#endif
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef UUID_SYSTEM_GENERATOR
+#include <objbase.h>
+#endif
+
+#ifdef UUID_TIME_GENERATOR
+#include <iphlpapi.h>
+#pragma comment(lib, "IPHLPAPI.lib")
+#endif
+
+#elif defined(__linux__) || defined(__unix__)
+
+#ifdef UUID_SYSTEM_GENERATOR
+#include <uuid/uuid.h>
+#endif
+
+#elif defined(__APPLE__)
+
+#ifdef UUID_SYSTEM_GENERATOR
+#include <CoreFoundation/CFUUID.h>
+#endif
+
+#endif
+
+namespace uuids
+{
+#ifdef __cpp_lib_span
+ template <class ElementType, std::size_t Extent>
+ using span = std::span<ElementType, Extent>;
+#else
+ template <class ElementType, std::ptrdiff_t Extent>
+ using span = gsl::span<ElementType, Extent>;
+#endif
+
+ namespace Details
+ {
+ template <typename TChar>
+ [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
+ {
+ if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
+ return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
+ if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
+ return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a'));
+ if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
+ return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
+ return 0;
+ }
+
+ template <typename TChar>
+ [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
+ {
+ return (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
+ (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) ||
+ (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'));
+ }
+
+ template <typename TChar>
+ [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(
+ TChar const* str) noexcept
+ {
+ if (str)
+ return str;
+ return {};
+ }
+
+ template <typename StringType>
+ [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type,
+ typename StringType::traits_type>
+ to_string_view(StringType const& str) noexcept
+ {
+ return str;
+ }
+
+ class sha1
+ {
+ public:
+ using digest32_t = uint32_t[5];
+ using digest8_t = uint8_t[20];
+
+ static constexpr unsigned int block_bytes = 64;
+
+ [[nodiscard]] inline static uint32_t left_rotate(
+ uint32_t value, size_t const count) noexcept
+ {
+ return (value << count) ^ (value >> (32 - count));
+ }
+
+ sha1()
+ {
+ reset();
+ }
+
+ void reset() noexcept
+ {
+ m_digest[0] = 0x67452301;
+ m_digest[1] = 0xEFCDAB89;
+ m_digest[2] = 0x98BADCFE;
+ m_digest[3] = 0x10325476;
+ m_digest[4] = 0xC3D2E1F0;
+ m_blockByteIndex = 0;
+ m_byteCount = 0;
+ }
+
+ void process_byte(uint8_t octet)
+ {
+ this->m_block[this->m_blockByteIndex++] = octet;
+ ++this->m_byteCount;
+ if (m_blockByteIndex == block_bytes)
+ {
+ this->m_blockByteIndex = 0;
+ process_block();
+ }
+ }
+
+ void process_block(void const* const start, void const* const end)
+ {
+ const uint8_t* begin = static_cast<const uint8_t*>(start);
+ const uint8_t* finish = static_cast<const uint8_t*>(end);
+ while (begin != finish)
+ {
+ process_byte(*begin);
+ begin++;
+ }
+ }
+
+ void process_bytes(void const* const data, size_t const len)
+ {
+ const uint8_t* block = static_cast<const uint8_t*>(data);
+ process_block(block, block + len);
+ }
+
+ uint32_t const* get_digest(digest32_t digest)
+ {
+ size_t const bitCount = this->m_byteCount * 8;
+ process_byte(0x80);
+ if (this->m_blockByteIndex > 56)
+ {
+ while (m_blockByteIndex != 0)
+ {
+ process_byte(0);
+ }
+ while (m_blockByteIndex < 56)
+ {
+ process_byte(0);
+ }
+ }
+ else
+ {
+ while (m_blockByteIndex < 56)
+ {
+ process_byte(0);
+ }
+ }
+ process_byte(0);
+ process_byte(0);
+ process_byte(0);
+ process_byte(0);
+ process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
+ process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
+ process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
+ process_byte(static_cast<unsigned char>((bitCount)&0xFF));
+
+ memcpy(digest, m_digest, 5 * sizeof(uint32_t));
+ return digest;
+ }
+
+ uint8_t const* get_digest_bytes(digest8_t digest)
+ {
+ digest32_t d32;
+ get_digest(d32);
+ size_t di = 0;
+ digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
+ digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
+ digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
+ digest[di++] = static_cast<uint8_t>(d32[0] >> 0);
+
+ digest[di++] = static_cast<uint8_t>(d32[1] >> 24);
+ digest[di++] = static_cast<uint8_t>(d32[1] >> 16);
+ digest[di++] = static_cast<uint8_t>(d32[1] >> 8);
+ digest[di++] = static_cast<uint8_t>(d32[1] >> 0);
+
+ digest[di++] = static_cast<uint8_t>(d32[2] >> 24);
+ digest[di++] = static_cast<uint8_t>(d32[2] >> 16);
+ digest[di++] = static_cast<uint8_t>(d32[2] >> 8);
+ digest[di++] = static_cast<uint8_t>(d32[2] >> 0);
+
+ digest[di++] = static_cast<uint8_t>(d32[3] >> 24);
+ digest[di++] = static_cast<uint8_t>(d32[3] >> 16);
+ digest[di++] = static_cast<uint8_t>(d32[3] >> 8);
+ digest[di++] = static_cast<uint8_t>(d32[3] >> 0);
+
+ digest[di++] = static_cast<uint8_t>(d32[4] >> 24);
+ digest[di++] = static_cast<uint8_t>(d32[4] >> 16);
+ digest[di++] = static_cast<uint8_t>(d32[4] >> 8);
+ digest[di++] = static_cast<uint8_t>(d32[4] >> 0);
+
+ return digest;
+ }
+
+ private:
+ void process_block()
+ {
+ uint32_t w[80];
+ for (size_t i = 0; i < 16; i++)
+ {
+ w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
+ w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
+ w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
+ w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]);
+ }
+ for (size_t i = 16; i < 80; i++)
+ {
+ w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
+ }
+
+ uint32_t a = m_digest[0];
+ uint32_t b = m_digest[1];
+ uint32_t c = m_digest[2];
+ uint32_t d = m_digest[3];
+ uint32_t e = m_digest[4];
+
+ for (std::size_t i = 0; i < 80; ++i)
+ {
+ uint32_t f = 0;
+ uint32_t k = 0;
+
+ if (i < 20)
+ {
+ f = (b & c) | (~b & d);
+ k = 0x5A827999;
+ }
+ else if (i < 40)
+ {
+ f = b ^ c ^ d;
+ k = 0x6ED9EBA1;
+ }
+ else if (i < 60)
+ {
+ f = (b & c) | (b & d) | (c & d);
+ k = 0x8F1BBCDC;
+ }
+ else
+ {
+ f = b ^ c ^ d;
+ k = 0xCA62C1D6;
+ }
+ uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
+ e = d;
+ d = c;
+ c = left_rotate(b, 30);
+ b = a;
+ a = temp;
+ }
+
+ m_digest[0] += a;
+ m_digest[1] += b;
+ m_digest[2] += c;
+ m_digest[3] += d;
+ m_digest[4] += e;
+ }
+
+ private:
+ digest32_t m_digest;
+ uint8_t m_block[64];
+ size_t m_blockByteIndex;
+ size_t m_byteCount;
+ };
+
+ template <typename CharT>
+ inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
+
+ template <>
+ inline constexpr wchar_t empty_guid<wchar_t>[37] =
+ L"00000000-0000-0000-0000-000000000000";
+
+ template <typename CharT>
+ inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
+
+ template <>
+ inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
+ } // namespace Details
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // UUID format https://tools.ietf.org/html/rfc4122
+ // --------------------------------------------------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // Field NDR Data Type Octet # Note
+ // --------------------------------------------------------------------------------------------------------------------------
+ // time_low unsigned long 0 - 3 The low field
+ // of the timestamp. time_mid unsigned short 4 - 5
+ // The middle field of the timestamp. time_hi_and_version unsigned
+ // short 6 - 7 The high field of the timestamp multiplexed
+ // with the version number. clock_seq_hi_and_reserved unsigned small 8
+ // The high field of the clock sequence multiplexed with the variant.
+ // clock_seq_low unsigned small 9 The low
+ // field of the clock sequence. node character 10
+ // - 15 The spatially unique node identifier.
+ // --------------------------------------------------------------------------------------------------------------------------
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | time_low |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | time_mid | time_hi_and_version |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // |clk_seq_hi_res | clk_seq_low | node (0-1) |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | node (2-5) |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // enumerations
+ // --------------------------------------------------------------------------------------------------------------------------
+
+ // indicated by a bit pattern in octet 8, marked with N in
+ // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
+ enum class uuid_variant
+ {
+ // NCS backward compatibility (with the obsolete Apollo Network Computing
+ // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the
+ // UUID are a 48-bit timestamp (the number of 4 microsecond units of time
+ // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet
+ // is the "address family"; > the final 7 octets are a 56-bit host ID in the
+ // form specified by the address family
+ ncs,
+
+ // RFC 4122/DCE 1.1
+ // N bit pattern: 10xx
+ // > big-endian byte order
+ rfc,
+
+ // Microsoft Corporation backward compatibility
+ // N bit pattern: 110x
+ // > little endian byte order
+ // > formely used in the Component Object Model (COM) library
+ microsoft,
+
+ // reserved for possible future definition
+ // N bit pattern: 111x
+ reserved
+ };
+
+ // indicated by a bit pattern in octet 6, marked with M in
+ // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
+ enum class uuid_version
+ {
+ none = 0, // only possible for nil or invalid uuids
+ time_based = 1, // The time-based version specified in RFC 4122
+ dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
+ name_based_md5 =
+ 3, // The name-based version specified in RFS 4122 with MD5 hashing
+ random_number_based = 4, // The randomly or pseudo-randomly generated version
+ // specified in RFS 4122
+ name_based_sha1 =
+ 5 // The name-based version specified in RFS 4122 with SHA1 hashing
+ };
+
+ // Forward declare uuid & to_string so that we can declare to_string as a friend
+ // later.
+ class uuid;
+ template <class CharT = char, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
+ std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // uuid class
+ // --------------------------------------------------------------------------------------------------------------------------
+ class uuid
+ {
+ public:
+ using value_type = uint8_t;
+
+ constexpr uuid() noexcept = default;
+
+ uuid(value_type (&arr)[16]) noexcept
+ {
+ std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
+ }
+
+ constexpr uuid(std::array<value_type, 16> const& arr) noexcept
+ : data{arr}
+ {
+ }
+
+ explicit uuid(span<value_type, 16> bytes)
+ {
+ std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
+ }
+
+ template <typename ForwardIterator>
+ explicit uuid(ForwardIterator first, ForwardIterator last)
+ {
+ if (std::distance(first, last) == 16)
+ std::copy(first, last, std::begin(data));
+ }
+
+ [[nodiscard]] constexpr uuid_variant variant() const noexcept
+ {
+ if ((data[8] & 0x80) == 0x00)
+ return uuid_variant::ncs;
+ else if ((data[8] & 0xC0) == 0x80)
+ return uuid_variant::rfc;
+ else if ((data[8] & 0xE0) == 0xC0)
+ return uuid_variant::microsoft;
+ else
+ return uuid_variant::reserved;
+ }
+
+ [[nodiscard]] constexpr uuid_version version() const noexcept
+ {
+ if ((data[6] & 0xF0) == 0x10)
+ return uuid_version::time_based;
+ else if ((data[6] & 0xF0) == 0x20)
+ return uuid_version::dce_security;
+ else if ((data[6] & 0xF0) == 0x30)
+ return uuid_version::name_based_md5;
+ else if ((data[6] & 0xF0) == 0x40)
+ return uuid_version::random_number_based;
+ else if ((data[6] & 0xF0) == 0x50)
+ return uuid_version::name_based_sha1;
+ else
+ return uuid_version::none;
+ }
+
+ [[nodiscard]] constexpr bool is_nil() const noexcept
+ {
+ for (size_t i = 0; i < data.size(); ++i)
+ if (data[i] != 0)
+ return false;
+ return true;
+ }
+
+ void swap(uuid& other) noexcept
+ {
+ data.swap(other.data);
+ }
+
+ [[nodiscard]] inline span<std::byte const, 16> as_bytes() const
+ {
+ return span<std::byte const, 16>(
+ reinterpret_cast<std::byte const*>(data.data()), 16);
+ }
+
+ template <typename StringType>
+ [[nodiscard]] constexpr static bool is_valid_uuid(
+ StringType const& in_str) noexcept
+ {
+ auto str = Details::to_string_view(in_str);
+ bool firstDigit = true;
+ size_t hasBraces = 0;
+ size_t index = 0;
+
+ if (str.empty())
+ return false;
+
+ if (str.front() == '{')
+ hasBraces = 1;
+ if (hasBraces && str.back() != '}')
+ return false;
+
+ for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
+ {
+ if (str[i] == '-')
+ continue;
+
+ if (index >= 16 || !Details::is_hex(str[i]))
+ {
+ return false;
+ }
+
+ if (firstDigit)
+ {
+ firstDigit = false;
+ }
+ else
+ {
+ index++;
+ firstDigit = true;
+ }
+ }
+
+ if (index < 16)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ template <typename StringType>
+ [[nodiscard]] constexpr static std::optional<uuid> from_string(
+ StringType const& in_str) noexcept
+ {
+ auto str = Details::to_string_view(in_str);
+ bool firstDigit = true;
+ size_t hasBraces = 0;
+ size_t index = 0;
+
+ std::array<uint8_t, 16> data{{0}};
+
+ if (str.empty())
+ return {};
+
+ if (str.front() == '{')
+ hasBraces = 1;
+ if (hasBraces && str.back() != '}')
+ return {};
+
+ for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
+ {
+ if (str[i] == '-')
+ continue;
+
+ if (index >= 16 || !Details::is_hex(str[i]))
+ {
+ return {};
+ }
+
+ if (firstDigit)
+ {
+ data[index] = static_cast<uint8_t>(Details::hex2char(str[i]) << 4);
+ firstDigit = false;
+ }
+ else
+ {
+ data[index] =
+ static_cast<uint8_t>(data[index] | Details::hex2char(str[i]));
+ index++;
+ firstDigit = true;
+ }
+ }
+
+ if (index < 16)
+ {
+ return {};
+ }
+
+ return uuid{data};
+ }
+
+ private:
+ std::array<value_type, 16> data{{0}};
+
+ friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept;
+ friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept;
+
+ template <class Elem, class Traits>
+ friend std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& s, uuid const& id);
+
+ template <class CharT, class Traits, class Allocator>
+ friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
+
+ friend std::hash<uuid>;
+ };
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // operators and non-member functions
+ // --------------------------------------------------------------------------------------------------------------------------
+
+ [[nodiscard]] inline bool operator==(uuid const& lhs,
+ uuid const& rhs) noexcept
+ {
+ return lhs.data == rhs.data;
+ }
+
+ [[nodiscard]] inline bool operator!=(uuid const& lhs,
+ uuid const& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept
+ {
+ return lhs.data < rhs.data;
+ }
+
+ template <class CharT, class Traits, class Allocator>
+ [[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(
+ uuid const& id)
+ {
+ std::basic_string<CharT, Traits, Allocator> uustr{Details::empty_guid<CharT>};
+
+ for (size_t i = 0, index = 0; i < 36; ++i)
+ {
+ if (i == 8 || i == 13 || i == 18 || i == 23)
+ {
+ continue;
+ }
+ uustr[i] = Details::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
+ uustr[++i] = Details::guid_encoder<CharT>[id.data[index] & 0x0f];
+ index++;
+ }
+
+ return uustr;
+ }
+
+ template <class Elem, class Traits>
+ std::basic_ostream<Elem, Traits>& operator<<(
+ std::basic_ostream<Elem, Traits>& s, uuid const& id)
+ {
+ s << to_string(id);
+ return s;
+ }
+
+ inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept
+ {
+ lhs.swap(rhs);
+ }
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // namespace IDs that could be used for generating name-based uuids
+ // --------------------------------------------------------------------------------------------------------------------------
+
+ // Name string is a fully-qualified domain name
+ static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
+ 0xc8}};
+
+ // Name string is a URL
+ static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
+ 0xc8}};
+
+ // Name string is an ISO OID (See https://oidref.com/,
+ // https://en.wikipedia.org/wiki/Object_identifier)
+ static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
+ 0xc8}};
+
+ // Name string is an X.500 DN, in DER or a text output format (See
+ // https://en.wikipedia.org/wiki/X.500,
+ // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One)
+ static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1,
+ 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
+ 0xc8}};
+
+ // --------------------------------------------------------------------------------------------------------------------------
+ // uuid generators
+ // --------------------------------------------------------------------------------------------------------------------------
+
+#ifdef UUID_SYSTEM_GENERATOR
+ class uuid_system_generator
+ {
+ public:
+ using result_type = uuid;
+
+ uuid operator()()
+ {
+#ifdef _WIN32
+
+ GUID newId;
+ HRESULT hr = ::CoCreateGuid(&newId);
+
+ if (FAILED(hr))
+ {
+ throw std::system_error(hr, std::system_category(),
+ "CoCreateGuid failed");
+ }
+
+ std::array<uint8_t, 16> bytes = {
+ {static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
+ static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
+ static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
+ static_cast<unsigned char>((newId.Data1) & 0xFF),
+
+ (unsigned char)((newId.Data2 >> 8) & 0xFF),
+ (unsigned char)((newId.Data2) & 0xFF),
+
+ (unsigned char)((newId.Data3 >> 8) & 0xFF),
+ (unsigned char)((newId.Data3) & 0xFF),
+
+ newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3],
+ newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}};
+
+ return uuid{std::begin(bytes), std::end(bytes)};
+
+#elif defined(__linux__) || defined(__unix__)
+
+ uuid_t id;
+ uuid_generate(id);
+
+ std::array<uint8_t, 16> bytes = {{id[0], id[1], id[2], id[3], id[4], id[5],
+ id[6], id[7], id[8], id[9], id[10],
+ id[11], id[12], id[13], id[14], id[15]}};
+
+ return uuid{std::begin(bytes), std::end(bytes)};
+
+#elif defined(__APPLE__)
+ auto newId = CFUUIDCreate(NULL);
+ auto bytes = CFUUIDGetUUIDBytes(newId);
+ CFRelease(newId);
+
+ std::array<uint8_t, 16> arrbytes = {
+ {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4,
+ bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9,
+ bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14,
+ bytes.byte15}};
+ return uuid{std::begin(arrbytes), std::end(arrbytes)};
+#else
+ return uuid{};
+#endif
+ }
+ };
+#endif
+
+ template <typename UniformRandomNumberGenerator>
+ class basic_uuid_random_generator
+ {
+ public:
+ using engine_type = UniformRandomNumberGenerator;
+
+ explicit basic_uuid_random_generator(engine_type& gen)
+ : generator(&gen, [](auto) {})
+ {
+ }
+ explicit basic_uuid_random_generator(engine_type* gen)
+ : generator(gen, [](auto) {})
+ {
+ }
+
+ [[nodiscard]] uuid operator()()
+ {
+ alignas(uint32_t) uint8_t bytes[16];
+ for (int i = 0; i < 16; i += 4)
+ *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
+
+ // variant must be 10xxxxxx
+ bytes[8] &= 0xBF;
+ bytes[8] |= 0x80;
+
+ // version must be 0100xxxx
+ bytes[6] &= 0x4F;
+ bytes[6] |= 0x40;
+
+ return uuid{std::begin(bytes), std::end(bytes)};
+ }
+
+ private:
+ std::uniform_int_distribution<uint32_t> distribution;
+ std::shared_ptr<UniformRandomNumberGenerator> generator;
+ };
+
+ using uuid_random_generator = basic_uuid_random_generator<std::mt19937>;
+
+ class uuid_name_generator
+ {
+ public:
+ explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
+ : nsuuid(namespace_uuid)
+ {
+ }
+
+ template <typename StringType>
+ [[nodiscard]] uuid operator()(StringType const& name)
+ {
+ reset();
+ process_characters(Details::to_string_view(name));
+ return make_uuid();
+ }
+
+ private:
+ void reset()
+ {
+ hasher.reset();
+ std::byte bytes[16];
+ auto nsbytes = nsuuid.as_bytes();
+ std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
+ hasher.process_bytes(bytes, 16);
+ }
+
+ template <typename CharT, typename Traits>
+ void process_characters(std::basic_string_view<CharT, Traits> const str)
+ {
+ for (uint32_t c : str)
+ {
+ hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
+ if constexpr (!std::is_same_v<CharT, char>)
+ {
+ hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
+ hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
+ hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
+ }
+ }
+ }
+
+ [[nodiscard]] uuid make_uuid()
+ {
+ Details::sha1::digest8_t digest;
+ hasher.get_digest_bytes(digest);
+
+ // variant must be 0b10xxxxxx
+ digest[8] &= 0xBF;
+ digest[8] |= 0x80;
+
+ // version must be 0b0101xxxx
+ digest[6] &= 0x5F;
+ digest[6] |= 0x50;
+
+ return uuid{digest, digest + 16};
+ }
+
+ private:
+ uuid nsuuid;
+ Details::sha1 hasher;
+ };
+
+#ifdef UUID_TIME_GENERATOR
+ // !!! DO NOT USE THIS IN PRODUCTION
+ // this implementation is unreliable for good uuids
+ class uuid_time_generator
+ {
+ using mac_address = std::array<unsigned char, 6>;
+
+ std::optional<mac_address> device_address;
+
+ [[nodiscard]] bool get_mac_address()
+ {
+ if (device_address.has_value())
+ {
+ return true;
+ }
+
+#ifdef _WIN32
+ DWORD len = 0;
+ auto ret = GetAdaptersInfo(nullptr, &len);
+ if (ret != ERROR_BUFFER_OVERFLOW)
+ return false;
+ std::vector<unsigned char> buf(len);
+ auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front());
+ ret = GetAdaptersInfo(pips, &len);
+ if (ret != ERROR_SUCCESS)
+ return false;
+ mac_address addr;
+ std::copy(pips->Address, pips->Address + 6, std::begin(addr));
+ device_address = addr;
+#endif
+
+ return device_address.has_value();
+ }
+
+ [[nodiscard]] long long get_time_intervals()
+ {
+ auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
+ auto diff = std::chrono::system_clock::now() - start;
+ auto ns =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();
+ return ns / 100;
+ }
+
+ [[nodiscard]] static unsigned short get_clock_sequence()
+ {
+ static std::mt19937 clock_gen(std::random_device{}());
+ static std::uniform_int_distribution<unsigned short> clock_dis;
+ static std::atomic_ushort clock_sequence = clock_dis(clock_gen);
+ return clock_sequence++;
+ }
+
+ public:
+ [[nodiscard]] uuid operator()()
+ {
+ if (get_mac_address())
+ {
+ std::array<uuids::uuid::value_type, 16> data;
+
+ auto tm = get_time_intervals();
+
+ auto clock_seq = get_clock_sequence();
+
+ auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
+
+ memcpy(&data[0], ptm + 4, 4);
+ memcpy(&data[4], ptm + 2, 2);
+ memcpy(&data[6], ptm, 2);
+
+ memcpy(&data[8], &clock_seq, 2);
+
+ // variant must be 0b10xxxxxx
+ data[8] &= 0xBF;
+ data[8] |= 0x80;
+
+ // version must be 0b0001xxxx
+ data[6] &= 0x1F;
+ data[6] |= 0x10;
+
+ memcpy(&data[10], &device_address.value()[0], 6);
+
+ return uuids::uuid{std::cbegin(data), std::cend(data)};
+ }
+
+ return {};
+ }
+ };
+#endif
+} // namespace uuids
+
+namespace std
+{
+ template <>
+ struct hash<uuids::uuid>
+ {
+ using argument_type = uuids::uuid;
+ using result_type = std::size_t;
+
+ [[nodiscard]] result_type operator()(argument_type const& uuid) const
+ {
+#ifdef UUID_HASH_STRING_BASED
+ std::hash<std::string> hasher;
+ return static_cast<result_type>(hasher(uuids::to_string(uuid)));
+#else
+ uint64_t l = static_cast<uint64_t>(uuid.data[0]) << 56 |
+ static_cast<uint64_t>(uuid.data[1]) << 48 |
+ static_cast<uint64_t>(uuid.data[2]) << 40 |
+ static_cast<uint64_t>(uuid.data[3]) << 32 |
+ static_cast<uint64_t>(uuid.data[4]) << 24 |
+ static_cast<uint64_t>(uuid.data[5]) << 16 |
+ static_cast<uint64_t>(uuid.data[6]) << 8 |
+ static_cast<uint64_t>(uuid.data[7]);
+ uint64_t h = static_cast<uint64_t>(uuid.data[8]) << 56 |
+ static_cast<uint64_t>(uuid.data[9]) << 48 |
+ static_cast<uint64_t>(uuid.data[10]) << 40 |
+ static_cast<uint64_t>(uuid.data[11]) << 32 |
+ static_cast<uint64_t>(uuid.data[12]) << 24 |
+ static_cast<uint64_t>(uuid.data[13]) << 16 |
+ static_cast<uint64_t>(uuid.data[14]) << 8 |
+ static_cast<uint64_t>(uuid.data[15]);
+
+ if constexpr (sizeof(result_type) > 4)
+ {
+ return result_type(l ^ h);
+ }
+ else
+ {
+ uint64_t hash64 = l ^ h;
+ return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
+ }
+#endif
+ }
+ };
+} // namespace std
+
+#endif /* STDUUID_H */ \ No newline at end of file
diff --git a/dev/LibCompiler/Version.h b/dev/LibCompiler/Version.h
new file mode 100644
index 0000000..7fd0ffe
--- /dev/null
+++ b/dev/LibCompiler/Version.h
@@ -0,0 +1,15 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#define kDistVersion "v1.1.0"
+#define kDistVersionBCD 0x0110
+
+#define ToString(X) Stringify(X)
+#define Stringify(X) #X
+
+#define kDistRelease ToString(kDistReleaseBranch)
diff --git a/dev/LibCompiler/src/Assembler32x0.cc b/dev/LibCompiler/src/Assembler32x0.cc
new file mode 100644
index 0000000..3a5e030
--- /dev/null
+++ b/dev/LibCompiler/src/Assembler32x0.cc
@@ -0,0 +1,50 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+/// bugs: 0
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @file 32asm.cxx
+// @author EL Mahrouss Amlal
+// @brief 32x0 Assembler.
+
+// REMINDER: when dealing with an undefined symbol use (string
+// size):LinkerFindSymbol:(string) so that ld will look for it.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define __ASM_NEED_32x0__ 1
+
+#include <LibCompiler/AAL/CPU/32x0.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/NFC/AE.h>
+#include <LibCompiler/NFC/PEF.h>
+
+/////////////////////
+
+// 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.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TOOLCHAINKIT_MODULE(ZKAAssemblerMain32000)
+{
+ return 0;
+}
diff --git a/dev/LibCompiler/src/Assembler64x0.cc b/dev/LibCompiler/src/Assembler64x0.cc
new file mode 100644
index 0000000..968b6a5
--- /dev/null
+++ b/dev/LibCompiler/src/Assembler64x0.cc
@@ -0,0 +1,1117 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+/// bugs: 0
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @file Assembler64x0.cxx
+// @author EL Mahrouss Amlal
+// @brief 64x000 Assembler.
+
+// REMINDER: when dealing with an undefined symbol use (string
+// size):LinkerFindSymbol:(string) so that ld will look for it.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define __ASM_NEED_64x0__ 1
+
+#include <LibCompiler/AAL/CPU/64x0.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/NFC/AE.h>
+#include <LibCompiler/NFC/PEF.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// ANSI ESCAPE CODES
+
+/////////////////////
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+#define kYellow "\e[0;33m"
+
+#define kStdOut (std::cout << kWhite)
+#define kStdErr (std::cout << kRed)
+
+static char kOutputArch = LibCompiler::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 LibCompiler::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<LibCompiler::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 Details
+{
+ void print_error(std::string reason, std::string file) noexcept
+ {
+ if (reason[0] == '\n')
+ reason.erase(0, 1);
+
+ kStdErr << kRed << "[ TQC++ ] " << kWhite
+ << ((file == "LibCompiler") ? "InternalErrorException: "
+ : ("FileException{ " + file + " }: "))
+ << kBlank << std::endl;
+ kStdErr << kRed << "[ TQC++ ] " << kWhite << reason << kBlank << std::endl;
+
+ if (kAcceptableErrors > kErrorLimit)
+ std::exit(3);
+
+ ++kAcceptableErrors;
+ }
+
+ void print_warning(std::string reason, std::string file) noexcept
+ {
+ if (reason[0] == '\n')
+ reason.erase(0, 1);
+
+ if (!file.empty())
+ {
+ kStdOut << kYellow << "[ TQC++ ] " << kWhite << file << kBlank << std::endl;
+ }
+
+ kStdOut << kYellow << "[ TQC++ ] " << kWhite << reason << kBlank << std::endl;
+ }
+} // namespace Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief 64x0 assembler entrypoint, the program/module starts here.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TOOLCHAINKIT_MODULE(AssemblerMain64x0)
+{
+ for (size_t i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0)
+ {
+ kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) "
+ "Theater Quality Inc\n";
+ return 0;
+ }
+ else if (strcmp(argv[i], "--h") == 0)
+ {
+ kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss "
+ "Logic.\n";
+ kStdOut << "--version: Print program version.\n";
+ kStdOut << "--verbose: Print verbose output.\n";
+ kStdOut << "--binary: Output as flat binary.\n";
+ kStdOut << "--64xxx: Compile for a subset of the X64000.\n";
+
+ return 0;
+ }
+ else if (strcmp(argv[i], "--binary") == 0)
+ {
+ kOutputAsBinary = true;
+ continue;
+ }
+ else if (strcmp(argv[i], "--verbose") == 0)
+ {
+ kVerbose = true;
+ continue;
+ }
+
+ kStdOut << "Assembler64x0: ignore " << argv[i] << "\n";
+ continue;
+ }
+
+ if (!std::filesystem::exists(argv[i]))
+ {
+ kStdOut << "Assembler64x0: can't open: " << argv[i] << std::endl;
+ goto asm_fail_exit;
+ }
+
+ std::string object_output(argv[i]);
+
+ for (auto& ext : kAsmFileExts)
+ {
+ if (object_output.find(ext) != std::string::npos)
+ {
+ object_output.erase(object_output.find(ext), std::strlen(ext));
+ }
+ }
+
+ object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt;
+
+ std::ifstream file_ptr(argv[i]);
+ std::ofstream file_ptr_out(object_output, std::ofstream::binary);
+
+ if (file_ptr_out.bad())
+ {
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: error: " << strerror(errno) << "\n";
+ }
+ }
+
+ std::string line;
+
+ LibCompiler::AEHeader hdr{0};
+
+ memset(hdr.fPad, kAENullType, kAEPad);
+
+ hdr.fMagic[0] = kAEMag0;
+ hdr.fMagic[1] = kAEMag1;
+ hdr.fSize = sizeof(LibCompiler::AEHeader);
+ hdr.fArch = kOutputArch;
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ // COMPILATION LOOP
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ LibCompiler::Encoder64x0 asm64;
+
+ while (std::getline(file_ptr, line))
+ {
+ if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty())
+ {
+ Details::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();
+ Details::print_warning("exit because of: " + what, "LibCompiler");
+ }
+
+ std::filesystem::remove(object_output);
+ goto asm_fail_exit;
+ }
+ }
+
+ if (!kOutputAsBinary)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: Writing object file...\n";
+ }
+
+ // this is the final step, write everything to the file.
+
+ auto pos = file_ptr_out.tellp();
+
+ hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
+
+ file_ptr_out << hdr;
+
+ if (kRecords.empty())
+ {
+ kStdErr << "Assembler64x0: At least one record is needed to write an object "
+ "file.\nAssembler64x0: Make one using `public_segment .code64 foo_bar`.\n";
+
+ std::filesystem::remove(object_output);
+ return 1;
+ }
+
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ std::size_t record_count = 0UL;
+
+ for (auto& rec : kRecords)
+ {
+ if (kVerbose)
+ kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n";
+
+ rec.fFlags |= LibCompiler::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)
+ {
+ LibCompiler::AERecordHeader _record_hdr{0};
+
+ if (kVerbose)
+ kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n";
+
+ _record_hdr.fKind = kAENullType;
+ _record_hdr.fSize = sym.size();
+ _record_hdr.fOffset = record_count;
+
+ ++record_count;
+
+ memset(_record_hdr.fPad, kAENullType, kAEPad);
+ memcpy(_record_hdr.fName, sym.c_str(), sym.size());
+
+ file_ptr_out << _record_hdr;
+
+ ++kCounter;
+ }
+
+ auto pos_end = file_ptr_out.tellp();
+
+ file_ptr_out.seekp(pos);
+
+ hdr.fStartCode = pos_end;
+ hdr.fCodeSize = kBytes.size();
+
+ file_ptr_out << hdr;
+
+ file_ptr_out.seekp(pos_end);
+ }
+ else
+ {
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: Write raw binary...\n";
+ }
+ }
+
+ // byte from byte, we write this.
+ for (auto& byte : kBytes)
+ {
+ file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte));
+ }
+
+ if (kVerbose)
+ kStdOut << "Assembler64x0: Wrote file with program in it.\n";
+
+ file_ptr_out.flush();
+ file_ptr_out.close();
+
+ if (kVerbose)
+ kStdOut << "Assembler64x0: Exit succeeded.\n";
+
+ return 0;
+ }
+
+asm_fail_exit:
+
+ if (kVerbose)
+ kStdOut << "Assembler64x0: Exit failed.\n";
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for attributes
+// returns true if any was found.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool asm_read_attributes(std::string& line)
+{
+ // extern_segment is the opposite of public_segment, it signals to the ld
+ // that we need this symbol.
+ if (LibCompiler::find_word(line, "extern_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid extern_segment directive in flat binary mode.",
+ "LibCompiler");
+ throw std::runtime_error("invalid_extern_segment_bin");
+ }
+
+ auto name = line.substr(line.find("extern_segment") + strlen("extern_segment"));
+
+ /// sanity check to avoid stupid linker errors.
+ if (name.size() == 0)
+ {
+ Details::print_error("Invalid extern_segment", "power-as");
+ throw std::runtime_error("invalid_extern_segment");
+ }
+
+ std::string result = std::to_string(name.size());
+ result += kUndefinedSymbol;
+
+ // mangle this
+ for (char& j : name)
+ {
+ if (j == ' ' || j == ',')
+ j = '$';
+ }
+
+ result += name;
+
+ if (name.find(".code64") != std::string::npos)
+ {
+ // data is treated as code.
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+ else if (name.find(".data64") != std::string::npos)
+ {
+ // no code will be executed from here.
+ kCurrentRecord.fKind = LibCompiler::kPefData;
+ }
+ else if (name.find(".zero64") != std::string::npos)
+ {
+ // this is a bss section.
+ kCurrentRecord.fKind = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that ld can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, result.c_str(), result.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+ // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to
+ // mark this section as a header. it currently supports .code64, .data64.,
+ // .zero64
+ else if (LibCompiler::find_word(line, "public_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid public_segment directive in flat binary mode.",
+ "LibCompiler");
+ throw std::runtime_error("invalid_public_segment_bin");
+ }
+
+ auto name = line.substr(line.find("public_segment") + strlen("public_segment"));
+
+ std::string name_copy = name;
+
+ for (char& j : name)
+ {
+ if (j == ' ')
+ j = '$';
+ }
+
+ if (name.find(".code64") != std::string::npos)
+ {
+ // data is treated as code.
+
+ name_copy.erase(name_copy.find(".code64"), strlen(".code64"));
+ kCurrentRecord.fKind = LibCompiler::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 = LibCompiler::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 = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that ld can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ while (name_copy.find(" ") != std::string::npos)
+ name_copy.erase(name_copy.find(" "), 1);
+
+ kOriginLabel.push_back(std::make_pair(name_copy, kOrigin));
+ ++kOrigin;
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, name.c_str(), name.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+
+ return false;
+}
+
+// \brief algorithms and helpers.
+
+namespace Details::algorithm
+{
+ // \brief authorize a brief set of characters.
+ static inline bool is_not_alnum_space(char c)
+ {
+ return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') ||
+ (c == ',') || (c == '(') || (c == ')') || (c == '"') ||
+ (c == '\'') || (c == '[') || (c == ']') || (c == '+') ||
+ (c == '_') || (c == ':') || (c == '@') || (c == '.'));
+ }
+
+ bool is_valid_64x0(const std::string& str)
+ {
+ return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
+ }
+} // namespace Details::algorithm
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for line (syntax check)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::string LibCompiler::Encoder64x0::CheckLine(std::string& line,
+ const std::string& file)
+{
+ std::string err_str;
+
+ if (line.empty() || LibCompiler::find_word(line, "extern_segment") ||
+ LibCompiler::find_word(line, "public_segment") ||
+ line.find('#') != std::string::npos || LibCompiler::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 (!Details::algorithm::is_valid_64x0(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+ }
+ }
+
+ return err_str;
+ }
+
+ if (!Details::algorithm::is_valid_64x0(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ // check for a valid instruction format.
+
+ if (line.find(',') != std::string::npos)
+ {
+ if (line.find(',') + 1 == line.size())
+ {
+ err_str += "\nInstruction lacks right register, here -> ";
+ err_str += line.substr(line.find(','));
+
+ return err_str;
+ }
+ else
+ {
+ bool nothing_on_right = true;
+
+ if (line.find(',') + 1 > line.size())
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ auto substr = line.substr(line.find(',') + 1);
+
+ for (auto& ch : substr)
+ {
+ if (ch != ' ' && ch != '\t')
+ {
+ nothing_on_right = false;
+ }
+ }
+
+ // this means we found nothing after that ',' .
+ if (nothing_on_right)
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+ }
+ }
+
+ // these do take an argument.
+ std::vector<std::string> operands_inst = {"stw", "ldw", "lda", "sta"};
+
+ // these don't.
+ std::vector<std::string> filter_inst = {"jlr", "jrl", "int"};
+
+ for (auto& opcode64x0 : kOpcodes64x0)
+ {
+ if (line.find(opcode64x0.fName) != std::string::npos)
+ {
+ if (opcode64x0.fFunct7 == kAsmNoArgs)
+ return err_str;
+
+ for (auto& op : operands_inst)
+ {
+ // if only the instruction was found.
+ if (line == op)
+ {
+ err_str += "\nMalformed ";
+ err_str += op;
+ err_str += " instruction, here -> ";
+ err_str += line;
+ }
+ }
+
+ // if it is like that -> addr1, 0x0
+ if (auto it = std::find(filter_inst.begin(), filter_inst.end(),
+ opcode64x0.fName);
+ it == filter_inst.cend())
+ {
+ if (LibCompiler::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 LibCompiler::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)
+ {
+ Details::print_error("invalid hex number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_hex_number");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid binary number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid octal number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos).c_str(), nullptr, 10));
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Read and write an instruction to the output array.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool LibCompiler::Encoder64x0::WriteLine(std::string& line,
+ const std::string& file)
+{
+ if (LibCompiler::find_word(line, "public_segment "))
+ return true;
+
+ for (auto& opcode64x0 : kOpcodes64x0)
+ {
+ // strict check here
+ if (LibCompiler::find_word(line, opcode64x0.fName) &&
+ Details::algorithm::is_valid_64x0(line))
+ {
+ std::string name(opcode64x0.fName);
+ std::string jump_label, cpy_jump_label;
+
+ kBytes.emplace_back(opcode64x0.fOpcode);
+ kBytes.emplace_back(opcode64x0.fFunct3);
+ kBytes.emplace_back(opcode64x0.fFunct7);
+
+ // check funct7 type.
+ switch (opcode64x0.fFunct7)
+ {
+ // reg to reg means register to register transfer operation.
+ case kAsmRegToReg:
+ case kAsmImmediate: {
+ // \brief how many registers we found.
+ std::size_t found_some = 0UL;
+
+ for (size_t line_index = 0UL; line_index < line.size();
+ line_index++)
+ {
+ if (line[line_index] == kAsmRegisterPrefix[0] &&
+ isdigit(line[line_index + 1]))
+ {
+ std::string register_syntax = kAsmRegisterPrefix;
+ register_syntax += line[line_index + 1];
+
+ if (isdigit(line[line_index + 2]))
+ register_syntax += line[line_index + 2];
+
+ std::string reg_str;
+ reg_str += line[line_index + 1];
+
+ if (isdigit(line[line_index + 2]))
+ reg_str += line[line_index + 2];
+
+ // it ranges from r0 to r19
+ // something like r190 doesn't exist in the instruction set.
+ if (kOutputArch == LibCompiler::kPefArch64000)
+ {
+ if (isdigit(line[line_index + 3]) &&
+ isdigit(line[line_index + 2]))
+ {
+ reg_str += line[line_index + 3];
+ Details::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)
+ {
+ Details::print_error("invalid register index, r" + reg_str,
+ file);
+ throw std::runtime_error("invalid_register_index");
+ }
+
+ kBytes.emplace_back(reg_index);
+ ++found_some;
+
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: Register found: " << register_syntax << "\n";
+ kStdOut << "Assembler64x0: Register amount in instruction: "
+ << found_some << "\n";
+ }
+ }
+ }
+
+ // we're not in immediate addressing, reg to reg.
+ if (opcode64x0.fFunct7 != kAsmImmediate)
+ {
+ // remember! register to register!
+ if (found_some == 1)
+ {
+ Details::print_error(
+ "Too few registers.\ntip: each Assembler64x0 register "
+ "starts with 'r'.\nline: " +
+ line,
+ file);
+ throw std::runtime_error("not_a_register");
+ }
+ }
+
+ if (found_some < 1 && name != "ldw" && name != "lda" &&
+ name != "stw")
+ {
+ Details::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")
+ {
+ Details::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")
+ {
+ Details::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")
+ {
+ Details::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)
+ {
+ Details::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")
+ {
+ Details::print_error(
+ "invalid combination of opcode and operands.\nHere ->" + line,
+ file);
+ throw std::runtime_error("invalid_comb_op_ops");
+ }
+ }
+ else
+ {
+ if (name == "sta" &&
+ cpy_jump_label.find("extern_segment ") != std::string::npos)
+ {
+ Details::print_error("invalid usage extern_segment on 'sta', here: " + line,
+ file);
+ throw std::runtime_error("invalid_sta_usage");
+ }
+ }
+
+ goto asm_write_label;
+ }
+
+ // This is the case where we jump to a label, it is also used as a goto.
+ if (name == "lda" || name == "sta")
+ {
+ asm_write_label:
+ if (cpy_jump_label.find('\n') != std::string::npos)
+ cpy_jump_label.erase(cpy_jump_label.find('\n'), 1);
+
+ if (cpy_jump_label.find("extern_segment") != std::string::npos)
+ {
+ cpy_jump_label.erase(cpy_jump_label.find("extern_segment"), strlen("extern_segment"));
+
+ if (name == "sta")
+ {
+ Details::print_error("extern_segment is not allowed on a sta operation.",
+ file);
+ throw std::runtime_error("extern_segment_sta_op");
+ }
+ else
+ {
+ goto asm_end_label_cpy;
+ }
+ }
+
+ if (name == "lda" || name == "sta")
+ {
+ for (auto& label : kOriginLabel)
+ {
+ if (cpy_jump_label == label.first)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "Assembler64x0: Replace label " << cpy_jump_label
+ << " to address: " << label.second << std::endl;
+ }
+
+ LibCompiler::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)
+ {
+ Details::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/dev/LibCompiler/src/AssemblerAMD64.cc b/dev/LibCompiler/src/AssemblerAMD64.cc
new file mode 100644
index 0000000..365163d
--- /dev/null
+++ b/dev/LibCompiler/src/AssemblerAMD64.cc
@@ -0,0 +1,1481 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @file AssemblerAMD64.cc
+/// @author EL Mahrouss Amlal
+/// @brief AMD64 Assembler.
+/// REMINDER: when dealing with an undefined symbol use (string
+/// size):LinkerFindSymbol:(string) so that ld will look for it.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// bugs: 0
+
+/// feature request: 1
+/// Encode registers in mov, add, xor...
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define __ASM_NEED_AMD64__ 1
+
+#define kAssemblerPragmaSymStr "#"
+#define kAssemblerPragmaSym '#'
+
+#include <LibCompiler/AAL/CPU/amd64.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/NFC/AE.h>
+#include <LibCompiler/NFC/PEF.h>
+#include <algorithm>
+#include <cstdlib>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+/////////////////////
+
+// ANSI ESCAPE CODES
+
+/////////////////////
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+#define kYellow "\e[0;33m"
+
+#define kStdOut (std::cout << kWhite)
+#define kStdErr (std::cout << kRed)
+
+static char kOutputArch = LibCompiler::kPefArchAMD64;
+static Boolean kOutputAsBinary = false;
+
+static UInt32 kErrorLimit = 10;
+static UInt32 kAcceptableErrors = 0;
+
+constexpr auto kIPAlignement = 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 LibCompiler::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<LibCompiler::AERecordHeader> kRecords;
+static std::vector<std::string> kDefinedSymbols;
+static std::vector<std::string> kUndefinedSymbols;
+
+static const std::string kUndefinedSymbol = ":UndefinedSymbol:";
+
+// \brief forward decl.
+static bool asm_read_attributes(std::string& line);
+
+#include <AsmUtils.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief AMD64 assembler entrypoint, the program/module starts here.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TOOLCHAINKIT_MODULE(AssemblerAMD64)
+{
+ //////////////// 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], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0)
+ {
+ kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: v1.10\nAssemblerAMD64: Copyright "
+ "(c) Theater Quality Inc\n";
+ return 0;
+ }
+ else if (strcmp(argv[i], "--amd64:h") == 0)
+ {
+ kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: Copyright (c) 2024 "
+ "Theater Quality Inc\n";
+ kStdOut << "--version: Print program version.\n";
+ kStdOut << "--verbose: Print verbose output.\n";
+ kStdOut << "--binary: Output as flat binary.\n";
+
+ return 0;
+ }
+ else if (strcmp(argv[i], "--amd64:binary") == 0)
+ {
+ kOutputAsBinary = true;
+ continue;
+ }
+ else if (strcmp(argv[i], "--amd64:verbose") == 0)
+ {
+ kVerbose = true;
+ continue;
+ }
+
+ kStdOut << "AssemblerAMD64: ignore " << argv[i] << "\n";
+ continue;
+ }
+
+ if (!std::filesystem::exists(argv[i]))
+ {
+ kStdOut << "AssemblerAMD64: can't open: " << argv[i] << std::endl;
+ goto asm_fail_exit;
+ }
+
+ std::string object_output(argv[i]);
+ std::string asm_input(argv[i]);
+
+ for (auto& ext : kAsmFileExts)
+ {
+ if (object_output.ends_with(ext))
+ {
+ object_output.erase(object_output.find(ext), std::strlen(ext));
+ break;
+ }
+ }
+
+ object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt;
+
+ std::ifstream file_ptr(argv[i]);
+ std::ofstream file_ptr_out(object_output, std::ofstream::binary);
+
+ kStdOut << "AssemblerAMD64: Assembling: " << argv[i] << "\n";
+
+ if (file_ptr_out.bad())
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: error: " << strerror(errno) << "\n";
+ }
+
+ return 1;
+ }
+
+ std::string line;
+
+ LibCompiler::AEHeader hdr{0};
+
+ memset(hdr.fPad, kAENullType, kAEPad);
+
+ hdr.fMagic[0] = kAEMag0;
+ hdr.fMagic[1] = kAEMag1;
+ hdr.fSize = sizeof(LibCompiler::AEHeader);
+ hdr.fArch = kOutputArch;
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ // COMPILATION LOOP
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ LibCompiler::EncoderAMD64 asm64;
+
+ if (kVerbose)
+ {
+ kStdOut << "Compiling: " + asm_input << "\n";
+ kStdOut << "From: " + line << "\n";
+ }
+
+ while (std::getline(file_ptr, line))
+ {
+ if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty())
+ {
+ Details::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();
+ Details::print_warning("exit because of: " + what, "LibCompiler");
+ }
+
+ try
+ {
+ std::filesystem::remove(object_output);
+ }
+ catch (...)
+ {
+ }
+
+ goto asm_fail_exit;
+ }
+ }
+
+ if (!kOutputAsBinary)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Writing object file...\n";
+ }
+
+ // this is the final step, write everything to the file.
+
+ auto pos = file_ptr_out.tellp();
+
+ hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
+
+ file_ptr_out << hdr;
+
+ if (kRecords.empty())
+ {
+ kStdErr << "AssemblerAMD64: At least one record is needed to write an object "
+ "file.\nAssemblerAMD64: Make one using `public_segment .code64 foo_bar`.\n";
+
+ std::filesystem::remove(object_output);
+ return 1;
+ }
+
+ kRecords[kRecords.size() - 1].fSize = kAppBytes.size();
+
+ std::size_t record_count = 0UL;
+
+ for (auto& rec : kRecords)
+ {
+ if (kVerbose)
+ kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n";
+
+ rec.fFlags |= LibCompiler::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)
+ {
+ LibCompiler::AERecordHeader _record_hdr{0};
+
+ if (kVerbose)
+ kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n";
+
+ _record_hdr.fKind = kAENullType;
+ _record_hdr.fSize = sym.size();
+ _record_hdr.fOffset = record_count;
+
+ ++record_count;
+
+ memset(_record_hdr.fPad, kAENullType, kAEPad);
+ memcpy(_record_hdr.fName, sym.c_str(), sym.size());
+
+ file_ptr_out << _record_hdr;
+
+ ++kCounter;
+ }
+
+ auto pos_end = file_ptr_out.tellp();
+
+ file_ptr_out.seekp(pos);
+
+ hdr.fStartCode = pos_end;
+ hdr.fCodeSize = kAppBytes.size();
+
+ file_ptr_out << hdr;
+
+ file_ptr_out.seekp(pos_end);
+ }
+ else
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Write raw binary...\n";
+ }
+ }
+
+ // byte from byte, we write this.
+ for (auto& byte : kAppBytes)
+ {
+ if (byte == 0)
+ continue;
+
+ if (byte == 0xFF)
+ {
+ byte = 0;
+ }
+
+ file_ptr_out << reinterpret_cast<const char*>(&byte)[0];
+ }
+
+ if (kVerbose)
+ kStdOut << "AssemblerAMD64: Wrote file with program in it.\n";
+
+ file_ptr_out.flush();
+ file_ptr_out.close();
+
+ if (kVerbose)
+ kStdOut << "AssemblerAMD64: Exit succeeded.\n";
+
+ return 0;
+ }
+
+asm_fail_exit:
+
+ if (kVerbose)
+ kStdOut << "AssemblerAMD64: Exit failed.\n";
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for attributes
+// returns true if any was found.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool asm_read_attributes(std::string& line)
+{
+ // extern_segment is the opposite of public_segment, it signals to the ld
+ // that we need this symbol.
+ if (LibCompiler::find_word(line, "extern_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid directive in flat binary mode.", "LibCompiler");
+ throw std::runtime_error("invalid_extern_segment_bin");
+ }
+
+ auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1);
+
+ if (name.size() == 0)
+ {
+ Details::print_error("Invalid extern_segment", "power-as");
+ throw std::runtime_error("invalid_extern_segment");
+ }
+
+ std::string result = std::to_string(name.size());
+ result += kUndefinedSymbol;
+
+ // mangle this
+ for (char& j : name)
+ {
+ if (j == ' ' || j == ',')
+ j = '$';
+ }
+
+ result += name;
+
+ if (name.find(kPefCode64) != std::string::npos)
+ {
+ // data is treated as code.
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+ else if (name.find(kPefData64) != std::string::npos)
+ {
+ // no code will be executed from here.
+ kCurrentRecord.fKind = LibCompiler::kPefData;
+ }
+ else if (name.find(kPefZero64) != std::string::npos)
+ {
+ // this is a bss section.
+ kCurrentRecord.fKind = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that ld can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kAppBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, result.c_str(), result.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+ // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to
+ // mark this section as a header. it currently supports .code64, .data64 and
+ // .zero64.
+ else if (LibCompiler::find_word(line, "public_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid directive in flat binary mode.", "LibCompiler");
+ throw std::runtime_error("invalid_public_segment_bin");
+ }
+
+ auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 1);
+
+ std::string name_copy = name;
+
+ for (char& j : name)
+ {
+ if (j == ' ')
+ j = '$';
+ }
+
+ if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) !=
+ kDefinedSymbols.end())
+ {
+ Details::print_error("Symbol already defined.", "LibCompiler");
+ throw std::runtime_error("invalid_public_segment_bin");
+ }
+
+ kDefinedSymbols.push_back(name);
+
+ if (name.find(".code64") != std::string::npos)
+ {
+ // data is treated as code.
+
+ name_copy.erase(name_copy.find(".code64"), strlen(".code64"));
+ kCurrentRecord.fKind = LibCompiler::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 = LibCompiler::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 = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that ld can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ while (name_copy.find(" ") != std::string::npos)
+ name_copy.erase(name_copy.find(" "), 1);
+
+ kOriginLabel.push_back(std::make_pair(name_copy, kOrigin));
+ ++kOrigin;
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kAppBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, name.c_str(), name.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+
+ return false;
+}
+
+// \brief algorithms and helpers.
+
+namespace Details::algorithm
+{
+ // \brief authorize a brief set of characters.
+ static inline bool is_not_valid(char c)
+ {
+ if ((isalpha(c) || isdigit(c)) || ((c == ' ') || (c == '\t') ||
+ (c == ',') || (c == '(') || (c == ')') || (c == '"') || (c == '*') ||
+ (c == '\'') || (c == '[') || (c == ']') || (c == '+') ||
+ (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#') || (c == ';')))
+ return false;
+
+ return true;
+ }
+
+ bool is_valid_amd64(const std::string& str)
+ {
+ return std::find_if(str.begin(), str.end(), is_not_valid) == str.end();
+ }
+} // namespace Details::algorithm
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for line (syntax check)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::string LibCompiler::EncoderAMD64::CheckLine(std::string& line,
+ const std::string& file)
+{
+ std::string err_str;
+
+ if (line.empty() || LibCompiler::find_word(line, "extern_segment") ||
+ LibCompiler::find_word(line, "public_segment") ||
+ LibCompiler::find_word(line, kAssemblerPragmaSymStr) ||
+ LibCompiler::find_word(line, ";") || line[0] == kAssemblerPragmaSym)
+ {
+ if (line.find(';') != std::string::npos)
+ {
+ line.erase(line.find(';'));
+ }
+ else
+ {
+ // now check the line for validity
+ if (!Details::algorithm::is_valid_amd64(line))
+ {
+ err_str = "Line contains non valid characters.\nhere -> ";
+ err_str += line;
+ }
+ }
+
+ return err_str;
+ }
+
+ // check for a valid instruction format.
+
+ if (line.find(',') != std::string::npos)
+ {
+ if (line.find(',') + 1 == line.size())
+ {
+ err_str += "\nInstruction lacks right register, here -> ";
+ err_str += line.substr(line.find(','));
+
+ return err_str;
+ }
+ else
+ {
+ bool nothing_on_right = true;
+
+ if (line.find(',') + 1 > line.size())
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ auto substr = line.substr(line.find(',') + 1);
+
+ for (auto& ch : substr)
+ {
+ if (ch != ' ' && ch != '\t')
+ {
+ nothing_on_right = false;
+ }
+ }
+
+ // this means we found nothing after that ',' .
+ if (nothing_on_right)
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+ }
+ }
+ for (auto& opcodeAMD64 : kOpcodesAMD64)
+ {
+ if (LibCompiler::find_word(line, opcodeAMD64.fName))
+ {
+ return err_str;
+ }
+ }
+
+ err_str += "\nUnrecognized instruction -> " + line;
+
+ return err_str;
+}
+
+bool LibCompiler::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)
+ {
+ Details::print_error("invalid hex number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_hex");
+ }
+ }
+
+ LibCompiler::NumberCast64 num = LibCompiler::NumberCast64(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid binary number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ LibCompiler::NumberCast64 num = LibCompiler::NumberCast64(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid octal number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ LibCompiler::NumberCast64 num = LibCompiler::NumberCast64(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ LibCompiler::NumberCast64 num = LibCompiler::NumberCast64(
+ strtol(jump_label.substr(pos).c_str(), nullptr, 10));
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+bool LibCompiler::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;
+ }
+
+ LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res);
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ res += kOrigin;
+
+ if (errno != 0)
+ {
+ return false;
+ }
+
+ LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res);
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o': {
+ auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ res += kOrigin;
+
+ if (errno != 0)
+ {
+ return false;
+ }
+
+ LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res);
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10);
+ res += kOrigin;
+
+ if (errno != 0)
+ {
+ return false;
+ }
+
+ LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res);
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+bool LibCompiler::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)
+ {
+ Details::print_error("invalid hex number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_hex");
+ }
+ }
+
+ LibCompiler::NumberCast16 num = LibCompiler::NumberCast16(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid binary number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ LibCompiler::NumberCast16 num = LibCompiler::NumberCast16(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid octal number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ LibCompiler::NumberCast16 num = LibCompiler::NumberCast16(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ LibCompiler::NumberCast16 num = LibCompiler::NumberCast16(
+ strtol(jump_label.substr(pos).c_str(), nullptr, 10));
+
+ for (char& i : num.number)
+ {
+ if (i == 0)
+ i = 0xFF;
+
+ kAppBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+bool LibCompiler::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)
+ {
+ Details::print_error("invalid hex number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_hex");
+ }
+ }
+
+ LibCompiler::NumberCast8 num = LibCompiler::NumberCast8(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
+
+ kAppBytes.push_back(num.number);
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid binary number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ LibCompiler::NumberCast8 num = LibCompiler::NumberCast8(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ kAppBytes.push_back(num.number);
+
+ return true;
+ }
+ case 'o': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid octal number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ LibCompiler::NumberCast8 num = LibCompiler::NumberCast8(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ kAppBytes.push_back(num.number);
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ LibCompiler::NumberCast8 num = LibCompiler::NumberCast8(
+ strtol(jump_label.substr(pos).c_str(), nullptr, 10));
+
+ kAppBytes.push_back(num.number);
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Read and write an instruction to the output array.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool LibCompiler::EncoderAMD64::WriteLine(std::string& line,
+ const std::string& file)
+{
+ if (LibCompiler::find_word(line, "public_segment "))
+ return true;
+
+ struct RegMapAMD64
+ {
+ std::string fName;
+ i64_byte_t fModRM;
+ };
+
+ std::vector<RegMapAMD64> kRegisterList{
+ {.fName = "ax", .fModRM = 0x0},
+ {.fName = "cx", .fModRM = 1},
+ {.fName = "dx", .fModRM = 0x2},
+ {.fName = "bx", .fModRM = 3},
+ {.fName = "sp", .fModRM = 0x4},
+ {.fName = "bp", .fModRM = 5},
+ {.fName = "si", .fModRM = 0x6},
+ {.fName = "di", .fModRM = 7},
+ {.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 (LibCompiler::find_word(line, opcodeAMD64.fName) &&
+ Details::algorithm::is_valid_amd64(line))
+ {
+ foundInstruction = true;
+ std::string name(opcodeAMD64.fName);
+
+ /// Move instruction handler.
+ if (line.find(name) != std::string::npos &&
+ name == "mov")
+ {
+ std::string substr = line.substr(line.find(name) + name.size());
+
+ uint64_t bits = kRegisterBitWidth;
+
+ if (substr.find(",") == std::string::npos)
+ {
+ Details::print_error("Syntax error: missing right operand.", "LibCompiler");
+ throw std::runtime_error("syntax_err");
+ }
+
+ bool onlyOneReg = true;
+
+ std::vector<RegMapAMD64> currentRegList;
+
+ for (auto& reg : kRegisterList)
+ {
+ std::vector<char> regExt = {'e', 'r'};
+
+ for (auto& ext : regExt)
+ {
+ std::string registerName;
+
+ if (bits > 16)
+ registerName.push_back(ext);
+
+ registerName += reg.fName;
+
+ while (line.find(registerName) != std::string::npos)
+ {
+ line.erase(line.find(registerName), registerName.size());
+
+ if (bits == 16)
+ {
+ if (registerName[0] == 'r')
+ {
+ Details::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);
+ }
+
+ if (!onlyOneReg)
+ kAppBytes.emplace_back(0x89);
+ }
+ else if (bits == 16)
+ {
+ if (hasRBasedRegs)
+ {
+ Details::print_error(
+ "Invalid combination of operands and registers.", "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+ else
+ {
+ kAppBytes.emplace_back(0x66);
+ kAppBytes.emplace_back(0x89);
+ }
+ }
+
+ if (onlyOneReg)
+ {
+ auto num = GetNumber32(line, ",");
+
+ for (auto& num_idx: num.number)
+ {
+ if (num_idx == 0)
+ num_idx = 0xFF;
+ }
+
+ auto modrm = (0x3 << 6 |
+ currentRegList[0].fModRM);
+
+ kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number.
+ kAppBytes.emplace_back(modrm);
+ kAppBytes.emplace_back(num.number[0]);
+ kAppBytes.emplace_back(num.number[1]);
+ kAppBytes.emplace_back(num.number[2]);
+ kAppBytes.emplace_back(num.number[3]);
+
+ break;
+ }
+
+ if (currentRegList[1].fName[0] == 'r' &&
+ currentRegList[0].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+
+ if (currentRegList[0].fName[0] == 'r' &&
+ currentRegList[1].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+
+ if (bits == 16)
+ {
+ if (currentRegList[0].fName[0] == 'r' ||
+ currentRegList[0].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+
+ if (currentRegList[1].fName[0] == 'r' ||
+ currentRegList[1].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+ }
+ else
+ {
+ if (currentRegList[0].fName[0] != 'r' ||
+ currentRegList[0].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ throw std::runtime_error("comb_op_reg");
+ }
+
+ if (currentRegList[1].fName[0] != 'r' ||
+ currentRegList[1].fName[0] == 'e')
+ {
+ Details::print_error("Invalid combination of operands and registers.",
+ "LibCompiler");
+ 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)
+ {
+ Details::print_error("Syntax error: " + line, "LibCompiler");
+ throw std::runtime_error("syntax_err");
+ }
+
+ if (line.find("bits 64") != std::string::npos)
+ {
+ kRegisterBitWidth = 64U;
+ }
+ else if (line.find("bits 32") != std::string::npos)
+ {
+ kRegisterBitWidth = 32U;
+ }
+ else if (line.find("bits 16") != std::string::npos)
+ {
+ kRegisterBitWidth = 16U;
+ }
+ else if (line.find("org") != std::string::npos)
+ {
+ size_t base[] = {10, 16, 2, 7};
+
+ for (size_t i = 0; i < 4; i++)
+ {
+ if (kOrigin = strtol(
+ (line.substr(line.find("org") + strlen("org") + 1)).c_str(),
+ nullptr, base[i]);
+ kOrigin)
+ {
+ if (errno != 0)
+ {
+ continue;
+ }
+ else
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerAMD64: origin set: " << kOrigin << std::endl;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ /// write a dword
+ else if (line.find(".dword") != std::string::npos)
+ {
+ this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line);
+ }
+ /// write a long
+ else if (line.find(".long") != std::string::npos)
+ {
+ this->WriteNumber(line.find(".long") + strlen(".long") + 1, line);
+ }
+ /// write a 16-bit number
+ else if (line.find(".word") != std::string::npos)
+ {
+ this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line);
+ }
+
+ kOrigin += kIPAlignement;
+
+ return true;
+}
+
+// Last rev 13-1-24
diff --git a/dev/LibCompiler/src/AssemblerPower.cc b/dev/LibCompiler/src/AssemblerPower.cc
new file mode 100644
index 0000000..a0b5739
--- /dev/null
+++ b/dev/LibCompiler/src/AssemblerPower.cc
@@ -0,0 +1,1096 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @file AssemblerPower.cxx
+/// @author EL Mahrouss Amlal
+/// @brief POWER Assembler.
+
+/// REMINDER: when dealing with an undefined symbol use (string
+/// size):LinkerFindSymbol:(string) so that li will look for it.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define __ASM_NEED_PPC__ 1
+
+#include <LibCompiler/NFC/ErrorID.h>
+#include <LibCompiler/AAL/CPU/power64.h>
+#include <LibCompiler/NFC/PEF.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/NFC/AE.h>
+#include <LibCompiler/Version.h>
+#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 = LibCompiler::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 LibCompiler::AERecordHeader kCurrentRecord{
+ .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0};
+
+static std::vector<LibCompiler::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);
+
+/// Do not move it on top! it uses the assembler detail namespace!
+#include <AsmUtils.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @brief POWER assembler entrypoint, the program/module starts here.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TOOLCHAINKIT_MODULE(AssemblerMainPower64)
+{
+ for (size_t i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0)
+ {
+ kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion << "\nAssemblerPower: "
+ "Copyright (c) "
+ "Theater Quality Inc\n";
+ return 0;
+ }
+ else if (strcmp(argv[i], "--h") == 0)
+ {
+ kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 "
+ "Theater Quality Inc\n";
+ kStdOut << "--version,/v: print program version.\n";
+ kStdOut << "--verbose: print verbose output.\n";
+ kStdOut << "--binary: output as flat binary.\n";
+
+ return 0;
+ }
+ else if (strcmp(argv[i], "--binary") == 0)
+ {
+ kOutputAsBinary = true;
+ continue;
+ }
+ else if (strcmp(argv[i], "--verbose") == 0)
+ {
+ kVerbose = true;
+ continue;
+ }
+
+ kStdOut << "AssemblerPower: ignore " << argv[i] << "\n";
+ continue;
+ }
+
+ if (!std::filesystem::exists(argv[i]))
+ {
+ kStdOut << "AssemblerPower: can't open: " << argv[i] << std::endl;
+ goto asm_fail_exit;
+ }
+
+ std::string object_output(argv[i]);
+
+ for (auto& ext : kAsmFileExts)
+ {
+ if (object_output.find(ext) != std::string::npos)
+ {
+ object_output.erase(object_output.find(ext), std::strlen(ext));
+ }
+ }
+
+ object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt;
+
+ std::ifstream file_ptr(argv[i]);
+ std::ofstream file_ptr_out(object_output, std::ofstream::binary);
+
+ if (file_ptr_out.bad())
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: error: " << strerror(errno) << "\n";
+ }
+ }
+
+ std::string line;
+
+ LibCompiler::AEHeader hdr{0};
+
+ memset(hdr.fPad, kAENullType, kAEPad);
+
+ hdr.fMagic[0] = kAEMag0;
+ hdr.fMagic[1] = kAEMag1;
+ hdr.fSize = sizeof(LibCompiler::AEHeader);
+ hdr.fArch = kOutputArch;
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ // COMPILATION LOOP
+
+ /////////////////////////////////////////////////////////////////////////////////////////
+
+ LibCompiler::EncoderPowerPC asm64;
+
+ while (std::getline(file_ptr, line))
+ {
+ if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty())
+ {
+ Details::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();
+ Details::print_warning("exit because of: " + what, "LibCompiler");
+ }
+
+ std::filesystem::remove(object_output);
+ goto asm_fail_exit;
+ }
+ }
+
+ if (!kOutputAsBinary)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: Writing object file...\n";
+ }
+
+ // this is the final step, write everything to the file.
+
+ auto pos = file_ptr_out.tellp();
+
+ hdr.fCount = kRecords.size() + kUndefinedSymbols.size();
+
+ file_ptr_out << hdr;
+
+ if (kRecords.empty())
+ {
+ kStdErr << "AssemblerPower: At least one record is needed to write an object "
+ "file.\nAssemblerPower: Make one using `public_segment .code64 foo_bar`.\n";
+
+ std::filesystem::remove(object_output);
+ return 1;
+ }
+
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ std::size_t record_count = 0UL;
+
+ for (auto& record_hdr : kRecords)
+ {
+ record_hdr.fFlags |= LibCompiler::kKindRelocationAtRuntime;
+ record_hdr.fOffset = record_count;
+ ++record_count;
+
+ file_ptr_out << record_hdr;
+
+ if (kVerbose)
+ kStdOut << "AssemblerPower: Wrote record " << record_hdr.fName << "...\n";
+ }
+
+ // increment once again, so that we won't lie about the kUndefinedSymbols.
+ ++record_count;
+
+ for (auto& sym : kUndefinedSymbols)
+ {
+ LibCompiler::AERecordHeader undefined_sym{0};
+
+ if (kVerbose)
+ kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n";
+
+ undefined_sym.fKind = kAENullType;
+ undefined_sym.fSize = sym.size();
+ undefined_sym.fOffset = record_count;
+
+ ++record_count;
+
+ memset(undefined_sym.fPad, kAENullType, kAEPad);
+ memcpy(undefined_sym.fName, sym.c_str(), sym.size());
+
+ file_ptr_out << undefined_sym;
+
+ ++kCounter;
+ }
+
+ auto pos_end = file_ptr_out.tellp();
+
+ file_ptr_out.seekp(pos);
+
+ hdr.fStartCode = pos_end;
+ hdr.fCodeSize = kBytes.size();
+
+ file_ptr_out << hdr;
+
+ file_ptr_out.seekp(pos_end);
+ }
+ else
+ {
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: Write raw binary...\n";
+ }
+ }
+
+ // byte from byte, we write this.
+ for (auto& byte : kBytes)
+ {
+ file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte));
+ }
+
+ if (kVerbose)
+ kStdOut << "AssemblerPower: Wrote file with program in it.\n";
+
+ file_ptr_out.flush();
+ file_ptr_out.close();
+
+ if (kVerbose)
+ kStdOut << "AssemblerPower: Exit succeeded.\n";
+
+ return 0;
+ }
+
+asm_fail_exit:
+
+ if (kVerbose)
+ kStdOut << "AssemblerPower: Exit failed.\n";
+
+ return TOOLCHAINKIT_EXEC_ERROR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for attributes
+// returns true if any was found.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool asm_read_attributes(std::string& line)
+{
+ // extern_segment is the opposite of public_segment, it signals to the li
+ // that we need this symbol.
+ if (LibCompiler::find_word(line, "extern_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid extern_segment directive in flat binary mode.",
+ "LibCompiler");
+ throw std::runtime_error("invalid_extern_segment_bin");
+ }
+
+ auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1);
+
+ if (name.size() == 0)
+ {
+ Details::print_error("Invalid extern_segment", "LibCompiler");
+ throw std::runtime_error("invalid_extern_segment");
+ }
+
+ std::string result = std::to_string(name.size());
+ result += kUndefinedSymbol;
+
+ // mangle this
+ for (char& j : name)
+ {
+ if (j == ' ' || j == ',')
+ j = '$';
+ }
+
+ result += name;
+
+ if (name.find(".code64") != std::string::npos)
+ {
+ // data is treated as code.
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+ else if (name.find(".data64") != std::string::npos)
+ {
+ // no code will be executed from here.
+ kCurrentRecord.fKind = LibCompiler::kPefData;
+ }
+ else if (name.find(".zero64") != std::string::npos)
+ {
+ // this is a bss section.
+ kCurrentRecord.fKind = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that li can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, result.c_str(), result.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+ // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to
+ // mark this section as a header. it currently supports .code64, .data64.,
+ // .zero64
+ else if (LibCompiler::find_word(line, "public_segment"))
+ {
+ if (kOutputAsBinary)
+ {
+ Details::print_error("Invalid public_segment directive in flat binary mode.",
+ "LibCompiler");
+ throw std::runtime_error("invalid_public_segment_bin");
+ }
+
+ auto name = line.substr(line.find("public_segment") + strlen("public_segment"));
+
+ std::string name_copy = name;
+
+ for (char& j : name)
+ {
+ if (j == ' ')
+ j = '$';
+ }
+
+ if (name.find(".code64") != std::string::npos)
+ {
+ // data is treated as code.
+
+ name_copy.erase(name_copy.find(".code64"), strlen(".code64"));
+ kCurrentRecord.fKind = LibCompiler::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 = LibCompiler::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 = LibCompiler::kPefZero;
+ }
+
+ // this is a special case for the start stub.
+ // we want this so that li can find it.
+
+ if (name == kPefStart)
+ {
+ kCurrentRecord.fKind = LibCompiler::kPefCode;
+ }
+
+ while (name_copy.find(" ") != std::string::npos)
+ name_copy.erase(name_copy.find(" "), 1);
+
+ kOriginLabel.push_back(std::make_pair(name_copy, kOrigin));
+ ++kOrigin;
+
+ // now we can tell the code size of the previous kCurrentRecord.
+
+ if (!kRecords.empty())
+ kRecords[kRecords.size() - 1].fSize = kBytes.size();
+
+ memset(kCurrentRecord.fName, 0, kAESymbolLen);
+ memcpy(kCurrentRecord.fName, name.c_str(), name.size());
+
+ ++kCounter;
+
+ memset(kCurrentRecord.fPad, kAENullType, kAEPad);
+
+ kRecords.emplace_back(kCurrentRecord);
+
+ return true;
+ }
+
+ return false;
+}
+
+// \brief algorithms and helpers.
+
+namespace Details::algorithm
+{
+ // \brief authorize a brief set of characters.
+ static inline bool is_not_alnum_space(char c)
+ {
+ return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') ||
+ (c == ',') || (c == '(') || (c == ')') || (c == '"') ||
+ (c == '\'') || (c == '[') || (c == ']') || (c == '+') ||
+ (c == '_') || (c == ':') || (c == '@') || (c == '.'));
+ }
+
+ bool is_valid_power64(const std::string& str)
+ {
+ return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end();
+ }
+} // namespace Details::algorithm
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief Check for line (syntax check)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::string LibCompiler::EncoderPowerPC::CheckLine(std::string& line,
+ const std::string& file)
+{
+ std::string err_str;
+
+ if (line.empty() || LibCompiler::find_word(line, "extern_segment") ||
+ LibCompiler::find_word(line, "public_segment") ||
+ line.find('#') != std::string::npos || LibCompiler::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 (!Details::algorithm::is_valid_power64(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+ }
+ }
+
+ return err_str;
+ }
+
+ if (!Details::algorithm::is_valid_power64(line))
+ {
+ err_str = "Line contains non alphanumeric characters.\nhere -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ // check for a valid instruction format.
+
+ if (line.find(',') != std::string::npos)
+ {
+ if (line.find(',') + 1 == line.size())
+ {
+ err_str += "\nInstruction lacks right register, here -> ";
+ err_str += line.substr(line.find(','));
+
+ return err_str;
+ }
+ else
+ {
+ bool nothing_on_right = true;
+
+ if (line.find(',') + 1 > line.size())
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+
+ auto substr = line.substr(line.find(',') + 1);
+
+ for (auto& ch : substr)
+ {
+ if (ch != ' ' && ch != '\t')
+ {
+ nothing_on_right = false;
+ }
+ }
+
+ // this means we found nothing after that ',' .
+ if (nothing_on_right)
+ {
+ err_str += "\nInstruction not complete, here -> ";
+ err_str += line;
+
+ return err_str;
+ }
+ }
+ }
+
+ // these do take an argument.
+ std::vector<std::string> operands_inst = {"stw", "li"};
+
+ // these don't.
+ std::vector<std::string> filter_inst = {"blr", "bl", "sc"};
+
+ for (auto& opcodePPC : kOpcodesPowerPC)
+ {
+ if (LibCompiler::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 (LibCompiler::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 LibCompiler::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)
+ {
+ Details::print_error("invalid hex number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_hex");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16));
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: found a base 16 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ return true;
+ }
+ case 'b': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid binary number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_bin");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: found a base 2 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ case 'o': {
+ if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7);
+ !res)
+ {
+ if (errno != 0)
+ {
+ Details::print_error("invalid octal number: " + jump_label, "LibCompiler");
+ throw std::runtime_error("invalid_octal");
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7));
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: found a base 8 number here: "
+ << jump_label.substr(pos) << "\n";
+ }
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ return true;
+ }
+ default: {
+ break;
+ }
+ }
+
+ /* check for errno and stuff like that */
+ if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res)
+ {
+ if (errno != 0)
+ {
+ return false;
+ }
+ }
+
+ LibCompiler::NumberCast64 num(
+ strtol(jump_label.substr(pos).c_str(), nullptr, 10));
+
+ for (char& i : num.number)
+ {
+ kBytes.push_back(i);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos)
+ << "\n";
+ }
+
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @brief Read and write an instruction to the output array.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool LibCompiler::EncoderPowerPC::WriteLine(std::string& line,
+ const std::string& file)
+{
+ if (LibCompiler::find_word(line, "public_segment"))
+ return true;
+ if (!Details::algorithm::is_valid_power64(line))
+ return true;
+
+ for (auto& opcodePPC : kOpcodesPowerPC)
+ {
+ // strict check here
+ if (LibCompiler::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];
+ Details::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)
+ {
+ Details::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)
+ {
+ Details::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)
+ {
+ Details::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)
+ {
+ Details::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)
+ {
+ Details::print_error("Too much registers. -> " + line, file);
+ throw std::runtime_error("too_much_regs");
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "AssemblerPower: Found register: " << register_syntax
+ << "\n";
+ kStdOut << "AssemblerPower: Amount of registers in instruction: "
+ << found_some_count << "\n";
+ }
+
+ if (reg_index >= 10 && reg_index < 20)
+ num.number[3] = 0x7d;
+ else if (reg_index >= 20 && reg_index < 30)
+ num.number[3] = 0x7e;
+ else if (reg_index >= 30)
+ num.number[3] = 0x7f;
+ else
+ num.number[3] = 0x7c;
+
+ for (auto ch : num.number)
+ {
+ kBytes.emplace_back(ch);
+ }
+ }
+
+ found_registers_index.push_back(reg_index);
+ }
+ }
+
+ if (opcodeName == "addi")
+ {
+ kBytes.emplace_back(0x38);
+ }
+
+ if (opcodeName.find("cmp") != std::string::npos)
+ {
+ char rightReg = 0x0;
+
+ for (size_t i = 0; i != found_registers_index[1]; i++)
+ {
+ rightReg += 0x08;
+ }
+
+ kBytes.emplace_back(0x00);
+ kBytes.emplace_back(rightReg);
+ kBytes.emplace_back(found_registers_index[0]);
+ kBytes.emplace_back(0x7c);
+ }
+
+ if ((opcodeName[0] == 's' && opcodeName[1] == 't'))
+ {
+ size_t offset = 0UL;
+
+ if (line.find('+') != std::string::npos)
+ {
+ auto number = GetNumber32(line.substr(line.find("+")), "+");
+ offset = number.raw;
+ }
+
+ kBytes.push_back(offset);
+ kBytes.push_back(0x00);
+ kBytes.push_back(register_sum);
+
+ kBytes.emplace_back(0x90);
+ }
+
+ if (opcodeName == "mr")
+ {
+ if (register_count == 1)
+ {
+ Details::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)
+ {
+ Details::print_error(
+ "Unrecognized register found.\ntip: each AssemblerPower register "
+ "starts with 'r'.\nline: " +
+ line,
+ file);
+
+ throw std::runtime_error("not_a_register");
+ }
+ }
+
+ if (found_some_count < 1 && name[0] != 'l' && name[0] != 's')
+ {
+ Details::print_error(
+ "invalid combination of opcode and registers.\nline: " + line,
+ file);
+ throw std::runtime_error("invalid_comb_op_reg");
+ }
+
+ break;
+ }
+ }
+
+ kOrigin += cPowerIPAlignment;
+ break;
+ }
+ }
+
+ return true;
+}
+
+// Last rev 13-1-24
diff --git a/dev/LibCompiler/src/AssemblyFactory.cc b/dev/LibCompiler/src/AssemblyFactory.cc
new file mode 100644
index 0000000..a0d7bd8
--- /dev/null
+++ b/dev/LibCompiler/src/AssemblyFactory.cc
@@ -0,0 +1,59 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#include <LibCompiler/AAL/AssemblyInterface.h>
+#include <LibCompiler/NFC/ErrorID.h>
+
+/**
+ * @file AssemblyFactory.cxx
+ * @author amlal (amlal@zka.com)
+ * @brief Assembler Kit
+ * @version 0.1
+ * @date 2024-01-27
+ *
+ * @copyright Copyright (c) 2024 Theater Quality Inc
+ *
+ */
+
+#include <iostream>
+
+//! @file Asm.cpp
+//! @brief AssemblyKit source implementation.
+
+namespace LibCompiler
+{
+ ///! @brief Compile for specific format (ELF, PEF, ZBIN)
+ Int32 AssemblyFactory::Compile(std::string& sourceFile,
+ const Int32& arch) noexcept
+ {
+ if (sourceFile.length() < 1 || !fMounted)
+ return TOOLCHAINKIT_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 LibCompiler
diff --git a/dev/LibCompiler/src/CCompiler64x0.cc b/dev/LibCompiler/src/CCompiler64x0.cc
new file mode 100644
index 0000000..e831401
--- /dev/null
+++ b/dev/LibCompiler/src/CCompiler64x0.cc
@@ -0,0 +1,1596 @@
+/*
+ * ========================================================
+ *
+ * cc
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/// BUGS: 0
+/// TODO: none
+
+#include <LibCompiler/AAL/CPU/64x0.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/UUID.h>
+#include <cstdio>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+
+/* C driver */
+/* This is part of the LibCompiler. */
+/* (c) Theater Quality Incorporated */
+
+/// @author EL Mahrouss Amlal (amlel)
+/// @file 64x0-cc.cxx
+/// @brief 64x0 C Compiler.
+
+/// TODO: support structures, else if, else, . and ->
+
+/////////////////////
+
+// ANSI ESCAPE CODES
+
+/////////////////////
+
+#define kExitOK (0)
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+
+/////////////////////////////////////
+
+// INTERNAL STUFF OF THE C COMPILER
+
+/////////////////////////////////////
+
+namespace Details
+{
+ // \brief Register map structure, used to keep track of each variable's registers.
+ struct CompilerRegisterMap final
+ {
+ std::string fName;
+ std::string fReg;
+ };
+
+ // \brief Map for C structs
+ // \author amlel
+ struct CompilerStructMap final
+ {
+ // 'my_foo'
+ std::string fName;
+
+ // if instance: stores a valid register.
+ std::string fReg;
+
+ // offset count
+ std::size_t fOffsetsCnt;
+
+ // offset array.
+ std::vector<std::pair<Int32, std::string>> fOffsets;
+ };
+
+ struct CompilerState final
+ {
+ std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> fOutputAssembly;
+ std::string fLastFile;
+ std::string fLastError;
+ bool fVerbose;
+ };
+} // namespace Details
+
+static Details::CompilerState kState;
+static SizeType kErrorLimit = 100;
+static std::string kIfFunction = "";
+static Int32 kAcceptableErrors = 0;
+
+namespace Details
+{
+ /// @brief prints an error into stdout.
+ /// @param reason the reason of the error.
+ /// @param file where does it originate from?
+ void print_error(std::string reason, std::string file) noexcept;
+
+ struct CompilerType final
+ {
+ std::string fName;
+ std::string fValue;
+ };
+} // namespace Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// 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 LibCompiler::AssemblyFactory kFactory;
+static bool kInStruct = false;
+static bool kOnWhileLoop = false;
+static bool kOnForLoop = false;
+static bool kInBraces = false;
+static bool kIfFound = false;
+static size_t kBracesCount = 0UL;
+
+/* @brief C compiler backend for C */
+class CompilerFrontend64x0 final : public LibCompiler::ICompilerFrontend
+{
+public:
+ explicit CompilerFrontend64x0() = default;
+ ~CompilerFrontend64x0() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(CompilerFrontend64x0);
+
+ std::string Check(const char* text, const char* file);
+ bool Compile(const std::string text, const std::string file) override;
+
+ const char* Language() override
+ {
+ return "64k C";
+ }
+};
+
+static CompilerFrontend64x0* kCompilerFrontend = nullptr;
+static std::vector<Details::CompilerType> kCompilerVariables;
+static std::vector<std::string> kCompilerFunctions;
+static std::vector<Details::CompilerType> kCompilerTypes;
+
+namespace Details
+{
+ 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 Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @name Compile
+// @brief Generate MASM from a C assignement.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool CompilerFrontend64x0::Compile(const std::string text, const std::string 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf();
+
+ auto gen = uuids::uuid_random_generator{generator};
+ uuids::uuid out = gen();
+
+ Details::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 += " extern_segment";
+ value += tmp;
+ }
+
+ syntaxLeaf.fUserValue = "\tldw r19, ";
+
+ // make it pretty.
+ if (value.find('\t') != std::string::npos)
+ value.erase(value.find('\t'), 1);
+
+ syntaxLeaf.fUserValue += value + "\n";
+ }
+
+ syntaxLeaf.fUserValue += "\tjlr";
+
+ kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
+
+ break;
+ }
+ }
+
+ if (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 = "__TOOLCHAINKIT_IF_PROC_";
+ kIfFunction += std::to_string(time_off._Raw);
+
+ syntaxLeaf.fUserValue = "\tlda r12, extern_segment ";
+ syntaxLeaf.fUserValue +=
+ kIfFunction +
+ "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq "
+ "r10, r11, r12\ndword public_segment .code64 " +
+ kIfFunction + "\n";
+ kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
+
+ kIfFound = true;
+ }
+
+ // Parse expressions and instructions here.
+ // what does this mean?
+ // we encounter an assignment, or we reached the end of an expression.
+ if (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)
+ {
+ Details::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 public_segment .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("public_segment .data64") == std::string::npos &&
+ !kInStruct)
+ substr += "public_segment .data64 ";
+ }
+
+ ++first_encountered;
+
+ continue;
+ }
+
+ if (textBuffer[text_index_2] == '=')
+ {
+ if (!kInBraces)
+ {
+ substr.replace(substr.find("public_segment .data64"),
+ strlen("public_segment .data64"), "public_segment .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"), "extern_segment ");
+
+ if (substr.find("public_segment .data64") != std::string::npos)
+ substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64"));
+ }
+
+ auto var_to_find =
+ std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(),
+ [&](Details::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 += "public_segment .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 = LibCompiler::SyntaxLeafList::SyntaxLeaf();
+ syntaxLeaf.fUserValue = "\n";
+ kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
+
+ return true;
+}
+
+static bool kShouldHaveBraces = false;
+static std::string kFnName;
+
+std::string CompilerFrontend64x0::Check(const char* text, const char* file)
+{
+ std::string err_str;
+ std::string ln = text;
+
+ if (ln.empty())
+ {
+ return err_str;
+ }
+
+ bool non_ascii_found = false;
+
+ for (int i = 0; i < ln.size(); ++i)
+ {
+ if (isalnum(ln[i]))
+ {
+ non_ascii_found = true;
+ break;
+ }
+ }
+
+ if (kShouldHaveBraces && ln.find('{') != std::string::npos)
+ {
+ kShouldHaveBraces = false;
+ }
+
+ if (!non_ascii_found)
+ return err_str;
+
+ size_t string_index = 1UL;
+
+ if (ln.find('\'') != std::string::npos)
+ {
+ string_index = ln.find('\'') + 1;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == '\'')
+ {
+ if (ln[string_index + 1] != ';')
+ {
+ ln.erase(string_index, 1);
+ }
+
+ return err_str;
+ }
+ }
+ }
+ else if (ln.find('"') != std::string::npos)
+ {
+ string_index = ln.find('"') + 1;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == '"')
+ {
+ if (ln[string_index + 1] != ';')
+ {
+ ln.erase(string_index, 1);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ else if (ln.find('"') == std::string::npos &&
+ ln.find('\'') == std::string::npos)
+ {
+ std::vector<std::string> forbidden_words;
+
+ forbidden_words.push_back("\\");
+ forbidden_words.push_back("?");
+ forbidden_words.push_back("@");
+ forbidden_words.push_back("~");
+ forbidden_words.push_back("::");
+ forbidden_words.push_back("--*");
+ forbidden_words.push_back("*/");
+
+ // add them to avoid stupid mistakes.
+ forbidden_words.push_back("namespace");
+ forbidden_words.push_back("class");
+ forbidden_words.push_back("extern \"C\"");
+
+ for (auto& forbidden : forbidden_words)
+ {
+ if (ln.find(forbidden) != std::string::npos)
+ {
+ err_str += "\nForbidden character detected: ";
+ err_str += forbidden;
+
+ return err_str;
+ }
+ }
+ }
+
+ struct CompilerVariableRange final
+ {
+ std::string fBegin;
+ std::string fEnd;
+ };
+
+ const std::vector<CompilerVariableRange> variables_list = {
+ {.fBegin = "static ", .fEnd = "="},
+ {.fBegin = "=", .fEnd = ";"},
+ {.fBegin = "if(", .fEnd = "="},
+ {.fBegin = "if (", .fEnd = "="},
+ {.fBegin = "if(", .fEnd = "<"},
+ {.fBegin = "if (", .fEnd = "<"},
+ {.fBegin = "if(", .fEnd = ">"},
+ {.fBegin = "if (", .fEnd = ">"},
+ {.fBegin = "if(", .fEnd = ")"},
+ {.fBegin = "if (", .fEnd = ")"},
+
+ {.fBegin = "else(", .fEnd = "="},
+ {.fBegin = "else (", .fEnd = "="},
+ {.fBegin = "else(", .fEnd = "<"},
+ {.fBegin = "else (", .fEnd = "<"},
+ {.fBegin = "else(", .fEnd = ">"},
+ {.fBegin = "else (", .fEnd = ">"},
+ {.fBegin = "else(", .fEnd = ")"},
+ {.fBegin = "else (", .fEnd = ")"},
+ };
+
+ for (auto& variable : variables_list)
+ {
+ if (ln.find(variable.fBegin) != std::string::npos)
+ {
+ string_index = ln.find(variable.fBegin) + variable.fBegin.size();
+
+ while (ln[string_index] == ' ')
+ ++string_index;
+
+ std::string keyword;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == variable.fEnd[0])
+ {
+ std::string varname = "";
+
+ for (size_t index_keyword = ln.find(' ');
+ ln[index_keyword] != variable.fBegin[0]; ++index_keyword)
+ {
+ if (ln[index_keyword] == ' ')
+ {
+ continue;
+ }
+
+ if (isdigit(ln[index_keyword]))
+ {
+ goto cc_next_loop;
+ }
+
+ varname += ln[index_keyword];
+ }
+
+ if (varname.find(' ') != std::string::npos)
+ {
+ varname.erase(0, varname.find(' '));
+
+ if (variable.fBegin == "extern")
+ {
+ varname.erase(0, varname.find(' '));
+ }
+ }
+
+ if (kRegisterCounter == 5 || kRegisterCounter == 6)
+ ++kRegisterCounter;
+
+ std::string reg = kAsmRegisterPrefix;
+ reg += std::to_string(kRegisterCounter);
+
+ kCompilerVariables.push_back({.fValue = varname});
+ goto cc_check_done;
+ }
+
+ keyword.push_back(ln[string_index]);
+ }
+
+ goto cc_next_loop;
+
+ cc_check_done:
+
+ // skip digit value.
+ if (isdigit(keyword[0]) || keyword[0] == '"')
+ {
+ goto cc_next_loop;
+ }
+
+ while (keyword.find(' ') != std::string::npos)
+ keyword.erase(keyword.find(' '), 1);
+
+ for (auto& var : kCompilerVariables)
+ {
+ if (var.fValue.find(keyword) != std::string::npos)
+ {
+ err_str.clear();
+ goto cc_next;
+ }
+ }
+
+ for (auto& fn : kCompilerFunctions)
+ {
+ if (fn.find(keyword[0]) != std::string::npos)
+ {
+ auto where_begin = fn.find(keyword[0]);
+ auto keyword_begin = 0UL;
+ auto failed = false;
+
+ for (; where_begin < keyword.size(); ++where_begin)
+ {
+ if (fn[where_begin] == '(' && keyword[keyword_begin] == '(')
+ break;
+
+ if (fn[where_begin] != keyword[keyword_begin])
+ {
+ failed = true;
+ break;
+ }
+
+ ++keyword_begin;
+ }
+
+ if (!failed)
+ {
+ err_str.clear();
+ goto cc_next;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ }
+
+ cc_error_value:
+ if (keyword.find("->") != std::string::npos)
+ return err_str;
+
+ if (keyword.find(".") != std::string::npos)
+ return err_str;
+
+ if (isalnum(keyword[0]))
+ err_str += "\nUndefined value: " + keyword;
+
+ return err_str;
+ }
+
+ cc_next_loop:
+ continue;
+ }
+
+cc_next:
+
+ // extern does not declare anything, it extern_segments a variable.
+ // so that's why it's not declare upper.
+ if (LibCompiler::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 (LibCompiler::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 && !LibCompiler::find_word(ln, "|") &&
+ !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") &&
+ !LibCompiler::find_word(ln, "&&") && !LibCompiler::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 ASSEMBLY_INTERFACE
+{
+public:
+ explicit AssemblyCCInterface() = default;
+ ~AssemblyCCInterface() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(AssemblyCCInterface);
+
+ [[maybe_unused]] static Int32 Arch() noexcept
+ {
+ return LibCompiler::AssemblyFactory::kArch64x0;
+ }
+
+ Int32 CompileToFormat(std::string& src, Int32 arch) override
+ {
+ if (arch != AssemblyCCInterface::Arch())
+ return 1;
+
+ if (kCompilerFrontend == nullptr)
+ return 1;
+
+ /* @brief copy contents wihtout extension */
+ std::string src_file = src.data();
+ std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
+ std::string dest;
+
+ for (auto& ch : src_file)
+ {
+ if (ch == '.')
+ {
+ break;
+ }
+
+ dest += ch;
+ }
+
+ /* According to PEF ABI. */
+ std::vector<const char*> exts = kAsmFileExts;
+ dest += exts[4];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(dest);
+
+ auto fmt = LibCompiler::current_date();
+
+ (*kState.fOutputAssembly) << "# Path: " << src_file << "\n";
+ (*kState.fOutputAssembly)
+ << "# Language: 64x0 Assembly (Generated from ANSI C)\n";
+ (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n";
+
+ LibCompiler::SyntaxLeafList syntax;
+
+ kState.fSyntaxTreeList.push_back(syntax);
+ kState.fSyntaxTree =
+ &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1];
+
+ std::string line_src;
+
+ while (std::getline(src_fp, line_src))
+ {
+ if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data());
+ err.empty())
+ {
+ kCompilerFrontend->Compile(line_src, src.data());
+ }
+ else
+ {
+ Details::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 (LibCompiler::find_word(leaf.fUserValue, access_ident))
+ {
+ for (auto& struc : kState.kStructMap)
+ {
+ /// TODO:
+ }
+ }
+ }
+
+ for (auto& keyword : keywords)
+ {
+ if (LibCompiler::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 (LibCompiler::find_word(leaf.fUserValue, needle))
+ {
+ if (leaf.fUserValue.find("extern_segment " + needle) !=
+ std::string::npos)
+ {
+ std::string range = "extern_segment " + needle;
+ leaf.fUserValue.replace(
+ leaf.fUserValue.find("extern_segment " + needle), range.size(),
+ needle);
+ }
+
+ if (leaf.fUserValue.find("ldw r6") != std::string::npos)
+ {
+ std::string::difference_type countComma = std::count(
+ leaf.fUserValue.begin(), leaf.fUserValue.end(), ',');
+
+ if (countComma == 1)
+ {
+ leaf.fUserValue.replace(leaf.fUserValue.find("ldw"),
+ strlen("ldw"), "mv");
+ }
+ }
+
+ leaf.fUserValue.replace(leaf.fUserValue.find(needle),
+ needle.size(), reg.fReg);
+
+ ++cnt;
+ }
+ }
+
+ if (cnt > 1 && keyword != "mv" && keyword != "add" &&
+ keyword != "sub")
+ {
+ leaf.fUserValue.replace(leaf.fUserValue.find(keyword),
+ keyword.size(), "mv");
+ }
+ }
+ }
+ }
+
+ for (auto& leaf : kState.fSyntaxTree->fLeafList)
+ {
+ (*kState.fOutputAssembly) << leaf.fUserValue;
+ }
+
+ kState.fSyntaxTree = nullptr;
+
+ kState.fOutputAssembly->flush();
+ kState.fOutputAssembly.reset();
+
+ return kExitOK;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Version.h>
+
+#define kPrintF printf
+#define kSplashCxx() \
+ kPrintF(kWhite "ZKA C Driver, %s, (c) Theater Quality Incorporated\n", kDistVersion)
+
+static void cc_print_help()
+{
+ kSplashCxx();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define kExt ".c"
+
+TOOLCHAINKIT_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 = LibCompiler::AssemblyFactory::kArch64x0;
+ kCompilerFrontend = new CompilerFrontend64x0();
+
+ for (auto index = 1UL; index < argc; ++index)
+ {
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
+
+ if (argv[index][0] == '-')
+ {
+ if (strcmp(argv[index], "--v") == 0 ||
+ strcmp(argv[index], "--version") == 0)
+ {
+ kSplashCxx();
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--verbose") == 0)
+ {
+ kState.fVerbose = true;
+
+ continue;
+ }
+
+ if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0)
+ {
+ cc_print_help();
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--dialect") == 0)
+ {
+ if (kCompilerFrontend)
+ std::cout << kCompilerFrontend->Language() << "\n";
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--fmax-exceptions") == 0)
+ {
+ try
+ {
+ kErrorLimit = std::strtol(argv[index + 1], nullptr, 10);
+ }
+ // catch anything here
+ catch (...)
+ {
+ kErrorLimit = 0;
+ }
+
+ skip = true;
+
+ continue;
+ }
+
+ std::string err = "Unknown command: ";
+ err += argv[index];
+
+ Details::print_error(err, "cc");
+
+ continue;
+ }
+
+ kFileList.emplace_back(argv[index]);
+
+ std::string srcFile = argv[index];
+
+ if (strstr(argv[index], kExt) == nullptr)
+ {
+ if (kState.fVerbose)
+ {
+ Details::print_error(srcFile + " is not a valid C source.\n", "cc");
+ }
+
+ return 1;
+ }
+
+ if (kFactory.Compile(srcFile, kMachine) != kExitOK)
+ return 1;
+ }
+
+ return kExitOK;
+}
+
+// Last rev 8-1-24
diff --git a/dev/LibCompiler/src/CCompilerPower64.cc b/dev/LibCompiler/src/CCompilerPower64.cc
new file mode 100644
index 0000000..99a3d0f
--- /dev/null
+++ b/dev/LibCompiler/src/CCompilerPower64.cc
@@ -0,0 +1,1616 @@
+/*
+ * ========================================================
+ *
+ * CCompilerPower64
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+#include <LibCompiler/AAL/CPU/power64.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/UUID.h>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+#include <cstdio>
+
+#define kExitOK 0
+
+/// @author EL Mahrouss Amlal (amlel)
+/// @file cc.cxx
+/// @brief POWER64 C Compiler.
+
+/////////////////////
+
+/// ANSI ESCAPE CODES
+
+/////////////////////
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+
+/////////////////////////////////////
+
+/// INTERNAL STRUCTURES OF THE C COMPILER
+
+/////////////////////////////////////
+
+namespace Details
+{
+ // \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<LibCompiler::SyntaxLeafList> fSyntaxTreeList;
+ std::vector<CompilerRegisterMap> kStackFrame;
+ std::vector<CompilerStructMap> kStructMap;
+ LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> fOutputAssembly;
+ std::string fLastFile;
+ std::string fLastError;
+ bool fVerbose;
+ };
+} // namespace Details
+
+static Details::CompilerState kState;
+static SizeType kErrorLimit = 100;
+static std::string kIfFunction = "";
+static Int32 kAcceptableErrors = 0;
+
+namespace Details
+{
+ /// @brief prints an error into stdout.
+ /// @param reason the reason of the error.
+ /// @param file where does it originate from?
+ void print_error(std::string reason, std::string file) noexcept;
+
+ struct CompilerType final
+ {
+ std::string fName;
+ std::string fValue;
+ };
+} // namespace Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// 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 LibCompiler::AssemblyFactory kFactory;
+static bool kInStruct = false;
+static bool kOnWhileLoop = false;
+static bool kOnForLoop = false;
+static bool kInBraces = false;
+static bool kIfFound = false;
+static size_t kBracesCount = 0UL;
+
+/* @brief C compiler backend for C */
+class CompilerFrontendPower64 final : public LibCompiler::ICompilerFrontend
+{
+public:
+ explicit CompilerFrontendPower64() = default;
+ ~CompilerFrontendPower64() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(CompilerFrontendPower64);
+
+ std::string Check(const char* text, const char* file);
+ bool Compile(const std::string text, const std::string file) override;
+
+ const char* Language() override
+ {
+ return "POWER C";
+ }
+};
+
+static CompilerFrontendPower64* kCompilerFrontend = nullptr;
+static std::vector<Details::CompilerType> kCompilerVariables;
+static std::vector<std::string> kCompilerFunctions;
+static std::vector<Details::CompilerType> kCompilerTypes;
+
+namespace Details
+{
+ 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 Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @name Compile
+// @brief Generate MASM from a C assignement.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool CompilerFrontendPower64::Compile(const std::string text, const std::string 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf();
+
+ auto gen = uuids::uuid_random_generator{generator};
+ uuids::uuid out = gen();
+
+ Details::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 += " extern_segment";
+ 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("extern_segment") != std::string::npos)
+ value.erase(value.find("extern_segment"), strlen("extern_segment"));
+
+ bool found = false;
+
+ for (auto& reg : kState.kStackFrame)
+ {
+ if (value.find(reg.fName) != std::string::npos)
+ {
+ found = true;
+ 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 = "__TOOLCHAINKIT_IF_PROC_";
+ kIfFunction += std::to_string(time_off._Raw);
+
+ syntaxLeaf.fUserValue =
+ "\tcmpw "
+ "r10, r11";
+
+ syntaxLeaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction +
+ " \ndword public_segment .code64 " + kIfFunction + "\n";
+
+ kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
+
+ kIfFound = true;
+ }
+
+ // Parse expressions and instructions here.
+ // what does this mean?
+ // we encounter an assignment, or we reached the end of an expression.
+ if (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)
+ {
+ Details::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 public_segment .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("public_segment .data64") == std::string::npos &&
+ !kInStruct)
+ substr += "public_segment .data64 ";
+ }
+
+ ++first_encountered;
+
+ continue;
+ }
+
+ if (textBuffer[text_index_2] == '=')
+ {
+ if (!kInBraces)
+ {
+ substr.replace(substr.find("public_segment .data64"),
+ strlen("public_segment .data64"), "public_segment .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"), "extern_segment ");
+
+ if (substr.find("public_segment .data64") != std::string::npos)
+ substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64"));
+ }
+
+ auto var_to_find =
+ std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(),
+ [&](Details::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 += "public_segment .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 = LibCompiler::SyntaxLeafList::SyntaxLeaf();
+ syntaxLeaf.fUserValue = "\n";
+ kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf);
+
+ return true;
+}
+
+static bool kShouldHaveBraces = false;
+static std::string kFnName;
+
+std::string CompilerFrontendPower64::Check(const char* text, const char* file)
+{
+ std::string err_str;
+ std::string ln = text;
+
+ if (ln.empty())
+ {
+ return err_str;
+ }
+
+ bool non_ascii_found = false;
+
+ for (int i = 0; i < ln.size(); ++i)
+ {
+ if (isalnum(ln[i]))
+ {
+ non_ascii_found = true;
+ break;
+ }
+ }
+
+ if (kShouldHaveBraces && ln.find('{') != std::string::npos)
+ {
+ kShouldHaveBraces = false;
+ }
+
+ if (!non_ascii_found)
+ return err_str;
+
+ size_t string_index = 1UL;
+
+ if (ln.find('\'') != std::string::npos)
+ {
+ string_index = ln.find('\'') + 1;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == '\'')
+ {
+ if (ln[string_index + 1] != ';')
+ {
+ ln.erase(string_index, 1);
+ }
+
+ return err_str;
+ }
+ }
+ }
+ else if (ln.find('"') != std::string::npos)
+ {
+ string_index = ln.find('"') + 1;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == '"')
+ {
+ if (ln[string_index + 1] != ';')
+ {
+ ln.erase(string_index, 1);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ else if (ln.find('"') == std::string::npos &&
+ ln.find('\'') == std::string::npos)
+ {
+ std::vector<std::string> forbidden_words;
+
+ forbidden_words.push_back("\\");
+ forbidden_words.push_back("?");
+ forbidden_words.push_back("@");
+ forbidden_words.push_back("~");
+ forbidden_words.push_back("::");
+ forbidden_words.push_back("--*");
+ forbidden_words.push_back("*/");
+
+ // add them to avoid stupid mistakes.
+ forbidden_words.push_back("namespace");
+ forbidden_words.push_back("class");
+ forbidden_words.push_back("extern \"C\"");
+
+ for (auto& forbidden : forbidden_words)
+ {
+ if (ln.find(forbidden) != std::string::npos)
+ {
+ err_str += "\nForbidden character detected: ";
+ err_str += forbidden;
+
+ return err_str;
+ }
+ }
+ }
+
+ struct CompilerVariableRange final
+ {
+ std::string fBegin;
+ std::string fEnd;
+ };
+
+ const std::vector<CompilerVariableRange> variables_list = {
+ {.fBegin = "static ", .fEnd = "="},
+ {.fBegin = "=", .fEnd = ";"},
+ {.fBegin = "if(", .fEnd = "="},
+ {.fBegin = "if (", .fEnd = "="},
+ {.fBegin = "if(", .fEnd = "<"},
+ {.fBegin = "if (", .fEnd = "<"},
+ {.fBegin = "if(", .fEnd = ">"},
+ {.fBegin = "if (", .fEnd = ">"},
+ {.fBegin = "if(", .fEnd = ")"},
+ {.fBegin = "if (", .fEnd = ")"},
+
+ {.fBegin = "else(", .fEnd = "="},
+ {.fBegin = "else (", .fEnd = "="},
+ {.fBegin = "else(", .fEnd = "<"},
+ {.fBegin = "else (", .fEnd = "<"},
+ {.fBegin = "else(", .fEnd = ">"},
+ {.fBegin = "else (", .fEnd = ">"},
+ {.fBegin = "else(", .fEnd = ")"},
+ {.fBegin = "else (", .fEnd = ")"},
+ };
+
+ for (auto& variable : variables_list)
+ {
+ if (ln.find(variable.fBegin) != std::string::npos)
+ {
+ string_index = ln.find(variable.fBegin) + variable.fBegin.size();
+
+ while (ln[string_index] == ' ')
+ ++string_index;
+
+ std::string keyword;
+
+ for (; string_index < ln.size(); ++string_index)
+ {
+ if (ln[string_index] == variable.fEnd[0])
+ {
+ std::string varname = "";
+
+ for (size_t index_keyword = ln.find(' ');
+ ln[index_keyword] != variable.fBegin[0]; ++index_keyword)
+ {
+ if (ln[index_keyword] == ' ')
+ {
+ continue;
+ }
+
+ if (isdigit(ln[index_keyword]))
+ {
+ goto cc_next_loop;
+ }
+
+ varname += ln[index_keyword];
+ }
+
+ if (varname.find(' ') != std::string::npos)
+ {
+ varname.erase(0, varname.find(' '));
+
+ if (variable.fBegin == "extern")
+ {
+ varname.erase(0, varname.find(' '));
+ }
+ }
+
+ if (kRegisterCounter == 5 || kRegisterCounter == 6)
+ ++kRegisterCounter;
+
+ std::string reg = kAsmRegisterPrefix;
+ reg += std::to_string(kRegisterCounter);
+
+ kCompilerVariables.push_back({.fValue = varname});
+ goto cc_check_done;
+ }
+
+ keyword.push_back(ln[string_index]);
+ }
+
+ goto cc_next_loop;
+
+ cc_check_done:
+
+ // skip digit value.
+ if (isdigit(keyword[0]) || keyword[0] == '"')
+ {
+ goto cc_next_loop;
+ }
+
+ while (keyword.find(' ') != std::string::npos)
+ keyword.erase(keyword.find(' '), 1);
+
+ for (auto& var : kCompilerVariables)
+ {
+ if (var.fValue.find(keyword) != std::string::npos)
+ {
+ err_str.clear();
+ goto cc_next;
+ }
+ }
+
+ for (auto& fn : kCompilerFunctions)
+ {
+ if (fn.find(keyword[0]) != std::string::npos)
+ {
+ auto where_begin = fn.find(keyword[0]);
+ auto keyword_begin = 0UL;
+ auto failed = false;
+
+ for (; where_begin < keyword.size(); ++where_begin)
+ {
+ if (fn[where_begin] == '(' && keyword[keyword_begin] == '(')
+ break;
+
+ if (fn[where_begin] != keyword[keyword_begin])
+ {
+ failed = true;
+ break;
+ }
+
+ ++keyword_begin;
+ }
+
+ if (!failed)
+ {
+ err_str.clear();
+ goto cc_next;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ }
+
+ cc_error_value:
+ if (keyword.find("->") != std::string::npos)
+ return err_str;
+
+ if (keyword.find(".") != std::string::npos)
+ return err_str;
+
+ if (isalnum(keyword[0]))
+ err_str += "\nUndefined value: " + keyword;
+
+ return err_str;
+ }
+
+ cc_next_loop:
+ continue;
+ }
+
+cc_next:
+
+ // extern does not declare anything, it extern_segments a variable.
+ // so that's why it's not declare upper.
+ if (LibCompiler::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 (LibCompiler::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 && !LibCompiler::find_word(ln, "|") &&
+ !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") &&
+ !LibCompiler::find_word(ln, "&&") && !LibCompiler::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 ASSEMBLY_INTERFACE
+{
+public:
+ explicit AssemblyMountpointCLang() = default;
+ ~AssemblyMountpointCLang() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(AssemblyMountpointCLang);
+
+ [[maybe_unused]] static Int32 Arch() noexcept
+ {
+ return LibCompiler::AssemblyFactory::kArchPowerPC;
+ }
+
+ Int32 CompileToFormat(std::string& src, Int32 arch) override
+ {
+ if (arch != AssemblyMountpointCLang::Arch())
+ return 1;
+
+ if (kCompilerFrontend == nullptr)
+ return 1;
+
+ /* @brief copy contents wihtout extension */
+ std::string src_file = src.data();
+ std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
+ std::string dest;
+
+ for (auto& ch : src_file)
+ {
+ if (ch == '.')
+ {
+ break;
+ }
+
+ dest += ch;
+ }
+
+ /* According to PEF ABI. */
+ std::vector<const char*> exts = kAsmFileExts;
+ dest += exts[4];
+
+ kState.fOutputAssembly = std::make_unique<std::ofstream>(dest);
+
+ auto fmt = LibCompiler::current_date();
+
+ (*kState.fOutputAssembly) << "# Path: " << src_file << "\n";
+ (*kState.fOutputAssembly)
+ << "# Language: POWER Assembly (Generated from C)\n";
+ (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n";
+
+ LibCompiler::SyntaxLeafList syntax;
+
+ kState.fSyntaxTreeList.push_back(syntax);
+ kState.fSyntaxTree =
+ &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1];
+
+ std::string line_src;
+
+ while (std::getline(src_fp, line_src))
+ {
+ if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data());
+ err.empty())
+ {
+ kCompilerFrontend->Compile(line_src, src.data());
+ }
+ else
+ {
+ Details::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 (LibCompiler::find_word(leaf.fUserValue, access_ident))
+ {
+ for (auto& struc : kState.kStructMap)
+ {
+ /// TODO:
+ }
+ }
+ }
+
+ for (auto& keyword : keywords)
+ {
+ if (LibCompiler::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 (LibCompiler::find_word(leaf.fUserValue, needle))
+ {
+ if (leaf.fUserValue.find("extern_segment ") != std::string::npos)
+ {
+ std::string range = "extern_segment ";
+ leaf.fUserValue.replace(leaf.fUserValue.find(range),
+ range.size(), "");
+ }
+
+ if (leaf.fUserValue.find("ldw r6") != std::string::npos)
+ {
+ std::string::difference_type countComma = std::count(
+ leaf.fUserValue.begin(), leaf.fUserValue.end(), ',');
+
+ if (countComma == 1)
+ {
+ leaf.fUserValue.replace(leaf.fUserValue.find("ldw"),
+ strlen("ldw"), "mr");
+ }
+ }
+
+ leaf.fUserValue.replace(leaf.fUserValue.find(needle),
+ needle.size(), reg.fReg);
+
+ ++cnt;
+ }
+ }
+
+ if (cnt > 1 && keyword != "mr" && keyword != "add" &&
+ keyword != "dec")
+ {
+ leaf.fUserValue.replace(leaf.fUserValue.find(keyword),
+ keyword.size(), "mr");
+ }
+ }
+ }
+ }
+
+ for (auto& leaf : kState.fSyntaxTree->fLeafList)
+ {
+ (*kState.fOutputAssembly) << leaf.fUserValue;
+ }
+
+ kState.fSyntaxTree = nullptr;
+
+ kState.fOutputAssembly->flush();
+ kState.fOutputAssembly.reset();
+
+ return kExitOK;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Version.h>
+
+#define kPrintF printf
+#define kSplashCxx() \
+ kPrintF(kWhite "cc, %s, (c) Theater Quality Incorporated\n", kDistVersion)
+
+static void cc_print_help()
+{
+ kSplashCxx();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define kExt ".c"
+
+TOOLCHAINKIT_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 = LibCompiler::AssemblyFactory::kArchPowerPC;
+ kCompilerFrontend = new CompilerFrontendPower64();
+
+ for (auto index = 1UL; index < argc; ++index)
+ {
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
+
+ if (argv[index][0] == '-')
+ {
+ if (strcmp(argv[index], "-v") == 0 ||
+ strcmp(argv[index], "-version") == 0)
+ {
+ kSplashCxx();
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "-verbose") == 0)
+ {
+ kState.fVerbose = true;
+
+ continue;
+ }
+
+ if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0)
+ {
+ cc_print_help();
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "-dialect") == 0)
+ {
+ if (kCompilerFrontend)
+ std::cout << kCompilerFrontend->Language() << "\n";
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "-fmax-exceptions") == 0)
+ {
+ try
+ {
+ kErrorLimit = std::strtol(argv[index + 1], nullptr, 10);
+ }
+ // catch anything here
+ catch (...)
+ {
+ kErrorLimit = 0;
+ }
+
+ skip = true;
+
+ continue;
+ }
+
+ std::string err = "Unknown command: ";
+ err += argv[index];
+
+ Details::print_error(err, "cc");
+
+ continue;
+ }
+
+ kFileList.emplace_back(argv[index]);
+
+ std::string srcFile = argv[index];
+
+ if (strstr(argv[index], kExt) == nullptr)
+ {
+ if (kState.fVerbose)
+ {
+ Details::print_error(srcFile + " is not a valid C source.\n", "cc");
+ }
+
+ return 1;
+ }
+
+ if (kFactory.Compile(srcFile, kMachine) != kExitOK)
+ return 1;
+ }
+
+ return kExitOK;
+}
+
+// Last rev 8-1-24
diff --git a/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc b/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc
new file mode 100644
index 0000000..0de1b06
--- /dev/null
+++ b/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc
@@ -0,0 +1,1091 @@
+/*
+ * ========================================================
+ *
+ * c++-drv
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/// BUGS: 1
+
+#include <cstdio>
+#define kPrintF printf
+
+#define kExitOK (EXIT_SUCCESS)
+#define kExitNO (EXIT_FAILURE)
+
+#define kSplashCxx() \
+ kPrintF(kWhite "%s\n", "TQ Media C++ Compiler Driver, (c) 2024 Theater Quality Incorporated, all rights reserved.")
+
+// extern_segment, @autodelete { ... }, fn foo() -> auto { ... }
+
+#include <LibCompiler/AAL/CPU/amd64.h>
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/UUID.h>
+
+/* ZKA C++ Compiler */
+/* This is part of the LibCompiler. */
+/* (c) Theater Quality Incorporated */
+
+/// @author EL Mahrouss Amlal (amlel)
+/// @file CPlusPlusCompilerAMD64.cxx
+/// @brief Optimized C++ Compiler Driver.
+/// @todo Throw error for scoped inside scoped variables when they get referenced outside.
+/// @todo Add class/struct/enum support.
+
+///////////////////////
+
+// ANSI ESCAPE CODES //
+
+///////////////////////
+
+#define kBlank "\e[0;30m"
+#define kRed "\e[0;31m"
+#define kWhite "\e[0;97m"
+
+/////////////////////////////////////
+
+// INTERNALS OF THE C++ COMPILER
+
+/////////////////////////////////////
+
+/// @internal
+namespace Details
+{
+ std::filesystem::path expand_home(const std::filesystem::path& p)
+ {
+ if (!p.empty() && p.string()[0] == '~')
+ {
+ const char* home = std::getenv("HOME"); // For Unix-like systems
+ if (!home)
+ {
+ home = std::getenv("USERPROFILE"); // For Windows
+ }
+ if (home)
+ {
+ return std::filesystem::path(home) / p.relative_path().string().substr(1);
+ }
+ else
+ {
+ throw std::runtime_error("Home directory not found in environment variables");
+ }
+ }
+ return p;
+ }
+
+ struct CompilerRegisterMap final
+ {
+ 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<CompilerRegisterMap> fStackMapVector;
+ std::vector<CompilerStructMap> fStructMapVector;
+ LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr};
+ std::unique_ptr<std::ofstream> fOutputAssembly;
+ std::string fLastFile;
+ std::string fLastError;
+ bool fVerbose;
+ };
+} // namespace Details
+
+static Details::CompilerState kState;
+static SizeType kErrorLimit = 100;
+
+static Int32 kAcceptableErrors = 0;
+
+namespace Details
+{
+ /// @brief prints an error into stdout.
+ /// @param reason the reason of the error.
+ /// @param file where does it originate from?
+ void print_error(std::string reason, std::string file) noexcept;
+
+ struct CompilerType final
+ {
+ std::string fName;
+ std::string fValue;
+ };
+} // namespace Details
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// Target architecture.
+static int kMachine = LibCompiler::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<LibCompiler::CompilerKeyword> kKeywords;
+
+/////////////////////////////////////////
+
+// COMPILER PARSING UTILITIES/STATES.
+
+/////////////////////////////////////////
+
+static std::vector<std::string> kFileList;
+static LibCompiler::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 CompilerFrontendCPlusPlus final : public LibCompiler::ICompilerFrontend
+{
+public:
+ explicit CompilerFrontendCPlusPlus() = default;
+ ~CompilerFrontendCPlusPlus() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(CompilerFrontendCPlusPlus);
+
+ bool Compile(const std::string text, const std::string file) override;
+
+ const char* Language() override;
+};
+
+/// @internal compiler variables
+
+static CompilerFrontendCPlusPlus* kCompilerFrontend = nullptr;
+
+static std::vector<std::string> kRegisterMap;
+
+static std::vector<std::string> kRegisterList = {
+ "rbx",
+ "rsi",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+ "xmm12",
+ "xmm13",
+ "xmm14",
+ "xmm15",
+};
+
+/// @brief The PEF calling convention (caller must save rax, rbp)
+/// @note callee must return via **rax**.
+static std::vector<std::string> kRegisterConventionCallList = {
+ "r8",
+ "r9",
+ "r10",
+ "r11",
+ "r12",
+ "r13",
+ "r14",
+ "r15",
+};
+
+static std::size_t kFunctionEmbedLevel = 0UL;
+
+/// detail namespaces
+
+const char* CompilerFrontendCPlusPlus::Language()
+{
+ return "ZKA C++";
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/// @name Compile
+/// @brief Generate assembly from a C++ source.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool CompilerFrontendCPlusPlus::Compile(const std::string text,
+ const std::string file)
+{
+ if (text.empty())
+ return false;
+
+ std::size_t index = 0UL;
+ std::vector<std::pair<LibCompiler::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 LibCompiler::eKeywordKindCommentMultiLineStart: {
+ commentBlock = true;
+ return true;
+ }
+ case LibCompiler::eKeywordKindCommentMultiLineEnd: {
+ commentBlock = false;
+ break;
+ }
+ case LibCompiler::eKeywordKindCommentInline: {
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (text[text.find(keyword.keyword_name) - 1] == '+' &&
+ keyword.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableAssign)
+ continue;
+
+ if (text[text.find(keyword.keyword_name) - 1] == '-' &&
+ keyword.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableAssign)
+ continue;
+
+ if (text[text.find(keyword.keyword_name) + 1] == '=' &&
+ keyword.keyword_kind == LibCompiler::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]))
+ {
+ Details::print_error("syntax error: " + text, file);
+ return false;
+ }
+ }
+ }
+
+ for (auto& keyword : keywords_list)
+ {
+ auto syntax_tree = LibCompiler::SyntaxLeafList::SyntaxLeaf();
+
+ switch (keyword.first.keyword_kind)
+ {
+ case LibCompiler::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 " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n";
+ syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + kRegisterList[indexRight + 1] + "\n";
+
+ goto done_iterarting_on_if;
+ }
+
+ auto& valueOfVarOpposite = isdigit(left[0]) ? left : right;
+
+ syntax_tree.fUserValue += "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n";
+ syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + kRegisterList[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_ON_TRUE_NDK\nsegment .code64 __OFFSET_ON_TRUE_NDK:\n";
+ }
+
+ break;
+ }
+ case LibCompiler::KeywordKind::eKeywordKindFunctionStart: {
+ for (auto& ch : text)
+ {
+ if (isdigit(ch))
+ {
+ goto dont_accept;
+ }
+ }
+
+ goto accept;
+
+ dont_accept:
+ return false;
+
+ accept:
+ std::string fnName = text;
+ size_t indexFnName = 0;
+
+ // this one is for the type.
+ for (auto& ch : text)
+ {
+ ++indexFnName;
+
+ if (ch == '\t')
+ break;
+
+ if (ch == ' ')
+ break;
+ }
+
+ fnName = text.substr(indexFnName);
+
+ if (text.ends_with(";"))
+ goto tk_write_assembly;
+ else if (text.size() <= indexFnName)
+ Details::print_error("Invalid function name: " + fnName, file);
+
+ indexFnName = 0;
+
+ for (auto& ch : fnName)
+ {
+ if (ch == ' ' ||
+ ch == '\t')
+ {
+ if (fnName[indexFnName - 1] != ')')
+ Details::print_error("Invalid function name: " + fnName, file);
+
+ if ((indexFnName + 1) != fnName.size())
+ Details::print_error("Extra characters after function name: " + fnName, file);
+ }
+
+ ++indexFnName;
+ }
+
+ syntax_tree.fUserValue = "public_segment .code64 __TOOLCHAINKIT_" + fnName + "\n";
+ ++kFunctionEmbedLevel;
+
+ break;
+
+tk_write_assembly:
+ syntax_tree.fUserValue = "jmp __TOOLCHAINKIT_" + fnName + "\n";
+ }
+ case LibCompiler::KeywordKind::eKeywordKindFunctionEnd: {
+ if (text.ends_with(";"))
+ break;
+
+ --kFunctionEmbedLevel;
+
+ if (kRegisterMap.size() > kRegisterList.size())
+ {
+ --kFunctionEmbedLevel;
+ }
+
+ if (kFunctionEmbedLevel < 1)
+ kRegisterMap.clear();
+ break;
+ }
+ case LibCompiler::KeywordKind::eKeywordKindEndInstr:
+ case LibCompiler::KeywordKind::eKeywordKindVariableInc:
+ case LibCompiler::KeywordKind::eKeywordKindVariableDec:
+ case LibCompiler::KeywordKind::eKeywordKindVariableAssign: {
+ std::string valueOfVar = "";
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableInc)
+ {
+ valueOfVar = text.substr(text.find("+=") + 2);
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableDec)
+ {
+ valueOfVar = text.substr(text.find("-=") + 2);
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableAssign)
+ {
+ valueOfVar = text.substr(text.find("=") + 1);
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindEndInstr)
+ {
+ break;
+ }
+
+ while (valueOfVar.find(";") != std::string::npos &&
+ keyword.first.keyword_kind != LibCompiler::KeywordKind::eKeywordKindEndInstr)
+ {
+ valueOfVar.erase(valueOfVar.find(";"));
+ }
+
+ std::string varName = text;
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableInc)
+ {
+ varName.erase(varName.find("+="));
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableDec)
+ {
+ varName.erase(varName.find("-="));
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableAssign)
+ {
+ varName.erase(varName.find("="));
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindEndInstr)
+ {
+ varName.erase(varName.find(";"));
+ }
+
+ static bool typeFound = false;
+
+ for (auto& keyword : kKeywords)
+ {
+ if (keyword.keyword_kind == LibCompiler::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 && keyword.first.keyword_kind != LibCompiler::KeywordKind::eKeywordKindVariableInc &&
+ keyword.first.keyword_kind != LibCompiler::KeywordKind::eKeywordKindVariableDec)
+ {
+ if (kRegisterMap.size() > kRegisterList.size())
+ {
+ ++kFunctionEmbedLevel;
+ }
+
+ 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)
+ {
+ if (valueOfVar[0] == '\"')
+ {
+
+ syntax_tree.fUserValue = "segment .data64 __TOOLCHAINKIT_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n\n";
+ syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + "__TOOLCHAINKIT_LOCAL_VAR_" + varName + "\n";
+ }
+ else
+ {
+ syntax_tree.fUserValue = instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n";
+ }
+
+ goto done;
+ }
+ }
+
+ if (((int)indexRight - 1) < 0)
+ {
+ if (valueOfVar[0] == '\"')
+ {
+
+ syntax_tree.fUserValue = "segment .data64 __TOOLCHAINKIT_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n";
+ syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + "__TOOLCHAINKIT_LOCAL_VAR_" + varName + "\n";
+ }
+ else
+ {
+ syntax_tree.fUserValue = instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n";
+ }
+
+ goto done;
+ }
+
+ if (valueOfVar[0] != '\"' &&
+ valueOfVar[0] != '\'' &&
+ !isdigit(valueOfVar[0]))
+ {
+ for (auto pair : kRegisterMap)
+ {
+ if (pair == valueOfVar)
+ goto done;
+ }
+
+ Details::print_error("Variable not declared: " + varName, file);
+ return false;
+ }
+
+ done:
+ for (auto& keyword : kKeywords)
+ {
+ if (keyword.keyword_kind == LibCompiler::eKeywordKindType &&
+ varName.find(keyword.keyword_name) != std::string::npos)
+ {
+ varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size());
+ break;
+ }
+ }
+
+ kRegisterMap.push_back(varName);
+
+ break;
+ }
+
+ if (kKeywords[keyword.second - 1].keyword_kind == LibCompiler::eKeywordKindType ||
+ kKeywords[keyword.second - 1].keyword_kind == LibCompiler::eKeywordKindTypePtr)
+ {
+ syntax_tree.fUserValue = "\n";
+ continue;
+ }
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindEndInstr)
+ {
+ syntax_tree.fUserValue = "\n";
+ continue;
+ }
+
+ if (keyword.first.keyword_kind == LibCompiler::KeywordKind::eKeywordKindVariableInc)
+ {
+ instr = "add ";
+ }
+ else if (keyword.first.keyword_kind == LibCompiler::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 + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n";
+ continue;
+ }
+
+ syntax_tree.fUserValue = instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n";
+ break;
+ }
+
+ break;
+ }
+
+ if (syntax_tree.fUserValue.empty())
+ {
+ Details::print_error("Variable not declared: " + varErrCpy, file);
+ }
+
+ break;
+ }
+ case LibCompiler::KeywordKind::eKeywordKindReturn: {
+ try
+ {
+ 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," + kRegisterList[indxReg - 1] + "\r\nret\n";
+ break;
+ }
+
+ if (syntax_tree.fUserValue.empty())
+ {
+ Details::print_error("Variable not declared: " + subText, file);
+ }
+ }
+ else
+ {
+ syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n";
+ }
+ }
+ else
+ {
+ syntax_tree.fUserValue = "__TOOLCHAINKIT_LOCAL_RETURN_STRING: db " + subText + ", 0\nmov rcx, __TOOLCHAINKIT_LOCAL_RETURN_STRING\n";
+ syntax_tree.fUserValue += "mov rax, rcx\r\nret\n";
+ }
+
+ break;
+ }
+ catch (...)
+ {
+ syntax_tree.fUserValue = "ret\n";
+ }
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ syntax_tree.fUserData = keyword.first;
+ kState.fSyntaxTree->fLeafList.push_back(syntax_tree);
+ }
+
+ndk_compile_ok:
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief C++ assembler class.
+ */
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class AssemblyCPlusPlusInterface final ASSEMBLY_INTERFACE
+{
+public:
+ explicit AssemblyCPlusPlusInterface() = default;
+ ~AssemblyCPlusPlusInterface() override = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(AssemblyCPlusPlusInterface);
+
+ [[maybe_unused]] static Int32 Arch() noexcept
+ {
+ return LibCompiler::AssemblyFactory::kArchAMD64;
+ }
+
+ Int32 CompileToFormat(std::string& src, Int32 arch) override
+ {
+ if (arch != AssemblyCPlusPlusInterface::Arch())
+ return 1;
+
+ if (kCompilerFrontend == nullptr)
+ return 1;
+
+ /* @brief copy contents wihtout extension */
+ std::string src_file = src;
+ std::ifstream src_fp = std::ifstream(src_file, std::ios::in);
+
+ const char* cExts[] = kAsmFileExts;
+
+ std::string dest = src_file;
+ dest += cExts[2];
+
+ if (dest.empty())
+ {
+ dest = "CXX-LibCompiler-";
+
+ 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 = LibCompiler::current_date();
+
+ (*kState.fOutputAssembly) << "; Repository Path: /" << src_file << "\n";
+
+ std::filesystem::path path = std::filesystem::path("./");
+
+ while (path != Details::expand_home(std::filesystem::path("~")))
+ {
+ for (auto const& dir_entry : std::filesystem::recursive_directory_iterator{path})
+ {
+ if (dir_entry.is_directory() &&
+ dir_entry.path().string().find(".git") != std::string::npos)
+ goto break_loop;
+ }
+
+ path = path.parent_path();
+ break_loop:
+ (*kState.fOutputAssembly) << "; Repository Style: Git\n";
+ break;
+ }
+
+ (*kState.fOutputAssembly)
+ << "; Assembler Dialect: AMD64 LibCompiler Assembler. (Generated from C++)\n";
+ (*kState.fOutputAssembly) << "; Date: " << fmt << "\n";
+ (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000"
+ << "\n";
+
+ kState.fSyntaxTree = new LibCompiler::SyntaxLeafList();
+
+ // ===================================
+ // Parse source file.
+ // ===================================
+
+ std::string line_source;
+
+ while (std::getline(src_fp, line_source))
+ {
+ kCompilerFrontend->Compile(line_source, src);
+ }
+
+ for (auto& ast_generated : kState.fSyntaxTree->fLeafList)
+ {
+ (*kState.fOutputAssembly) << ast_generated.fUserValue;
+ }
+
+ kState.fOutputAssembly->flush();
+ kState.fOutputAssembly->close();
+
+ delete kState.fSyntaxTree;
+ kState.fSyntaxTree = nullptr;
+
+ if (kAcceptableErrors > 0)
+ return 1;
+
+ return kExitOK;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void cxx_print_help()
+{
+ kSplashCxx();
+ kPrintF("%s", "No help available, see:\n");
+ kPrintF("%s", "www.zws.zka.com/help/c++lang\n");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define kExtListCxx \
+ { \
+ ".cpp", ".cxx", ".cc", ".c++", ".cp" \
+ }
+
+TOOLCHAINKIT_MODULE(CompilerCPlusPlusX8664)
+{
+ bool skip = false;
+
+ kKeywords.push_back({.keyword_name = "if", .keyword_kind = LibCompiler::eKeywordKindIf});
+ kKeywords.push_back({.keyword_name = "else", .keyword_kind = LibCompiler::eKeywordKindElse});
+ kKeywords.push_back({.keyword_name = "else if", .keyword_kind = LibCompiler::eKeywordKindElseIf});
+
+ kKeywords.push_back({.keyword_name = "class", .keyword_kind = LibCompiler::eKeywordKindClass});
+ kKeywords.push_back({.keyword_name = "struct", .keyword_kind = LibCompiler::eKeywordKindClass});
+ kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = LibCompiler::eKeywordKindNamespace});
+ kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = LibCompiler::eKeywordKindTypedef});
+ kKeywords.push_back({.keyword_name = "using", .keyword_kind = LibCompiler::eKeywordKindTypedef});
+ kKeywords.push_back({.keyword_name = "{", .keyword_kind = LibCompiler::eKeywordKindBodyStart});
+ kKeywords.push_back({.keyword_name = "}", .keyword_kind = LibCompiler::eKeywordKindBodyEnd});
+ kKeywords.push_back({.keyword_name = "auto", .keyword_kind = LibCompiler::eKeywordKindVariable});
+ kKeywords.push_back({.keyword_name = "int", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "bool", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "short", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "char", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "long", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "float", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "double", .keyword_kind = LibCompiler::eKeywordKindType});
+ kKeywords.push_back({.keyword_name = "void", .keyword_kind = LibCompiler::eKeywordKindType});
+
+ kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = LibCompiler::eKeywordKindVariablePtr});
+ kKeywords.push_back({.keyword_name = "int*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "short*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "char*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "long*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "float*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "double*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+ kKeywords.push_back({.keyword_name = "void*", .keyword_kind = LibCompiler::eKeywordKindTypePtr});
+
+ kKeywords.push_back({.keyword_name = "(", .keyword_kind = LibCompiler::eKeywordKindFunctionStart});
+ kKeywords.push_back({.keyword_name = ")", .keyword_kind = LibCompiler::eKeywordKindFunctionEnd});
+ kKeywords.push_back({.keyword_name = "=", .keyword_kind = LibCompiler::eKeywordKindVariableAssign});
+ kKeywords.push_back({.keyword_name = "+=", .keyword_kind = LibCompiler::eKeywordKindVariableInc});
+ kKeywords.push_back({.keyword_name = "-=", .keyword_kind = LibCompiler::eKeywordKindVariableDec});
+ kKeywords.push_back({.keyword_name = "const", .keyword_kind = LibCompiler::eKeywordKindConstant});
+ kKeywords.push_back({.keyword_name = "*", .keyword_kind = LibCompiler::eKeywordKindPtr});
+ kKeywords.push_back({.keyword_name = "->", .keyword_kind = LibCompiler::eKeywordKindPtrAccess});
+ kKeywords.push_back({.keyword_name = ".", .keyword_kind = LibCompiler::eKeywordKindAccess});
+ kKeywords.push_back({.keyword_name = ",", .keyword_kind = LibCompiler::eKeywordKindArgSeparator});
+ kKeywords.push_back({.keyword_name = ";", .keyword_kind = LibCompiler::eKeywordKindEndInstr});
+ kKeywords.push_back({.keyword_name = ":", .keyword_kind = LibCompiler::eKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "public:", .keyword_kind = LibCompiler::eKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "private:", .keyword_kind = LibCompiler::eKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = LibCompiler::eKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "final", .keyword_kind = LibCompiler::eKeywordKindSpecifier});
+ kKeywords.push_back({.keyword_name = "return", .keyword_kind = LibCompiler::eKeywordKindReturn});
+ kKeywords.push_back({.keyword_name = "--*", .keyword_kind = LibCompiler::eKeywordKindCommentMultiLineStart});
+ kKeywords.push_back({.keyword_name = "*/", .keyword_kind = LibCompiler::eKeywordKindCommentMultiLineStart});
+ kKeywords.push_back({.keyword_name = "--/", .keyword_kind = LibCompiler::eKeywordKindCommentInline});
+ kKeywords.push_back({.keyword_name = "==", .keyword_kind = LibCompiler::eKeywordKindEq});
+ kKeywords.push_back({.keyword_name = "!=", .keyword_kind = LibCompiler::eKeywordKindNotEq});
+ kKeywords.push_back({.keyword_name = ">=", .keyword_kind = LibCompiler::eKeywordKindGreaterEq});
+ kKeywords.push_back({.keyword_name = "<=", .keyword_kind = LibCompiler::eKeywordKindLessEq});
+
+ kFactory.Mount(new AssemblyCPlusPlusInterface());
+ kCompilerFrontend = new CompilerFrontendCPlusPlus();
+
+ for (auto index = 1UL; index < argc; ++index)
+ {
+ if (argv[index][0] == '-')
+ {
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
+
+ if (strcmp(argv[index], "--cl:version") == 0)
+ {
+ kSplashCxx();
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--cl:verbose") == 0)
+ {
+ kState.fVerbose = true;
+
+ continue;
+ }
+
+ if (strcmp(argv[index], "--cl:h") == 0)
+ {
+ cxx_print_help();
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--cl:c++-dialect") == 0)
+ {
+ if (kCompilerFrontend)
+ std::cout << kCompilerFrontend->Language() << "\n";
+
+ return kExitOK;
+ }
+
+ if (strcmp(argv[index], "--cl:max-err") == 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];
+
+ Details::print_error(err, "c++-drv");
+
+ 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)
+ {
+ Details::print_error(argv_i + " is not a valid C++ source.\n", "c++-drv");
+ }
+
+ return 1;
+ }
+
+ std::cout << "CPlusPlusCompilerAMD64: Building: " << argv[index] << std::endl;
+
+ if (kFactory.Compile(argv_i, kMachine) != kExitOK)
+ return 1;
+ }
+
+ return kExitOK;
+}
+
+// Last rev 8-1-24
+//
diff --git a/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc b/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc
new file mode 100644
index 0000000..819cfc7
--- /dev/null
+++ b/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc
@@ -0,0 +1,1070 @@
+/*
+ * ========================================================
+ *
+ * bpp
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/// BUGS: 0
+
+#include <LibCompiler/Parser.h>
+#include <LibCompiler/NFC/ErrorID.h>
+#include <algorithm>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <stdexcept>
+#include <vector>
+
+#define kMacroPrefix '#'
+
+/// @author EL Mahrouss Amlal (amlel)
+/// @file bpp.cxx
+/// @brief Preprocessor.
+
+typedef Int32 (*bpp_parser_fn_t)(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;
+
+ void Print()
+ {
+ std::cout << "name: " << fName << "\n";
+ std::cout << "value: " << fValue << "\n";
+
+ for (auto& arg : fArgs)
+ {
+ std::cout << "arg: " << arg << "\n";
+ }
+ }
+ };
+
+ class bpp_pragma final
+ {
+ public:
+ explicit bpp_pragma() = default;
+ ~bpp_pragma() = default;
+
+ TOOLCHAINKIT_COPY_DEFAULT(bpp_pragma);
+
+ std::string fMacroName;
+ bpp_parser_fn_t fParse;
+ };
+} // namespace Details
+
+static std::vector<std::string> kFiles;
+static std::vector<Details::bpp_macro> kMacros;
+static std::vector<std::string> kIncludes;
+
+static std::string kWorkingDir;
+
+static std::vector<std::string> kKeywords = {
+ "include", "if", "pragma", "def", "elif",
+ "ifdef", "ifndef", "else", "warning", "error"};
+
+#define kKeywordCxxCnt kKeywords.size()
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @name bpp_parse_if_condition
+// @brief parse #if condition
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int32_t bpp_parse_if_condition(Details::bpp_macro_condition& cond,
+ Details::bpp_macro& macro,
+ bool& inactive_code,
+ bool& defined,
+ std::string& macro_str)
+{
+ if (cond.fType == Details::kEqual)
+ {
+ auto substr_macro =
+ macro_str.substr(macro_str.find(macro.fName) + macro.fName.size());
+
+ if (substr_macro.find(macro.fValue) != std::string::npos)
+ {
+ if (macro.fValue == "0")
+ {
+ defined = false;
+ inactive_code = true;
+
+ return 1;
+ }
+
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+ }
+ else if (cond.fType == Details::kNotEqual)
+ {
+ auto substr_macro =
+ macro_str.substr(macro_str.find(macro.fName) + macro.fName.size());
+
+ if (substr_macro.find(macro.fName) != std::string::npos)
+ {
+ if (substr_macro.find(macro.fValue) != std::string::npos)
+ {
+ defined = false;
+ inactive_code = true;
+
+ return 1;
+ }
+
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ auto substr_macro =
+ macro_str.substr(macro_str.find(macro.fName) + macro.fName.size());
+
+ std::string number;
+
+ for (auto& macro_num : kMacros)
+ {
+ if (substr_macro.find(macro_num.fName) != std::string::npos)
+ {
+ for (size_t i = 0; i < macro_num.fName.size(); ++i)
+ {
+ if (isdigit(macro_num.fValue[i]))
+ {
+ number += macro_num.fValue[i];
+ }
+ else
+ {
+ number.clear();
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ size_t y = 2;
+
+ /* last try */
+ for (; y < macro_str.size(); y++)
+ {
+ if (isdigit(macro_str[y]))
+ {
+ for (size_t x = y; x < macro_str.size(); x++)
+ {
+ if (macro_str[x] == ' ')
+ break;
+
+ number += macro_str[x];
+ }
+
+ break;
+ }
+ }
+
+ size_t rhs = atol(macro.fValue.c_str());
+ size_t lhs = atol(number.c_str());
+
+ if (lhs == 0)
+ {
+ number.clear();
+ ++y;
+
+ for (; y < macro_str.size(); y++)
+ {
+ if (isdigit(macro_str[y]))
+ {
+ for (size_t x = y; x < macro_str.size(); x++)
+ {
+ if (macro_str[x] == ' ')
+ break;
+
+ number += macro_str[x];
+ }
+
+ break;
+ }
+ }
+
+ lhs = atol(number.c_str());
+ }
+
+ if (cond.fType == Details::kGreaterThan)
+ {
+ if (lhs < rhs)
+ {
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (cond.fType == Details::kGreaterEqThan)
+ {
+ if (lhs <= rhs)
+ {
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (cond.fType == Details::kLesserEqThan)
+ {
+ if (lhs >= rhs)
+ {
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (cond.fType == Details::kLesserThan)
+ {
+ if (lhs > rhs)
+ {
+ defined = true;
+ inactive_code = false;
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @brief stores every included file here.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+std::vector<std::string> kAllIncludes;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+// @name bpp_parse_file
+// @brief parse file to preprocess it.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out)
+{
+ std::string hdr_line;
+ std::string line_after_include;
+
+ bool inactive_code = false;
+ bool defined = false;
+
+ try
+ {
+ while (std::getline(hdr_file, hdr_line))
+ {
+ if (inactive_code)
+ {
+ if (hdr_line.find("#endif") == std::string::npos)
+ {
+ continue;
+ }
+ else if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("#endif") != std::string::npos)
+ {
+
+ inactive_code = false;
+ }
+
+ if (hdr_line.find("*/") != std::string::npos)
+ {
+ continue;
+ }
+ }
+
+ if (hdr_line.find("--/") != std::string::npos)
+ {
+ hdr_line.erase(hdr_line.find("--/"));
+ }
+
+ if (hdr_line.find("--*") != std::string::npos)
+ {
+ inactive_code = true;
+ // get rid of comment.
+ hdr_line.erase(hdr_line.find("--*"));
+ }
+
+ /// BPP 'brief' documentation.
+ if (hdr_line.find("@brief") != std::string::npos)
+ {
+ hdr_line.erase(hdr_line.find("@brief"));
+
+ // TODO: Write an <file_name>.html or append to it.
+ }
+
+ 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 (LibCompiler::find_word(hdr_line, macro.fName))
+ {
+ if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != LibCompiler::String::npos)
+ {
+ if (!macro.fArgs.empty())
+ {
+ LibCompiler::String symbol_val = macro.fValue;
+ std::vector<LibCompiler::String> args;
+
+ size_t x_arg_indx = 0;
+
+ LibCompiler::String line_after_define = hdr_line;
+ LibCompiler::String str_arg;
+
+ if (line_after_define.find("(") != LibCompiler::String::npos)
+ {
+ line_after_define.erase(0, line_after_define.find("(") + 1);
+
+ for (auto& subc : line_after_define)
+ {
+ if (subc == ' ' || subc == '\t')
+ continue;
+
+ if (subc == ',' || subc == ')')
+ {
+ if (str_arg.empty())
+ continue;
+
+ args.push_back(str_arg);
+
+ str_arg.clear();
+
+ continue;
+ }
+
+ str_arg.push_back(subc);
+ }
+ }
+
+ for (auto arg : macro.fArgs)
+ {
+ if (symbol_val.find(macro.fArgs[x_arg_indx]) != LibCompiler::String::npos)
+ {
+ symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), macro.fArgs[x_arg_indx].size(),
+ args[x_arg_indx]);
+ ++x_arg_indx;
+ }
+ else
+ {
+ throw std::runtime_error("internal: Internal C++ error. (Please report that bug.)");
+ }
+ }
+
+ auto len = macro.fName.size();
+ len += symbol_val.size();
+ len += 2; // ( and )
+
+ hdr_line.erase(hdr_line.find(")"), 1);
+
+ hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), len,
+ symbol_val);
+ }
+ else
+ {
+ auto value = macro.fValue;
+
+ hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(),
+ value);
+ }
+ }
+ }
+ }
+
+ if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("define ") != std::string::npos)
+ {
+ auto line_after_define =
+ hdr_line.substr(hdr_line.find("define ") + strlen("define "));
+
+ 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::string str;
+
+ if (line_after_define.find("(") != LibCompiler::String::npos)
+ {
+ line_after_define.erase(0, line_after_define.find("(") + 1);
+
+ for (auto& subc : line_after_define)
+ {
+ if (subc == ',' || subc == ')')
+ {
+ if (str.empty())
+ continue;
+
+ args.push_back(str);
+
+ str.clear();
+
+ continue;
+ }
+
+ str.push_back(subc);
+ }
+ }
+
+ 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;
+ }
+
+ pp_out << hdr_line << std::endl;
+
+ continue;
+ }
+
+ if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("ifndef") != std::string::npos)
+ {
+ auto line_after_ifndef =
+ hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1);
+ std::string macro;
+
+ for (auto& ch : line_after_ifndef)
+ {
+ if (ch == ' ')
+ {
+ break;
+ }
+
+ macro += ch;
+ }
+
+ if (macro == "0")
+ {
+ defined = true;
+ inactive_code = false;
+ continue;
+ }
+
+ if (macro == "1")
+ {
+ defined = false;
+ inactive_code = true;
+
+ continue;
+ }
+
+ bool found = false;
+
+ defined = true;
+ inactive_code = false;
+
+ for (auto& macro_ref : kMacros)
+ {
+ if (hdr_line.find(macro_ref.fName) != std::string::npos)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ defined = false;
+ inactive_code = true;
+
+ continue;
+ }
+ }
+ else if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("else") != std::string::npos)
+ {
+ if (!defined && inactive_code)
+ {
+ inactive_code = false;
+ defined = true;
+
+ continue;
+ }
+ else
+ {
+ defined = false;
+ inactive_code = true;
+
+ continue;
+ }
+ }
+ else if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("ifdef") != std::string::npos)
+ {
+ auto line_after_ifdef =
+ hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1);
+ std::string macro;
+
+ for (auto& ch : line_after_ifdef)
+ {
+ if (ch == ' ')
+ {
+ break;
+ }
+
+ macro += ch;
+ }
+
+ if (macro == "0")
+ {
+ defined = false;
+ inactive_code = true;
+
+ continue;
+ }
+
+ if (macro == "1")
+ {
+ defined = true;
+ inactive_code = false;
+
+ continue;
+ }
+
+ defined = false;
+ inactive_code = true;
+
+ for (auto& macro_ref : kMacros)
+ {
+ if (hdr_line.find(macro_ref.fName) != std::string::npos)
+ {
+ defined = true;
+ inactive_code = false;
+
+ break;
+ }
+ }
+ }
+ else if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("if") != std::string::npos)
+ {
+ inactive_code = true;
+
+ std::vector<Details::bpp_macro_condition> bpp_macro_condition_list = {
+ {
+ .fType = Details::kEqual,
+ .fTypeName = "==",
+ },
+ {
+ .fType = Details::kNotEqual,
+ .fTypeName = "!=",
+ },
+ {
+ .fType = Details::kLesserThan,
+ .fTypeName = "<",
+ },
+ {
+ .fType = Details::kGreaterThan,
+ .fTypeName = ">",
+ },
+ {
+ .fType = Details::kLesserEqThan,
+ .fTypeName = "<=",
+ },
+ {
+ .fType = Details::kGreaterEqThan,
+ .fTypeName = ">=",
+ },
+ };
+
+ int32_t good_to_go = 0;
+
+ for (auto& macro_condition : bpp_macro_condition_list)
+ {
+ if (hdr_line.find(macro_condition.fTypeName) != std::string::npos)
+ {
+ for (auto& found_macro : kMacros)
+ {
+ if (hdr_line.find(found_macro.fName) != std::string::npos)
+ {
+ good_to_go =
+ bpp_parse_if_condition(macro_condition, found_macro,
+ inactive_code, defined, hdr_line);
+
+ break;
+ }
+ }
+ }
+ }
+
+ if (good_to_go)
+ continue;
+
+ auto line_after_if =
+ hdr_line.substr(hdr_line.find("if") + strlen("if") + 1);
+ std::string macro;
+
+ for (auto& ch : line_after_if)
+ {
+ if (ch == ' ')
+ {
+ break;
+ }
+
+ macro += ch;
+ }
+
+ if (macro == "0")
+ {
+ defined = false;
+ inactive_code = true;
+ continue;
+ }
+
+ if (macro == "1")
+ {
+ defined = true;
+ inactive_code = false;
+
+ continue;
+ }
+
+ // last try, is it defined to be one?
+ for (auto& macro_ref : kMacros)
+ {
+ if (macro_ref.fName.find(macro) != std::string::npos &&
+ macro_ref.fValue == "1")
+ {
+ inactive_code = false;
+ defined = true;
+
+ break;
+ }
+ }
+ }
+ else if (hdr_line[0] == kMacroPrefix &&
+ hdr_line.find("warning") != std::string::npos)
+ {
+ auto line_after_warning =
+ hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1);
+ std::string message;
+
+ for (auto& ch : line_after_warning)
+ {
+ if (ch == '\r' || ch == '\n')
+ {
+ break;
+ }
+
+ message += ch;
+ }
+
+ std::cout << "warn: " << 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("include ") != std::string::npos)
+ {
+ line_after_include =
+ hdr_line.substr(hdr_line.find("include ") + strlen("include "));
+
+ kIncludeFile:
+ auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(),
+ line_after_include);
+
+ if (it != kAllIncludes.cend())
+ {
+ continue;
+ }
+
+ 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 == '\"')
+ {
+ not_local = false;
+ enable = true;
+ continue;
+ }
+
+ if (enable)
+ {
+ path += ch;
+ }
+ }
+
+ if (not_local)
+ {
+ bool open = false;
+
+ if (path.ends_with('>'))
+ {
+ path.erase(path.find('>'));
+ }
+
+ if (path.ends_with('"'))
+ {
+ path.erase(path.find('"'));
+ }
+
+ for (auto& include : kIncludes)
+ {
+ 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(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.
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TOOLCHAINKIT_MODULE(CPlusPlusPreprocessorMain)
+{
+ 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_zka;
+
+ macro_zka.fName = "__TOOLCHAINKIT__";
+ macro_zka.fValue = "1";
+
+ kMacros.push_back(macro_zka);
+
+ Details::bpp_macro macro_size_t;
+ macro_size_t.fName = "__SIZE_TYPE__";
+ macro_size_t.fValue = "unsigned long long int";
+
+ kMacros.push_back(macro_size_t);
+
+ macro_size_t.fName = "__UINT32_TYPE__";
+ macro_size_t.fValue = "unsigned int";
+
+ kMacros.push_back(macro_size_t);
+
+ macro_size_t.fName = "__UINTPTR_TYPE__";
+ macro_size_t.fValue = "unsigned int";
+
+ kMacros.push_back(macro_size_t);
+
+ for (auto index = 1UL; index < argc; ++index)
+ {
+ if (skip)
+ {
+ skip = false;
+ continue;
+ }
+
+ if (double_skip)
+ {
+ ++index;
+ double_skip = false;
+ continue;
+ }
+
+ if (argv[index][0] == '-')
+ {
+ if (strcmp(argv[index], "--bpp:ver") == 0)
+ {
+ printf("%s\n", "bpp v1.11, (c) Theater Quality Incorporated");
+ return 0;
+ }
+
+ if (strcmp(argv[index], "--bpp:?") == 0)
+ {
+ printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) Theater Quality Incorporated");
+ printf("%s\n", "--bpp:working-dir <path>: set directory to working path.");
+ printf("%s\n", "--bpp:include-dir <path>: add directory to include path.");
+ printf("%s\n", "--bpp:def <name> <value>: define a macro.");
+ printf("%s\n", "--bpp:ver: print the version.");
+ printf("%s\n", "--bpp:?: show help (this current command).");
+
+ return 0;
+ }
+
+ if (strcmp(argv[index], "--bpp:include-dir") == 0)
+ {
+ std::string inc = argv[index + 1];
+
+ skip = true;
+
+ kIncludes.push_back(inc);
+ }
+
+ if (strcmp(argv[index], "--bpp:working-dir") == 0)
+ {
+ std::string inc = argv[index + 1];
+ skip = true;
+ kWorkingDir = inc;
+ }
+
+ if (strcmp(argv[index], "--bpp: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 TOOLCHAINKIT_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/dev/LibCompiler/src/Detail/AsmUtils.h b/dev/LibCompiler/src/Detail/AsmUtils.h
new file mode 100644
index 0000000..0825fa5
--- /dev/null
+++ b/dev/LibCompiler/src/Detail/AsmUtils.h
@@ -0,0 +1,116 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/AAL/AssemblyInterface.h>
+#include <LibCompiler/Parser.h>
+
+using namespace LibCompiler;
+
+namespace Details
+{
+ extern void print_error(std::string reason, std::string file) noexcept;
+ extern void print_warning(std::string reason, std::string file) noexcept;
+} // namespace Details
+
+/// @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();
+
+ 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)
+ {
+ Details::print_error("invalid hex number: " + lineBuffer, "LibCompiler");
+ 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)
+ {
+ Details::print_error("invalid binary number:" + lineBuffer, "LibCompiler");
+ 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)
+ {
+ Details::print_error("invalid octal number: " + lineBuffer, "LibCompiler");
+ 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)
+ {
+ Details::print_error("invalid hex number: " + lineBuffer, "LibCompiler");
+ 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/dev/LibCompiler/src/Detail/ClUtils.h b/dev/LibCompiler/src/Detail/ClUtils.h
new file mode 100644
index 0000000..4596148
--- /dev/null
+++ b/dev/LibCompiler/src/Detail/ClUtils.h
@@ -0,0 +1,14 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+------------------------------------------- */
+
+#pragma once
+
+#include <LibCompiler/AAL/AssemblyInterface.h>
+#include <LibCompiler/Parser.h>
+
+#define kZero64Section ".zero64"
+#define kCode64Section ".code64"
+#define kData64Section ".data64"
diff --git a/dev/LibCompiler/src/Detail/ReadMe.md b/dev/LibCompiler/src/Detail/ReadMe.md
new file mode 100644
index 0000000..e9d0a2c
--- /dev/null
+++ b/dev/LibCompiler/src/Detail/ReadMe.md
@@ -0,0 +1,3 @@
+# Compiler utilities.
+
+A list of headers used to make compiler/assemblers.
diff --git a/dev/LibCompiler/src/DynamicLinker64PEF.cc b/dev/LibCompiler/src/DynamicLinker64PEF.cc
new file mode 100644
index 0000000..67b6105
--- /dev/null
+++ b/dev/LibCompiler/src/DynamicLinker64PEF.cc
@@ -0,0 +1,774 @@
+/* -------------------------------------------
+
+ Copyright (C) 2024 Theater Quality Inc, all rights reserved
+
+ @file DynamicLinker64PEF.cc
+ @brief: C++ 64-Bit PEF Linker.
+
+------------------------------------------- */
+
+/// @author EL Mahrouss Amlal (amlel)
+/// @brief TQ Media 64-bit PEF Linker.
+/// Last Rev: Sat Feb 24 CET 2024
+/// @note Do not look up for anything with .code64/.data64/.zero64!
+/// It will be loaded when the program loader will start the image.
+
+//! Toolchain Kit.
+#include <LibCompiler/Defines.h>
+
+#include <LibCompiler/NFC/ErrorID.h>
+
+//! Assembler Kit
+#include <LibCompiler/AAL/AssemblyInterface.h>
+
+//! Preferred Executable Format
+#include <LibCompiler/NFC/PEF.h>
+#include <LibCompiler/UUID.h>
+
+//! Release macros.
+#include <LibCompiler/Version.h>
+
+//! Advanced Executable Object Format.
+#include <LibCompiler/NFC/AE.h>
+#include <cstdint>
+
+#define kLinkerVersionStr "TQ Media 64-Bit Linker %s, (c) Theater Quality Incorporated 2024, all rights reserved.\n"
+
+#define MemoryCopy(DST, SRC, SZ) memcpy(DST, SRC, SZ)
+#define StringCompare(DST, SRC) strcmp(DST, SRC)
+
+#define kPefNoCpu 0U
+#define kPefNoSubCpu 0U
+
+#define kWhite "\e[0;97m"
+
+#define kStdOut (std::cout << kWhite << "ld64: ")
+
+#define kLinkerDefaultOrigin kPefBaseOrigin
+#define kLinkerId (0x5046FF)
+#define kLinkerAbiContainer "Container:ABI:"
+
+/// @brief PEF stack size symbol.
+#define kLinkerStackSizeSymbol "SizeOfReserveStack"
+
+namespace Details
+{
+struct DynamicLinkerBlob final
+{
+ std::vector<CharType> fPefBlob; // PEF code/bss/data blob.
+ std::uintptr_t fAEOffset; // the offset of the PEF container header..
+};
+}
+
+enum
+{
+ kABITypeStart = 0x1010, /* Invalid ABI start of ABI list. */
+ kABITypeZKA = 0x5046, /* PF (ZKA PEF ABI) */
+ kABITypeInvalid = 0xFFFF,
+};
+
+static LibCompiler::String kOutput = "";
+static Int32 kAbi = kABITypeZKA;
+static Int32 kSubArch = kPefNoSubCpu;
+static Int32 kArch = LibCompiler::kPefArchInvalid;
+static Bool kFatBinaryEnable = false;
+static Bool kStartFound = false;
+static Bool kDuplicateSymbols = false;
+static Bool kVerbose = false;
+
+/* ld64 is to be found, mld is to be found at runtime. */
+static const char* kLdDefineSymbol = ":UndefinedSymbol:";
+static const char* kLdDynamicSym = ":RuntimeSymbol:";
+
+/* object code and list. */
+static std::vector<LibCompiler::String> kObjectList;
+static std::vector<Details::DynamicLinkerBlob> kObjectBytes;
+
+static uintptr_t kMIBCount = 8;
+static uintptr_t kByteCount = 1024;
+
+#define kPrintF printf
+#define kLinkerSplash() kPrintF(kWhite kLinkerVersionStr, kDistVersion)
+
+/// @brief ZKA 64-bit Linker.
+/// @note This linker is made for PEF executable, thus ZKA based OSes.
+TOOLCHAINKIT_MODULE(DynamicLinker64PEF)
+{
+ bool is_executable = true;
+
+ /**
+ * @brief parse flags and trigger options.
+ */
+ for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg)
+ {
+ if (StringCompare(argv[linker_arg], "--ld64:help") == 0)
+ {
+ kLinkerSplash();
+
+ kStdOut << "--ld64:ver: Show linker version.\n";
+ kStdOut << "--ld64:?: Show linker help.\n";
+ kStdOut << "--ld64:verbose: Enable linker trace.\n";
+ kStdOut << "--ld64:dylib: Output as a Dylib PEF.\n";
+ kStdOut << "--ld64:fat: Output as a FAT PEF.\n";
+ kStdOut << "--ld64:32k: Output as a 32x0 PEF.\n";
+ kStdOut << "--ld64:64k: Output as a 64x0 PEF.\n";
+ kStdOut << "--ld64:amd64: Output as a AMD64 PEF.\n";
+ kStdOut << "--ld64:rv64: Output as a RISC-V PEF.\n";
+ kStdOut << "--ld64:power64: Output as a POWER PEF.\n";
+ kStdOut << "--ld64:arm64: Output as a ARM64 PEF.\n";
+ kStdOut << "--ld64:output: Select the output file name.\n";
+
+ return EXIT_SUCCESS;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:version") == 0)
+ {
+ kLinkerSplash();
+ return EXIT_SUCCESS;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:fat-binary") == 0)
+ {
+ kFatBinaryEnable = true;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:64k") == 0)
+ {
+ kArch = LibCompiler::kPefArch64000;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:amd64") == 0)
+ {
+ kArch = LibCompiler::kPefArchAMD64;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:32k") == 0)
+ {
+ kArch = LibCompiler::kPefArch32000;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:power64") == 0)
+ {
+ kArch = LibCompiler::kPefArchPowerPC;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:riscv64") == 0)
+ {
+ kArch = LibCompiler::kPefArchRISCV;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:arm64") == 0)
+ {
+ kArch = LibCompiler::kPefArchARM64;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:verbose") == 0)
+ {
+ kVerbose = true;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:dylib") == 0)
+ {
+ if (kOutput.empty())
+ {
+ continue;
+ }
+
+ if (kOutput.find(kPefExt) != LibCompiler::String::npos)
+ kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt));
+
+ kOutput += kPefDylibExt;
+
+ is_executable = false;
+
+ continue;
+ }
+ else if (StringCompare(argv[linker_arg], "--ld64:output") == 0)
+ {
+ kOutput = argv[linker_arg + 1];
+ ++linker_arg;
+
+ continue;
+ }
+ else
+ {
+ if (argv[linker_arg][0] == '-')
+ {
+ kStdOut << "unknown flag: " << argv[linker_arg] << "\n";
+ return EXIT_FAILURE;
+ }
+
+ kObjectList.emplace_back(argv[linker_arg]);
+
+ continue;
+ }
+ }
+
+ if (kOutput.empty())
+ {
+ kStdOut << "no output filename set." << std::endl;
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+
+ // sanity check.
+ if (kObjectList.empty())
+ {
+ kStdOut << "no input files." << std::endl;
+ return TOOLCHAINKIT_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 << "no such file: " << obj << std::endl;
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+ }
+ }
+
+ // PEF expects a valid target architecture when outputing a binary.
+ if (kArch == 0)
+ {
+ kStdOut << "no target architecture set, can't continue." << std::endl;
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+
+ LibCompiler::PEFContainer pef_container{};
+
+ int32_t archs = kArch;
+
+ pef_container.Count = 0UL;
+ pef_container.Kind = is_executable ? LibCompiler::kPefKindExec : LibCompiler::kPefKindDylib;
+ pef_container.SubCpu = kSubArch;
+ pef_container.Linker = kLinkerId; // Theater Quality Incorporated 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(LibCompiler::PEFContainer);
+
+ std::ofstream output_fc(kOutput, std::ofstream::binary);
+
+ if (output_fc.bad())
+ {
+ if (kVerbose)
+ {
+ kStdOut << "error: " << strerror(errno) << "\n";
+ }
+
+ return TOOLCHAINKIT_FILE_NOT_FOUND;
+ }
+
+ //! Read AE to convert as PEF.
+
+ std::vector<LibCompiler::PEFCommandHeader> command_headers;
+ LibCompiler::Utils::AEReadableProtocol reader_protocol{};
+
+ for (const auto& objectFile : kObjectList)
+ {
+ if (!std::filesystem::exists(objectFile))
+ continue;
+
+ LibCompiler::AEHeader hdr{};
+
+ reader_protocol.FP = std::ifstream(objectFile, std::ifstream::binary);
+ reader_protocol.FP >> hdr;
+
+ auto ae_header = hdr;
+
+ if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 &&
+ ae_header.fSize == sizeof(LibCompiler::AEHeader))
+ {
+ if (ae_header.fArch != kArch)
+ {
+ if (kVerbose)
+ kStdOut << "info: is this a FAT binary? : ";
+
+ if (!kFatBinaryEnable)
+ {
+ if (kVerbose)
+ kStdOut << "No.\n";
+
+ kStdOut << "error: object " << objectFile
+ << " is a different kind of architecture and output isn't "
+ "treated as a FAT binary."
+ << std::endl;
+
+ return TOOLCHAINKIT_FAT_ERROR;
+ }
+ else
+ {
+ if (kVerbose)
+ {
+ kStdOut << "Architecture matches what we expect.\n";
+ }
+ }
+ }
+
+ // append arch type to archs varaible.
+ archs |= ae_header.fArch;
+ std::size_t cnt = ae_header.fCount;
+
+ if (kVerbose)
+ kStdOut << "object header found, record count: " << cnt << "\n";
+
+ pef_container.Count = cnt;
+
+ char_type* raw_ae_records =
+ new char_type[cnt * sizeof(LibCompiler::AERecordHeader)];
+
+ memset(raw_ae_records, 0, cnt * sizeof(LibCompiler::AERecordHeader));
+
+ auto* ae_records = reader_protocol.Read(raw_ae_records, cnt);
+
+ for (size_t ae_record_index = 0; ae_record_index < cnt;
+ ++ae_record_index)
+ {
+ LibCompiler::PEFCommandHeader command_header{0};
+ std::size_t offset_of_obj = ae_records[ae_record_index].fOffset;
+
+ MemoryCopy(command_header.Name, ae_records[ae_record_index].fName,
+ kPefNameLen);
+
+ LibCompiler::String cmd_hdr_name(command_header.Name);
+
+ // check this header if it's any valid.
+ if (cmd_hdr_name.find(kPefCode64) ==
+ LibCompiler::String::npos &&
+ cmd_hdr_name.find(kPefData64) ==
+ LibCompiler::String::npos &&
+ cmd_hdr_name.find(kPefZero64) ==
+ LibCompiler::String::npos)
+ {
+ if (cmd_hdr_name.find(kPefStart) ==
+ LibCompiler::String::npos &&
+ *command_header.Name == 0)
+ {
+ if (cmd_hdr_name.find(kLdDefineSymbol) !=
+ LibCompiler::String::npos)
+ {
+ goto ld_mark_header;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ }
+
+ if (cmd_hdr_name.find(kPefStart) !=
+ LibCompiler::String::npos &&
+ cmd_hdr_name.find(kPefCode64) !=
+ LibCompiler::String::npos)
+ {
+ kStartFound = true;
+ }
+
+ ld_mark_header:
+ command_header.Offset = offset_of_obj;
+ command_header.Kind = ae_records[ae_record_index].fKind;
+ command_header.Size = ae_records[ae_record_index].fSize;
+ command_header.Cpu = ae_header.fArch;
+ command_header.SubCpu = ae_header.fSubArch;
+
+ if (kVerbose)
+ {
+ kStdOut << "Record: "
+ << ae_records[ae_record_index].fName << " is marked.\n";
+
+ kStdOut << "Record offset: " << command_header.Offset << "\n";
+ }
+
+ command_headers.emplace_back(command_header);
+ }
+
+ delete[] raw_ae_records;
+
+ std::vector<char> bytes;
+ bytes.resize(ae_header.fCodeSize);
+
+ // TODO: Port this to NeFS.
+
+ reader_protocol.FP.seekg(std::streamsize(ae_header.fStartCode));
+ reader_protocol.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize));
+
+ for (auto& byte : bytes)
+ {
+ kObjectBytes.push_back({ .fPefBlob = bytes, .fAEOffset = ae_header.fStartCode });
+ }
+
+ reader_protocol.FP.close();
+
+ continue;
+ }
+
+ kStdOut << "Not an object container: " << objectFile << std::endl;
+ // don't continue, it is a fatal error.
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+
+ pef_container.Cpu = archs;
+
+ output_fc << pef_container;
+
+ if (kVerbose)
+ {
+ kStdOut << "Wrote container header.\n";
+ }
+
+ output_fc.seekp(std::streamsize(pef_container.HdrSz));
+
+ std::vector<LibCompiler::String> not_found;
+ std::vector<LibCompiler::String> symbols;
+
+ // step 2: check for errors (multiple symbols, undefined ones)
+
+ for (auto& command_hdr : command_headers)
+ {
+ // check if this symbol needs to be resolved.
+ if (LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) !=
+ LibCompiler::String::npos &&
+ LibCompiler::String(command_hdr.Name).find(kLdDynamicSym) == LibCompiler::String::npos)
+ {
+ if (kVerbose)
+ kStdOut << "Found undefined symbol: " << command_hdr.Name << "\n";
+
+ if (auto it = std::find(not_found.begin(), not_found.end(),
+ LibCompiler::String(command_hdr.Name));
+ it == not_found.end())
+ {
+ not_found.emplace_back(command_hdr.Name);
+ }
+ }
+
+ symbols.emplace_back(command_hdr.Name);
+ }
+
+ // Now try to solve these symbols.
+
+ for (size_t not_found_idx = 0; not_found_idx < command_headers.size();
+ ++not_found_idx)
+ {
+ if (const auto it = std::find(not_found.begin(), not_found.end(),
+ LibCompiler::String(command_headers[not_found_idx].Name));
+ it != not_found.end())
+ {
+ LibCompiler::String symbol_imp = *it;
+
+ if (symbol_imp.find(kLdDefineSymbol) == LibCompiler::String::npos)
+ continue;
+
+ // erase the lookup prefix.
+ symbol_imp.erase(
+ 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol));
+
+ // demangle everything.
+ while (symbol_imp.find('$') != LibCompiler::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& command_hdr : command_headers)
+ {
+ if (LibCompiler::String(command_hdr.Name).find(symbol_imp) !=
+ LibCompiler::String::npos &&
+ LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) ==
+ LibCompiler::String::npos)
+ {
+ LibCompiler::String undefined_symbol = command_hdr.Name;
+ auto result_of_sym =
+ undefined_symbol.substr(undefined_symbol.find(symbol_imp));
+
+ for (int i = 0; result_of_sym[i] != 0; ++i)
+ {
+ if (result_of_sym[i] != symbol_imp[i])
+ goto ld_continue_search;
+ }
+
+ not_found.erase(it);
+
+ if (kVerbose)
+ kStdOut << "found symbol: " << command_hdr.Name << "\n";
+
+ break;
+ }
+ }
+
+ ld_continue_search:
+ continue;
+ }
+ }
+
+ // step 3: check for errors (recheck if we have those symbols.)
+
+ if (!kStartFound && is_executable)
+ {
+ if (kVerbose)
+ kStdOut
+ << "undefined entrypoint: " << kPefStart << ", you may have forget to ld64 "
+ "against your compiler's runtime library.\n";
+
+ kStdOut << "undefined entrypoint " << kPefStart
+ << " for executable: " << kOutput << "\n";
+ }
+
+ // step 4: write all PEF commands.
+
+ LibCompiler::PEFCommandHeader date_cmd_hdr{};
+
+ time_t timestamp = time(nullptr);
+
+ LibCompiler::String timeStampStr = "Container:BuildEpoch:";
+ timeStampStr += std::to_string(timestamp);
+
+ strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size());
+
+ date_cmd_hdr.Flags = 0;
+ date_cmd_hdr.Kind = LibCompiler::kPefZero;
+ date_cmd_hdr.Offset = output_fc.tellp();
+ date_cmd_hdr.Size = timeStampStr.size();
+
+ command_headers.push_back(date_cmd_hdr);
+
+ LibCompiler::PEFCommandHeader abi_cmd_hdr{};
+
+ LibCompiler::String abi = kLinkerAbiContainer;
+
+ switch (kArch)
+ {
+ case LibCompiler::kPefArchAMD64: {
+ abi += "MSFT";
+ break;
+ }
+ case LibCompiler::kPefArchPowerPC: {
+ abi += "SYSV";
+ break;
+ }
+ case LibCompiler::kPefArch32000:
+ case LibCompiler::kPefArch64000: {
+ abi += " ZWS";
+ break;
+ }
+ default: {
+ abi += " IDK";
+ break;
+ }
+ }
+
+ MemoryCopy(abi_cmd_hdr.Name, abi.c_str(), abi.size());
+
+ abi_cmd_hdr.Size = abi.size();
+ abi_cmd_hdr.Offset = output_fc.tellp();
+ abi_cmd_hdr.Flags = 0;
+ abi_cmd_hdr.Kind = LibCompiler::kPefLinkerID;
+
+ command_headers.push_back(abi_cmd_hdr);
+
+ LibCompiler::PEFCommandHeader stack_cmd_hdr{0};
+
+ stack_cmd_hdr.Cpu = kArch;
+ stack_cmd_hdr.Flags = 0;
+ stack_cmd_hdr.Size = sizeof(uintptr_t);
+ stack_cmd_hdr.Offset = 0;
+
+ MemoryCopy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol));
+
+ command_headers.push_back(stack_cmd_hdr);
+
+ LibCompiler::PEFCommandHeader uuid_cmd_hdr{};
+
+ std::random_device rd;
+
+ auto seedData = std::array<int, std::mt19937::state_size>{};
+ std::generate(std::begin(seedData), std::end(seedData), std::ref(rd));
+ std::seed_seq seq(std::begin(seedData), std::end(seedData));
+ std::mt19937 generator(seq);
+
+ auto gen = uuids::uuid_random_generator{generator};
+ uuids::uuid id = gen();
+ auto uuidStr = uuids::to_string(id);
+
+ MemoryCopy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:"));
+ MemoryCopy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(),
+ uuidStr.size());
+
+ uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name);
+ uuid_cmd_hdr.Offset = output_fc.tellp();
+ uuid_cmd_hdr.Flags = LibCompiler::kPefLinkerID;
+ uuid_cmd_hdr.Kind = LibCompiler::kPefZero;
+
+ command_headers.push_back(uuid_cmd_hdr);
+
+ // prepare a symbol vector.
+ std::vector<LibCompiler::String> undef_symbols;
+ std::vector<LibCompiler::String> dupl_symbols;
+ std::vector<LibCompiler::String> resolve_symbols;
+
+ constexpr Int32 cPaddingOffset = 16;
+
+ size_t previous_offset = (command_headers.size() * sizeof(LibCompiler::PEFCommandHeader)) + cPaddingOffset;
+
+ // Finally write down the command headers.
+ // And check for any duplications
+ for (size_t commandHeaderIndex = 0UL;
+ commandHeaderIndex < command_headers.size(); ++commandHeaderIndex)
+ {
+ if (LibCompiler::String(command_headers[commandHeaderIndex].Name)
+ .find(kLdDefineSymbol) != LibCompiler::String::npos &&
+ LibCompiler::String(command_headers[commandHeaderIndex].Name)
+ .find(kLdDynamicSym) == LibCompiler::String::npos)
+ {
+ // ignore :UndefinedSymbol: headers, they do not contain code.
+ continue;
+ }
+
+ LibCompiler::String symbol_name = command_headers[commandHeaderIndex].Name;
+
+ if (!symbol_name.empty())
+ {
+ undef_symbols.emplace_back(symbol_name);
+ }
+
+ command_headers[commandHeaderIndex].Offset += previous_offset;
+ previous_offset += command_headers[commandHeaderIndex].Size;
+
+ LibCompiler::String name = command_headers[commandHeaderIndex].Name;
+
+ /// so this is valid when we get to the entrypoint.
+ /// it is always a code64 container. And should equal to kPefStart as well.
+ /// this chunk of code updates the pef_container.Start with the updated offset.
+ if (name.find(kPefStart) != LibCompiler::String::npos &&
+ name.find(kPefCode64) != LibCompiler::String::npos)
+ {
+ pef_container.Start = command_headers[commandHeaderIndex].Offset;
+ auto tellCurPos = output_fc.tellp();
+
+ output_fc.seekp(0);
+ output_fc << pef_container;
+
+ output_fc.seekp(tellCurPos);
+ }
+
+ if (kVerbose)
+ {
+ kStdOut << "Command header name: " << name << "\n";
+ kStdOut << "Real address of command header content: " << command_headers[commandHeaderIndex].Offset << "\n";
+ }
+
+ output_fc << command_headers[commandHeaderIndex];
+
+ for (size_t sub_command_header_index = 0UL;
+ sub_command_header_index < command_headers.size();
+ ++sub_command_header_index)
+ {
+ if (sub_command_header_index == commandHeaderIndex)
+ continue;
+
+ if (LibCompiler::String(command_headers[sub_command_header_index].Name)
+ .find(kLdDefineSymbol) != LibCompiler::String::npos &&
+ LibCompiler::String(command_headers[sub_command_header_index].Name)
+ .find(kLdDynamicSym) == LibCompiler::String::npos)
+ {
+ if (kVerbose)
+ {
+ kStdOut << "ignore :UndefinedSymbol: command header...\n";
+ }
+
+ // ignore :UndefinedSymbol: headers, they do not contain code.
+ continue;
+ }
+
+ auto& command_hdr = command_headers[sub_command_header_index];
+
+ if (command_hdr.Name ==
+ LibCompiler::String(command_headers[commandHeaderIndex].Name))
+ {
+ if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(),
+ command_hdr.Name) == dupl_symbols.cend())
+ {
+ dupl_symbols.emplace_back(command_hdr.Name);
+ }
+
+ if (kVerbose)
+ kStdOut << "found duplicate symbol: " << command_hdr.Name
+ << "\n";
+
+ kDuplicateSymbols = true;
+ }
+ }
+ }
+
+ if (!dupl_symbols.empty())
+ {
+ for (auto& symbol : dupl_symbols)
+ {
+ kStdOut << "Multiple symbols of " << symbol << ".\n";
+ }
+
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+
+ // step 2.5: write program bytes.
+
+ for (auto& struct_of_blob : kObjectBytes)
+ {
+ output_fc.write(struct_of_blob.fPefBlob.data(), struct_of_blob.fPefBlob.size());
+ }
+
+ if (kVerbose)
+ kStdOut << "wrote contents of: " << kOutput << "\n";
+
+ // step 3: check if we have those symbols
+
+ std::vector<LibCompiler::String> unreferenced_symbols;
+
+ for (auto& command_hdr : command_headers)
+ {
+ if (auto it = std::find(not_found.begin(), not_found.end(),
+ LibCompiler::String(command_hdr.Name));
+ it != not_found.end())
+ {
+ unreferenced_symbols.emplace_back(command_hdr.Name);
+ }
+ }
+
+ if (!unreferenced_symbols.empty())
+ {
+ for (auto& unreferenced_symbol : unreferenced_symbols)
+ {
+ kStdOut << "undefined symbol " << unreferenced_symbol << "\n";
+ }
+ }
+
+ if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) ||
+ !unreferenced_symbols.empty())
+ {
+ if (kVerbose)
+ kStdOut << "file: " << kOutput
+ << ", is corrupt, removing file...\n";
+
+ return TOOLCHAINKIT_EXEC_ERROR;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+// Last rev 13-1-24
diff --git a/dev/LibCompiler/src/String.cc b/dev/LibCompiler/src/String.cc
new file mode 100644
index 0000000..0804c2b
--- /dev/null
+++ b/dev/LibCompiler/src/String.cc
@@ -0,0 +1,256 @@
+/*
+ * ========================================================
+ *
+ * LibCompiler
+ * Copyright (C) 2024 Theater Quality Inc, all rights reserved.
+ *
+ * ========================================================
+ */
+
+/**
+ * @file String.cxx
+ * @author Amlal (amlal@el-mahrouss-logic.com)
+ * @brief C++ string manipulation API.
+ * @version 0.2
+ * @date 2024-01-23
+ *
+ * @copyright Copyright (c) Theater Quality Incorporated
+ *
+ */
+
+#include <LibCompiler/NFC/String.h>
+
+namespace LibCompiler
+{
+ 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[sizeof(int64_t)];
+
+ if (!to_str(result, sizeof(int64_t), i))
+ {
+ delete[] ret;
+ return ("-1");
+ }
+
+ const auto fmt_len = string_length(fmt);
+ const auto res_len = string_length(result);
+
+ for (SizeType idx = 0; idx < fmt_len; ++idx)
+ {
+ if (fmt[idx] == '%')
+ {
+ SizeType result_cnt = idx;
+
+ for (auto y_idx = 0; y_idx < res_len; ++y_idx)
+ {
+ ret[y_idx] = result[result_cnt];
+ ++result_cnt;
+ }
+
+ break;
+ }
+
+ ret[idx] = fmt[idx];
+ }
+
+ return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */
+ }
+
+ const char* StringBuilder::FromBool(const char* fmt, bool i)
+ {
+ if (!fmt)
+ return ("?");
+
+ const char* boolean_expr = i ? "true" : "false";
+ char* ret = new char[i ? 4 : 5 + string_length(fmt)];
+
+ if (!ret)
+ return ("?");
+
+ const auto fmt_len = string_length(fmt);
+ const auto res_len = string_length(boolean_expr);
+
+ for (SizeType idx = 0; idx < fmt_len; ++idx)
+ {
+ if (fmt[idx] == '%')
+ {
+ SizeType result_cnt = idx;
+
+ for (auto y_idx = idx; y_idx < res_len; ++y_idx)
+ {
+ ret[result_cnt] = boolean_expr[y_idx];
+ ++result_cnt;
+ }
+
+ break;
+ }
+
+ ret[idx] = fmt[idx];
+ }
+
+ return ret;
+ }
+
+ bool StringBuilder::Equals(const char* lhs, const char* rhs)
+ {
+ if (string_length(rhs) != string_length(lhs))
+ return false;
+
+ for (SizeType index = 0; index < string_length(rhs); ++index)
+ {
+ if (rhs[index] != lhs[index])
+ return false;
+ }
+
+ return true;
+ }
+
+ const char* StringBuilder::Format(const char* fmt, const char* fmtRight)
+ {
+ if (!fmt || !fmtRight)
+ return ("?");
+
+ char* ret = new char[string_length(fmtRight) + string_length(fmtRight)];
+ if (!ret)
+ return ("?");
+
+ for (SizeType idx = 0; idx < string_length(fmt); ++idx)
+ {
+ if (fmt[idx] == '%')
+ {
+ SizeType result_cnt = idx;
+
+ for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx)
+ {
+ ret[result_cnt] = fmtRight[y_idx];
+ ++result_cnt;
+ }
+
+ break;
+ }
+
+ ret[idx] = fmt[idx];
+ }
+
+ return ret;
+ }
+
+ 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 LibCompiler