diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-24 03:05:29 +0100 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal@nekernel.org> | 2025-11-24 03:05:29 +0100 |
| commit | bbe2c77243c541ca7e0075149f5be3262eb89523 (patch) | |
| tree | ae5d59d299344fd19584a2c3642bacd788e841d4 /dev | |
| parent | b5adf16a96b9cbb80c74cf30404ed5bcff03ac34 (diff) | |
feat! breaking changes on necti sources.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'dev')
65 files changed, 0 insertions, 17292 deletions
diff --git a/dev/.keep b/dev/.keep deleted file mode 100644 index e69de29..0000000 --- a/dev/.keep +++ /dev/null diff --git a/dev/CompilerKit/AE.h b/dev/CompilerKit/AE.h deleted file mode 100644 index 7b6d9b4..0000000 --- a/dev/CompilerKit/AE.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#ifndef _NECTI_AE_H_ -#define _NECTI_AE_H_ - -#include <CompilerKit/Defines.h> - -#define kAEVer (0x0121) - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen (255) -#define kAEPad (8) -#define kAEMagLen (2) -#define kAENullType (0x00) - -/// @author Amlal El Mahrouss - -/// @brief -// Advanced Executable File Format for ld64. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system loader. - -namespace CompilerKit { -// @brief Advanced Executable Header -// One thing to keep in mind. -// This object format, is reloctable. -typedef struct AEHeader final { - Char fMagic[kAEMagLen] = {}; - UInt16 fVersion{kAEVer}; - Char fArch{}; - Char fSubArch{}; - SizeType fCount{}; - Char fSize{}; - SizeType fStartCode{}; - SizeType fCodeSize{}; - Char fPad[kAEPad] = {}; -} PACKED AEHeader, *AEHeaderPtr; - -// @brief Advanced Executable Record. -// Could be data, code or bss. -// fKind must be filled with PEF fields. - -typedef struct AERecordHeader final { - Char fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - Char fPad[kAEPad]; -} PACKED AERecordHeader, *AERecordHeaderPtr; - -enum { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, -}; -} // namespace CompilerKit - -// provide operator<< for AE - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AERecordHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AERecordHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils { -/** - * @brief AE Reader protocol - * - */ -class AEReadableProtocol final { - public: - std::ifstream file_pointer_; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - NECTI_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) { - file_pointer_.read(raw, std::streamsize(sz)); - return reinterpret_cast<TypeClass*>(raw); - } -}; -} // namespace CompilerKit::Utils - -#endif /* ifndef _NECTI_AE_H_ */
\ No newline at end of file diff --git a/dev/CompilerKit/Compiler.h b/dev/CompilerKit/Compiler.h deleted file mode 100644 index 1f24370..0000000 --- a/dev/CompilerKit/Compiler.h +++ /dev/null @@ -1,222 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> -#include <CompilerKit/Macros.h> -#include <CompilerKit/StringKit.h> - -#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface -#define CK_ENCODER : public ::CompilerKit::EncoderInterface - -namespace CompilerKit { -class AssemblyFactory; -class AssemblyInterface; - -/// =========================================================== /// -/// @brief Simple assembly factory -/// =========================================================== /// -class AssemblyFactory final { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - NECTI_COPY_DEFAULT(AssemblyFactory); - - public: - enum { - kArchInvalid = 0, - kArchAMD64 = 100, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchAARCH64, - kArchUnknown, - kArchCount = kArchUnknown - kArchAMD64, - }; - - Int32 Compile(std::string sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; -}; - -/// =========================================================== /// -/// @brief Assembly to binary generator class. -/// @note This interface creates according to the CPU target of the child class. -/// =========================================================== /// -class AssemblyInterface { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - NECTI_COPY_DEFAULT(AssemblyInterface); - - virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } - - /// =========================================================== /// - /// @brief compile to object file. - /// @note Example C++ -> MASM -> AE object. - /// =========================================================== /// - virtual Int32 CompileToFormat(std::string src, Int32 arch) = 0; -}; - -/// =========================================================== /// -/// @brief Number casting unions for different sizes. -/// =========================================================== /// -union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; -}; - -union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) : raw(raw) {} - - ~NumberCast64() { raw = 0; } - - Char number[8]; - UInt64 raw; -}; - -union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) : raw(raw) {} - - ~NumberCast32() { raw = 0; } - - Char number[4]; - UInt32 raw; -}; - -union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) : raw(raw) {} - - ~NumberCast16() { raw = 0; } - - Char number[2]; - UInt16 raw; -}; - -union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) : raw(raw) {} - - ~NumberCast8() { raw = 0; } - - Char number; - UInt8 raw; -}; - -/// =========================================================== /// -/// @brief Assembly encoder interface. -/// =========================================================== /// -class EncoderInterface { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - NECTI_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string line, std::string file) = 0; - virtual bool WriteLine(std::string line, std::string file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; -}; - -/// =========================================================== /// -/// @brief Different architecture encoders. -/// =========================================================== /// - -#ifdef __ASM_NEED_AMD64__ - -class EncoderAMD64 final : public EncoderInterface { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - NECTI_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); -}; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_ARM64__ - -class EncoderARM64 final : public EncoderInterface { - public: - explicit EncoderARM64() = default; - ~EncoderARM64() override = default; - - NECTI_COPY_DEFAULT(EncoderARM64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_ARM64__ - -#ifdef __ASM_NEED_64x0__ - -class Encoder64x0 final : public EncoderInterface { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - NECTI_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - -class Encoder32x0 final : public EncoderInterface { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - NECTI_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - -class EncoderPowerPC final : public EncoderInterface { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - NECTI_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h deleted file mode 100644 index d036767..0000000 --- a/dev/CompilerKit/Defines.h +++ /dev/null @@ -1,173 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#ifndef __NECTI_DEFINES_H__ -#define __NECTI_DEFINES_H__ - -/// =========================================================== /// -/// @file Defines.h -/// @author Amlal El Mahrouss -/// @brief Basic defines and types for CompilerKit. -/// =========================================================== /// - -#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 Char char -#define Boolean bool - -#include <signal.h> -#include <unistd.h> -#include <cassert> -#include <cctype> -#include <cstdint> -#include <cstdio> -#include <cstring> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <new> -#include <string> -#include <utility> -#include <vector> - -#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 ATTRIBUTE(X) __attribute__((X)) -#define PACKED ATTRIBUTE(packed) - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" } - -#define kAsmFileExtsMax (7U) - -#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) - -#ifdef MSVC -#pragma scalar_storage_order big - endian -#endif // ifdef MSVC - -#define NECTI_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define NECTI_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#define CK_IMPORT_C extern "C" -#define CK_IMPORT extern -namespace CompilerKit { -inline constexpr int kBaseYear = 1900; - -typedef std::string STLString; - -inline STLString current_date() noexcept { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - STLString 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(Char* 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; -} - -inline bool install_signal(Int32 signal, void (*handler)(int)) noexcept { - if (handler == nullptr) return false; - - if (::signal(signal, handler) == SIG_ERR) { - return false; - } - - return true; -} -} // namespace CompilerKit - -#endif /* ifndef __NECTI_DEFINES_H__ */ diff --git a/dev/CompilerKit/ErrorID.h b/dev/CompilerKit/ErrorID.h deleted file mode 100644 index 35039ab..0000000 --- a/dev/CompilerKit/ErrorID.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -#include <CompilerKit/Defines.h> - -/// =========================================================== /// -/// @file ErrorID.h -/// @author Amlal El Mahrouss -/// @brief Error IDs for CompilerKit. -/// =========================================================== /// - -#define NECTI_SUCCESS 0 -#define NECTI_EXEC_ERROR -30 -#define NECTI_FILE_NOT_FOUND -31 -#define NECTI_DIR_NOT_FOUND -32 -#define NECTI_FILE_EXISTS -33 -#define NECTI_TOO_LONG -34 -#define NECTI_INVALID_DATA -35 -#define NECTI_UNIMPLEMENTED -36 -#define NECTI_FAT_ERROR -37 -#define NECTI_INVALID_ARCH -38 diff --git a/dev/CompilerKit/ErrorOr.h b/dev/CompilerKit/ErrorOr.h deleted file mode 100644 index ac42c19..0000000 --- a/dev/CompilerKit/ErrorOr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -/// =========================================================== /// -/// @file ErrorOr.h -/// @author Amlal El Mahrouss -/// @brief ErrorOr for CompilerKit. -/// =========================================================== /// - -#include <CompilerKit/Defines.h> -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/Ref.h> -#include <CompilerKit/StringKit.h> - -namespace CompilerKit { -using ErrorT = Int32; - -template <typename T> -class ErrorOr final { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(ErrorT err) : mId(err) {} - explicit ErrorOr(nullPtr null) {} - explicit ErrorOr(T klass) : mRef(klass) {} - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref<T> Leak() { return mRef; } - - ErrorT Error() { return mId; } - - Bool HasError() { return mId != NECTI_SUCCESS; } - - explicit operator bool() { return mRef; } - - private: - Ref<T> mRef; - ErrorT mId{0}; -}; - -using ErrorOrAny = ErrorOr<VoidPtr>; -using ErrorOrString = ErrorOr<STLString>; -} // namespace CompilerKit diff --git a/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h deleted file mode 100644 index df70048..0000000 --- a/dev/CompilerKit/Frontend.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Compiler.h> - -#define CK_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface - -namespace CompilerKit { -inline static auto kInvalidFrontend = "(null)"; - -struct SyntaxLeafList; -struct SyntaxLeafList; -struct CompilerKeyword; - -/// =========================================================== /// -/// @note we want to do that to separate keywords. -/// =========================================================== /// - -enum KeywordKind { - kKeywordKindNamespace, - kKeywordKindFunctionStart, - kKeywordKindFunctionEnd, - kKeywordKindVariable, - kKeywordKindVariablePtr, - kKeywordKindType, - kKeywordKindTypePtr, - kKeywordKindExpressionBegin, - kKeywordKindExpressionEnd, - kKeywordKindArgSeparator, - kKeywordKindBodyStart, - kKeywordKindBodyEnd, - kKeywordKindClass, - kKeywordKindPtrAccess, - kKeywordKindAccess, - kKeywordKindIf, - kKeywordKindElse, - kKeywordKindElseIf, - kKeywordKindVariableAssign, - kKeywordKindVariableDec, - kKeywordKindVariableInc, - kKeywordKindConstant, - kKeywordKindTypedef, - kKeywordKindEndInstr, - kKeywordKindSpecifier, - kKeywordKindInvalid, - kKeywordKindReturn, - kKeywordKindCommentInline, - kKeywordKindCommentMultiLineStart, - kKeywordKindCommentMultiLineEnd, - kKeywordKindEq, - kKeywordKindNotEq, - kKeywordKindGreaterEq, - kKeywordKindLessEq, - kKeywordKindPtr, -}; - -/// =========================================================== /// -/// \brief Compiler keyword information struct. -/// =========================================================== /// -struct CompilerKeyword { - CompilerKeyword(STLString name, KeywordKind kind) : keyword_name(name), keyword_kind(kind) {} - - STLString keyword_name{""}; - KeywordKind keyword_kind{kKeywordKindInvalid}; -}; - -struct SyntaxLeafList final { - struct SyntaxLeaf final { - Int32 fUserType{0U}; - CompilerKeyword fUserData{"", kKeywordKindInvalid}; - - STLString fUserValue{""}; - struct SyntaxLeaf* fNext{nullptr}; - }; - - std::vector<SyntaxLeaf> fLeafList; - SizeType fNumLeafs{0}; - - SizeType SizeOf() { return fNumLeafs; } - std::vector<SyntaxLeaf>& Get() { return fLeafList; } - SyntaxLeaf& At(SizeType 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. -/// =========================================================== /// -Bool find_word(STLString haystack, STLString needle) noexcept; - -/// =========================================================== /// -/// find a word within strict conditions and returns a range of it. -/// \param haystack -/// \param needle -/// \return position of needle. -/// =========================================================== /// -SizeType find_word_range(STLString haystack, STLString needle) noexcept; - -/// =========================================================== /// -/// @brief Compiler backend, implements a frontend, such as C, C++... -/// See Toolchain, for some examples. -/// =========================================================== /// -class CompilerFrontendInterface { - public: - explicit CompilerFrontendInterface() = default; - virtual ~CompilerFrontendInterface() = default; - - NECTI_COPY_DEFAULT(CompilerFrontendInterface); - - /// =========================================================== /// - // NOTE: cast this to your user defined ast. - /// =========================================================== /// - typedef VoidPtr AstType; - - /// =========================================================== /// - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - /// =========================================================== /// - - virtual CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) = 0; - - /// =========================================================== /// - //! @brief What language are we dealing with? - /// =========================================================== /// - virtual const char* Language() { return kInvalidFrontend; } - - /// =========================================================== /// - /// @brief Checks if language is a valid frontend. - /// =========================================================== /// - virtual bool IsValid() { return strcmp(this->Language(), kInvalidFrontend) > 0; } -}; -} // namespace CompilerKit diff --git a/dev/CompilerKit/Macros.h b/dev/CompilerKit/Macros.h deleted file mode 100644 index 6cef758..0000000 --- a/dev/CompilerKit/Macros.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// @brief provide support for Macros.h header. - -#ifndef _NECTI_MACROS_H_ -#define _NECTI_MACROS_H_ - -#define NECTI_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define NECTI_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#endif /* ifndef _NECTI_MACROS_H_ */ diff --git a/dev/CompilerKit/PEF.h b/dev/CompilerKit/PEF.h deleted file mode 100644 index edf8f5d..0000000 --- a/dev/CompilerKit/PEF.h +++ /dev/null @@ -1,137 +0,0 @@ -/* ========================================= - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> - -// @file PEF.h -// @brief Preferred Executable Format - -#define kPefMagic "Open" -#define kPefMagicFat "nepO" - -#define kPefExt ".exec" -#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" - -/* @note counting the \0 at the end */ -#define kPefMagicLen (5) - -#define kPefVersion (0x0500) -#define kPefNameLen (255) - -#define kPefBaseOrigin (0x40000000) - -/* @note this doesn't have to be __ImageStart only, any C initialization stub will do. */ -#define kPefStart "__ImageStart" - -namespace CompilerKit { -/* @brief Architecture type. */ -enum { - kPefArchIntel86S, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* Open64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchARM64, - kPefArchCount = (kPefArchARM64 - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, -}; - -/* @brief Architecture vendor. */ -enum { - kPefSubArchGeneric = 0, - kPefSubArchAMD = 200, - kPefSubArchIntel, - kPefSubArchARM, - kPefSubArchIBM, -}; - -enum { - kPefKindInvalid = 0, - kPefKindExec = 1, /* .exec */ - kPefKindDylib = 2, /* .dylib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, -}; - -/* PEF container information */ -typedef struct PEFContainer final { - Char Magic[kPefMagicLen]; - UInt32 Linker; /* Linker used to link executable */ - 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 */ - UInt32 Checksum; /* Whole binary checksum */ -} PACKED PEFContainer, *PEFContainerPtr; - -/* First PEFCommandHeader starts after PEFContainer */ -/* Last container is __exec_end */ - -/* PEF executable section and commands. */ - -/* @brief Command Header, a la Mach-O, designed with FAT binaries and virtual memory in mind. */ -typedef struct PEFCommandHeader final { - Char Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* File offset */ - SizeType OffsetSize; - UIntPtr VirtualAddress; /* Virtual Address */ - SizeType VirtualSize; /* Virtual Size */ -} PACKED PEFCommandHeader, *PEFCommandHeaderPtr; - -enum { - kPefInvalid = 0x0, - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, -}; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFContainer& container) { - fp.write((char*) &container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFCommandHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFContainer& container) { - fp.read((char*) &container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFCommandHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/dev/CompilerKit/Ref.h b/dev/CompilerKit/Ref.h deleted file mode 100644 index 66ed60f..0000000 --- a/dev/CompilerKit/Ref.h +++ /dev/null @@ -1,77 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -#include <CompilerKit/Defines.h> - -namespace CompilerKit { -/// @author Amlal El Mahrouss -/// @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) { - MUST_PASS(m_Class); - if (m_Class) delete m_Class; - m_Class = nullptr; - } - } - - NECTI_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; } - - explicit operator bool() { return *m_Class; } - - private: - T* m_Class{nullptr}; - Bool m_Strong{false}; -}; - -// @author Amlal El Mahrouss -// @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 CompilerKit diff --git a/dev/CompilerKit/StringKit.h b/dev/CompilerKit/StringKit.h deleted file mode 100644 index eb7ccc3..0000000 --- a/dev/CompilerKit/StringKit.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#ifndef __NECTI_STRINGKIT__ -#define __NECTI_STRINGKIT__ - -#include <CompilerKit/Defines.h> -#include <CompilerKit/ErrorOr.h> - -/// =========================================================== /// -/// @file StringKit.h -/// @author Amlal El Mahrouss -/// @brief StringKit for CompilerKit. -/// =========================================================== /// - -namespace CompilerKit { -class StringBuilder; -class BasicString; - -/** - * @brief BasicString class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - -class BasicString final { - public: - explicit BasicString() = delete; - - explicit BasicString(SizeType Sz) noexcept : m_Sz(Sz) { - m_Data = new Char[Sz]; - assert(m_Data); - } - - ~BasicString() noexcept { - if (m_Data) { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - NECTI_COPY_DEFAULT(BasicString); - - Char* Data(); - const Char* CData() const; - SizeType Length() const; - - bool operator==(const Char* rhs) const; - bool operator!=(const Char* rhs) const; - - bool operator==(const BasicString& rhs) const; - bool operator!=(const BasicString& rhs) const; - - BasicString& operator+=(const Char* rhs); - BasicString& operator+=(const Char rhs); - BasicString& operator+=(const BasicString& rhs); - - explicit operator bool() { return m_Data && m_Data[0] != 0; } - - bool operator!() { return !m_Data || m_Data[0] == 0; } - - private: - Char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; -}; - -/** - * @brief StringBuilder class - * @note These results shall call be delete[] after they're used. - */ -struct StringBuilder final { - static BasicString Construct(const Char* data); - static BasicString FromInt(const char* fmt, int n); - static BasicString FromBool(const char* fmt, bool n); - static BasicString Format(const char* fmt, const char* from); - static Bool Equals(const char* lhs, const char* rhs); -}; - -using BasicStringOr = ErrorOr<BasicString>; -using BasicStringPtr = BasicString*; -using BasicStringRef = Ref<BasicString>; -} // namespace CompilerKit - -#endif /* ifndef __NECTI_STRINGKIT__ */ diff --git a/dev/CompilerKit/UUID.h b/dev/CompilerKit/UUID.h deleted file mode 100644 index 98733fd..0000000 --- a/dev/CompilerKit/UUID.h +++ /dev/null @@ -1,826 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include <array> -#include <atomic> -#include <cctype> -#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 Detail { - 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 std::basic_string_view<TChar> to_string_view(TChar const* str) noexcept { - return str; - } - - 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 Detail - -// -------------------------------------------------------------------------------------------------------------------------- -// 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 = Detail::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 || !std::isxdigit(static_cast<unsigned char>(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 = Detail::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 || !std::isxdigit(static_cast<unsigned char>(str[i]))) { - return {}; - } - - if (firstDigit) { - data[index] = static_cast<uint8_t>(Detail::hex2char(str[i]) << 4); - firstDigit = false; - } else { - data[index] = static_cast<uint8_t>(data[index] | Detail::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{Detail::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] = Detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f]; - uustr[++i] = Detail::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{}; /// AMLALE: Should be zero-initialized. - 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), - static_cast<unsigned char>((newId.Data2 >> 8) & 0xFF), - static_cast<unsigned char>((newId.Data2) & 0xFF), - static_cast<unsigned char>((newId.Data3 >> 8) & 0xFF), - static_cast<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(Detail::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() { - Detail::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; - Detail::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 */ diff --git a/dev/CompilerKit/Version.h b/dev/CompilerKit/Version.h deleted file mode 100644 index efd174c..0000000 --- a/dev/CompilerKit/Version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#define kDistVersion "v0.0.7-compilerkit" -#define kDistVersionBCD 0x0002 - -#define ToString(X) Stringify(X) -#define Stringify(X) #X - -#define kDistRelease ToString(kDistReleaseBranch) diff --git a/dev/CompilerKit/XCOFF.h b/dev/CompilerKit/XCOFF.h deleted file mode 100644 index a61949a..0000000 --- a/dev/CompilerKit/XCOFF.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - - File: XCOFF.h - Purpose: XCOFF for NeKernel. - - Revision History: - - 04/07/24: Added file (Amlal El Mahrouss) - -======================================== */ - -#ifndef _NECTI_XCOFF_H_ -#define _NECTI_XCOFF_H_ - -#include <CompilerKit/Defines.h> - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit { -struct XCoffFileHeader; - -/// @brief XCoff file 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; - -typedef struct XCoffFileHeader* XCoffFileHeaderPtr; -} // namespace CompilerKit - -#endif // ifndef _NECTI_XCOFF_H_ diff --git a/dev/CompilerKit/ck-osx-san.json b/dev/CompilerKit/ck-osx-san.json deleted file mode 100644 index df1c36b..0000000 --- a/dev/CompilerKit/ck-osx-san.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl", - "/opt/homebrew/Cellar/boost/1.87.0/include" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared", - "-fstack-protector-all", - "-fno-omit-frame-pointer", - "-g", - "-fsanitize=address", - "-fsanitize=undefined" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -}
\ No newline at end of file diff --git a/dev/CompilerKit/ck-osx.json b/dev/CompilerKit/ck-osx.json deleted file mode 100644 index cab0221..0000000 --- a/dev/CompilerKit/ck-osx.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl", - "/opt/homebrew/Cellar/boost/1.87.0/include" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -}
\ No newline at end of file diff --git a/dev/CompilerKit/ck-posix.json b/dev/CompilerKit/ck-posix.json deleted file mode 100644 index b748f7a..0000000 --- a/dev/CompilerKit/ck-posix.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/lib/libCompilerKit.so", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} diff --git a/dev/CompilerKit/impl/32x0.h b/dev/CompilerKit/impl/32x0.h deleted file mode 100644 index 1ad13ee..0000000 --- a/dev/CompilerKit/impl/32x0.h +++ /dev/null @@ -1,93 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> - -// @brief Open32x0 support. -// @file impl/32x0.h - -#define CK_ASM_OPCODE(__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 = { - CK_ASM_OPCODE("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) - CK_ASM_OPCODE("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) - CK_ASM_OPCODE("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) - CK_ASM_OPCODE("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) - CK_ASM_OPCODE("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) - CK_ASM_OPCODE("lea", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR (1C). - CK_ASM_OPCODE("ret", 0b0111011, 0b110, - kAsmImmediate) // return from procedure (2C). - CK_ASM_OPCODE("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) - CK_ASM_OPCODE("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) - CK_ASM_OPCODE("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) -}; - -// \brief 64x0 register prefix -// 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/CompilerKit/impl/64x0.h b/dev/CompilerKit/impl/64x0.h deleted file mode 100644 index ce2ae89..0000000 --- a/dev/CompilerKit/impl/64x0.h +++ /dev/null @@ -1,100 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> -#include <vector> - -// @brief Open64x0 support. -// @file impl/64x0.h - -#define CK_ASM_OPCODE(__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 = { - CK_ASM_OPCODE("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - CK_ASM_OPCODE("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - CK_ASM_OPCODE("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - CK_ASM_OPCODE("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - CK_ASM_OPCODE("mv", 0b0100011, 0b101, kAsmRegToReg) CK_ASM_OPCODE( - "bg", 0b1100111, 0b111, kAsmRegToReg) CK_ASM_OPCODE("bl", 0b1100111, 0b011, kAsmRegToReg) - CK_ASM_OPCODE("beq", 0b1100111, 0b000, kAsmRegToReg) - CK_ASM_OPCODE("bne", 0b1100111, 0b001, kAsmRegToReg) - CK_ASM_OPCODE("bge", 0b1100111, 0b101, kAsmRegToReg) - CK_ASM_OPCODE("ble", 0b1100111, 0b100, kAsmRegToReg) - CK_ASM_OPCODE("stw", 0b0001111, 0b100, kAsmImmediate) - CK_ASM_OPCODE("ldw", 0b0001111, 0b100, kAsmImmediate) - CK_ASM_OPCODE("lda", 0b0001111, 0b101, kAsmImmediate) - CK_ASM_OPCODE("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - CK_ASM_OPCODE("add", 0b0101011, 0b100, kAsmImmediate) - CK_ASM_OPCODE("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - CK_ASM_OPCODE("addc", 0b0101011, 0b110, kAsmImmediate) CK_ASM_OPCODE( - "subc", 0b0101011, 0b111, kAsmImmediate) CK_ASM_OPCODE("sc", 0b1110011, 0b00, kAsmSyscall)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// 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/CompilerKit/impl/Aarch64.h b/dev/CompilerKit/impl/Aarch64.h deleted file mode 100644 index c1e9c77..0000000 --- a/dev/CompilerKit/impl/Aarch64.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ======================================== - -Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> -#include <stdint.h> - -/// @brief ARM64 encoding support. -/// @file impl/Aarch64.h - -struct CpuOpcodeArm64; - -/// @brief ARM64 opcode header. -struct PACKED CpuOpcodeArm64_Data final { - uint32_t fOpcode : 10; // Bits 31–22: Opcode for operation - uint32_t fRm : 5; // Bits 21–16: Source register Rm - uint32_t fShamt : 6; // Bits 15–10: Shift amount - uint32_t fRn : 5; // Bits 9–5: Source register Rn - uint32_t fRd : 5; // Bits 4–0: Destination register Rd -}; - -typedef struct { - uint32_t opcode : 6; // Bits 31–26: Branch opcode - int32_t offset : 26; // Bits 25–0: Signed offset (branch target) -} PACKED CpuOpcodeArm64_Branch; - -typedef struct { - uint32_t size : 2; // Bits 31–30: Size of the data - uint32_t opcode : 7; // Bits 29–23: Opcode for load/store - uint32_t offset : 12; // Bits 22–10: Offset - uint32_t rn : 5; // Bits 9–5: Base address register Rn - uint32_t rt : 5; // Bits 4–0: Target/source register Rt -} PACKED CpuOpcodeArm64_LoadStore; - -#define kAsmRegisterLimit (30) -#define kAsmRegisterPrefix "x" -#define kOpcodeARM64Count (1000) diff --git a/dev/CompilerKit/impl/PowerPC.h b/dev/CompilerKit/impl/PowerPC.h deleted file mode 100644 index 7c7f67c..0000000 --- a/dev/CompilerKit/impl/PowerPC.h +++ /dev/null @@ -1,1557 +0,0 @@ -/* ======================================== - - Some modifications are copyrighted under: - Amlal El Mahrouss - - Original author: - Apple Inc - -======================================== */ - -#pragma once - -#include <stdint.h> - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -#define kOpcodePPCCount (1073U) - -/* - * 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 OpcodeType { - 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 CpuOpcodePPC { - struct OpcodeType final { - uint32_t offset : 5; - uint32_t width : 5; - uint32_t type : 6; - }; - - uint32_t opcode; - const char* name; // c++ wants the string to be const, it makes sense here. - OpcodeType ops[5]; - uint32_t cpus; -}; - -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/CompilerKit/impl/X64.h b/dev/CompilerKit/impl/X64.h deleted file mode 100644 index ccbcf13..0000000 --- a/dev/CompilerKit/impl/X64.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> - -// @brief AMD64 support. -// @file impl/X64.h - -#define CK_ASM_OPCODE(__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; - -#define kAsmRegisterPrefix "r" - -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 = { - CK_ASM_OPCODE("int", 0xCD) CK_ASM_OPCODE("into", 0xCE) CK_ASM_OPCODE("intd", 0xF1) - CK_ASM_OPCODE("int3", 0xC3) CK_ASM_OPCODE("iret", 0xCF) CK_ASM_OPCODE("retf", 0xCB) - CK_ASM_OPCODE("retn", 0xC3) CK_ASM_OPCODE("ret", 0xC3) CK_ASM_OPCODE("sti", 0xfb) - CK_ASM_OPCODE("cli", 0xfa) CK_ASM_OPCODE("hlt", 0xf4) CK_ASM_OPCODE("nop", 0x90) - CK_ASM_OPCODE("mov", 0x48) CK_ASM_OPCODE("call", 0xFF) - CK_ASM_OPCODE("syscall", 0x0F) CK_ASM_OPCODE("xor", 0x48)}; - -#define kAsmRegisterLimit 16 diff --git a/dev/CompilerKit/src/AssemblyFactory.cc b/dev/CompilerKit/src/AssemblyFactory.cc deleted file mode 100644 index 5c606e9..0000000 --- a/dev/CompilerKit/src/AssemblyFactory.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#include <CompilerKit/Compiler.h> -#include <CompilerKit/ErrorID.h> - -/** - * @file AssemblyFactory.cc - * @author Amlal El Mahrouss (amlal@nekernel.org) - * @brief Assembly API of NeCTI - * @version 0.0.2 - * - * @copyright Copyright (c) 2024-2025 Amlal El Mahrouss - * - */ - -namespace CompilerKit { -///! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { - if (sourceFile.length() < 1) return NECTI_UNIMPLEMENTED; - - if (!fMounted) return NECTI_UNIMPLEMENTED; - if (arch != fMounted->Arch()) return NECTI_INVALID_ARCH; - - try { - return this->fMounted->CompileToFormat(sourceFile, arch); - } catch (std::exception& e) { - return NECTI_EXEC_ERROR; - } -} - -///! @brief mount assembly backend. -void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { - if (mountPtr) { - fMounted = mountPtr; - } -} - -///! @brief Unmount assembler. -AssemblyInterface* AssemblyFactory::Unmount() noexcept { - auto mount_prev = fMounted; - - if (fMounted) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc deleted file mode 100644 index 6ffaa6e..0000000 --- a/dev/CompilerKit/src/Backend/Assembler32x0.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 32asm.cc -// @author Amlal El Mahrouss -// @brief 32x0 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_32x0__ -#define __ASM_NEED_32x0__ 1 -#endif - -#include <CompilerKit/AE.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/impl/32x0.h> -#include <CompilerKit/utils/CompilerUtils.h> - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 32x0 Assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(NEAssemblerMain32000) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - return EXIT_SUCCESS; -} diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc deleted file mode 100644 index f9052d2..0000000 --- a/dev/CompilerKit/src/Backend/Assembler64x0.cc +++ /dev/null @@ -1,874 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file Assembler64x0.cc -// @author Amlal El Mahrouss -// @brief 64x000 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_64x0__ -#define __ASM_NEED_64x0__ 1 -#endif - -#include <CompilerKit/AE.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/impl/64x0.h> -#include <CompilerKit/utils/CompilerUtils.h> -#include <algorithm> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <vector> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -static char kOutputArch = CompilerKit::kPefArch64000; - -constexpr auto k64x0IPAlignment = 0x1U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; - -static std::vector<e64k_num_t> kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector<CompilerKit::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 64x0 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMain64x0) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-64x0-ver") == 0 || strcmp(argv[i], "-64x0-v") == 0) { - kStdOut - << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "-64x0-h") == 0) { - kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss " - "Logic.\n"; - kStdOut << "--version: Print program version.\n"; - kStdOut << "--verbose: Print verbose output.\n"; - kStdOut << "--binary: Output as flat binary.\n"; - kStdOut << "--64xxx: Compile for a subset of the X64000.\n"; - - return 0; - } else if (strcmp(argv[i], "-64x0-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-64x0-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "Assembler64x0: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "Assembler64x0: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "Assembler64x0: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::Encoder64x0 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "Assembler64x0: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "Assembler64x0: At least one record is needed to write an object " - "file.\nAssembler64x0: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) { - if (kVerbose) kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "Assembler64x0: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "Assembler64x0: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "Assembler64x0: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "Assembler64x0: Exit failed.\n"; - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment")); - - /// sanity check to avoid stupid linker errors. - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "power-as"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_64x0(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::Encoder64x0::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!Detail::algorithm::is_valid_64x0(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_64x0(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector<std::string> operands_inst = {"stw", "ldw", "lda", "sta"}; - - // these don't. - std::vector<std::string> filter_inst = {"jlr", "jrl", "int"}; - - for (auto& opcode64x0 : kOpcodes64x0) { - if (line.find(opcode64x0.fName) != std::string::npos) { - if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; - - for (auto& op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode64x0.fName); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex_number"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 16 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::Encoder64x0::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment ")) return true; - - for (auto& opcode64x0 : kOpcodes64x0) { - // strict check here - if (CompilerKit::find_word(line, opcode64x0.fName) && Detail::algorithm::is_valid_64x0(line)) { - std::string name(opcode64x0.fName); - std::string jump_label, cpy_jump_label; - - kBytes.emplace_back(opcode64x0.fOpcode); - kBytes.emplace_back(opcode64x0.fFunct3); - kBytes.emplace_back(opcode64x0.fFunct7); - - // check funct7 type. - switch (opcode64x0.fFunct7) { - // reg to reg means register to register transfer operation. - case kAsmRegToReg: - case kAsmImmediate: { - // \brief how many registers we found. - std::size_t found_some = 0UL; - - for (size_t line_index = 0UL; line_index < line.size(); line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (kOutputArch == CompilerKit::kPefArch64000) { - if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - Detail::print_error("invalid register index, r" + reg_str + - "\nnote: The 64x0 accepts registers from r0 to r20.", - file); - throw std::runtime_error("invalid_register_index"); - } - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - Detail::print_error("invalid register index, r" + reg_str, file); - throw std::runtime_error("invalid_register_index"); - } - - kBytes.emplace_back(reg_index); - ++found_some; - - if (kVerbose) { - kStdOut << "Assembler64x0: Register found: " << register_syntax << "\n"; - kStdOut << "Assembler64x0: Register amount in instruction: " << found_some << "\n"; - } - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode64x0.fFunct7 != kAsmImmediate) { - // remember! register to register! - if (found_some == 1) { - Detail::print_error( - "Too few registers.\ntip: each Assembler64x0 register " - "starts with 'r'.\nline: " + - line, - file); - throw std::runtime_error("not_a_register"); - } - } - - if (found_some < 1 && name != "ldw" && name != "lda" && name != "stw") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "add") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "sub") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - if (found_some > 0 && name == "pop") { - Detail::print_error( - "invalid combination for opcode 'pop'.\ntip: it expects " - "nothing.\nline: " + - line, - file); - throw std::runtime_error("invalid_comb_op_pop"); - } - } - default: - break; - } - - // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { - auto where_string = name; - - // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || name == "sta") - where_string = ","; - - jump_label = line; - - auto found_sym = false; - - while (jump_label.find(where_string) != std::string::npos) { - jump_label = jump_label.substr(jump_label.find(where_string) + where_string.size()); - - while (jump_label.find(" ") != std::string::npos) { - jump_label.erase(jump_label.find(" "), 1); - } - - if (jump_label[0] != kAsmRegisterPrefix[0] && !isdigit(jump_label[1])) { - if (found_sym) { - Detail::print_error( - "invalid combination of opcode and operands.\nhere -> " + jump_label, file); - throw std::runtime_error("invalid_comb_op_ops"); - } else { - // death trap installed. - found_sym = true; - } - } - } - - cpy_jump_label = jump_label; - - // replace any spaces with $ - if (jump_label[0] == ' ') { - while (jump_label.find(' ') != std::string::npos) { - if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; - - jump_label.erase(jump_label.find(' '), 1); - } - } - - if (!this->WriteNumber(0, jump_label)) { - // sta expects this: sta 0x000000, r0 - if (name == "sta") { - Detail::print_error("invalid combination of opcode and operands.\nHere ->" + line, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } - } else { - if (name == "sta" && cpy_jump_label.find("extern_segment ") != std::string::npos) { - Detail::print_error("invalid usage extern_segment on 'sta', here: " + line, file); - throw std::runtime_error("invalid_sta_usage"); - } - } - - goto asm_write_label; - } - - // This is the case where we jump to a label, it is also used as a goto. - if (name == "lda" || name == "sta") { - asm_write_label: - if (cpy_jump_label.find('\n') != std::string::npos) - cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); - - if (cpy_jump_label.find("extern_segment") != std::string::npos) { - cpy_jump_label.erase(cpy_jump_label.find("extern_segment"), strlen("extern_segment")); - - if (name == "sta") { - Detail::print_error("extern_segment is not allowed on a sta operation.", file); - throw std::runtime_error("extern_segment_sta_op"); - } else { - goto asm_end_label_cpy; - } - } - - if (name == "lda" || name == "sta") { - for (auto& label : kOriginLabel) { - if (cpy_jump_label == label.first) { - if (kVerbose) { - kStdOut << "Assembler64x0: Replace label " << cpy_jump_label - << " to address: " << label.second << std::endl; - } - - CompilerKit::NumberCast64 num(label.second); - - for (auto& num : num.number) { - kBytes.push_back(num); - } - - goto asm_end_label_cpy; - } - } - - if (cpy_jump_label[0] == '0') { - switch (cpy_jump_label[1]) { - case 'x': - case 'o': - case 'b': - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - default: - break; - } - - if (isdigit(cpy_jump_label[0])) { - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - } - } - } - - if (cpy_jump_label.size() < 1) { - Detail::print_error("label is empty, can't jump on it.", file); - throw std::runtime_error("label_empty"); - } - - /// don't go any further if: - /// load word (ldw) or store word. (stw) - - if (name == "ldw" || name == "stw") break; - - auto mld_reloc_str = std::to_string(cpy_jump_label.size()); - mld_reloc_str += kUndefinedSymbol; - mld_reloc_str += cpy_jump_label; - - bool ignore_back_slash = false; - - for (auto& reloc_chr : mld_reloc_str) { - if (reloc_chr == '\\') { - ignore_back_slash = true; - continue; - } - - if (ignore_back_slash) { - ignore_back_slash = false; - continue; - } - - kBytes.push_back(reloc_chr); - } - - kBytes.push_back('\0'); - goto asm_end_label_cpy; - } - - asm_end_label_cpy: - kOrigin += k64x0IPAlignment; - - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc deleted file mode 100644 index 8c7e21c..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc +++ /dev/null @@ -1,1204 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerAMD64.cc -/// @author Amlal El Mahrouss -/// @brief AMD64 Assembler. -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -/// bugs: 0 - -/// feature request: 1 -/// Encode registers in mov, add, xor... - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_AMD64__ -#define __ASM_NEED_AMD64__ 1 -#endif - -#define kAssemblerPragmaSymStr "%%" -#define kAssemblerPragmaSym '%' - -#include <CompilerKit/AE.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/impl/X64.h> -#include <algorithm> -#include <cstdlib> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <vector> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -static char kOutputArch = CompilerKit::kPefArchAMD64; - -static constexpr auto kIPAlignement = 0x1U; -static auto kCounter = 0x1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; - -/// @brief keep it simple by default. -static std::int32_t kRegisterBitWidth = 16U; - -static std::vector<i64_byte_t> kAppBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector<CompilerKit::AERecordHeader> kRecords; -static std::vector<std::string> kDefinedSymbols; -static std::vector<std::string> kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -#include <CompilerKit/utils/AsmUtils.h> - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainAMD64) { - //////////////// CPU OPCODES BEGIN //////////////// - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - std::string opcodes_jump[kJumpLimit] = {"ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", - "jl", "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", - "jng", "jnge", "jnl", "jnle", "jno", "jnp", "jns", "jnz", - "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuOpcodeAMD64 code{.fName = opcodes_jump[i], - .fOpcode = static_cast<i64_hword_t>(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) { - kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: " - "v1.10\nAssemblerAMD64: Copyright " - "(c) Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--amd64:h") == 0) { - kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version: Print program version.\n"; - kStdOut << "--verbose: Print verbose output.\n"; - kStdOut << "--binary: Output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--amd64:binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--amd64:verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerAMD64: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerAMD64: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - std::string asm_input(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.ends_with(ext)) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - break; - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - kStdOut << "AssemblerAMD64: Assembling: " << argv[i] << "\n"; - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerAMD64: error: " << strerror(errno) << "\n"; - } - - return 1; - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderAMD64 asm64; - - if (kVerbose) { - kStdOut << "Compiling: " + asm_input << "\n"; - kStdOut << "From: " + line << "\n"; - } - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - try { - std::filesystem::remove(object_output); - } catch (...) { - } - - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerAMD64: At least one record is needed to write an object " - "file.\nAssemblerAMD64: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) { - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kAppBytes) { - if (byte == 0) continue; - - if (byte == 0xFF) { - byte = 0; - } - - file_ptr_out << reinterpret_cast<const char*>(&byte)[0]; - } - - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerAMD64: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerAMD64: Exit failed.\n"; - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "power-as"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(kPefCode64) != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(kPefData64) != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(kPefZero64) != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 1); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != kDefinedSymbols.end()) { - Detail::print_error("Symbol already defined.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_valid(char c) { - if ((isalpha(c) || isdigit(c)) || - ((c == ' ') || (c == '\t') || (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '*') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || (c == '_') || - (c == ':') || (c == '@') || (c == '.') || (c == '#') || (c == ';'))) - return false; - - return true; -} - -bool is_valid_amd64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_valid) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderAMD64::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || - CompilerKit::find_word(line, kAssemblerPragmaSymStr) || CompilerKit::find_word(line, ";") || - line[0] == kAssemblerPragmaSym) { - if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!Detail::algorithm::is_valid_amd64(line)) { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto& opcodeAMD64 : kOpcodesAMD64) { - if (CompilerKit::find_word(line, opcodeAMD64.fName)) { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderAMD64::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment ")) return true; - - struct RegMapAMD64 { - CompilerKit::STLString fName; - i64_byte_t fModRM; - }; - - std::vector<RegMapAMD64> kRegisterList{ - {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, - }; - - Bool foundInstruction = false; - - for (auto& opcodeAMD64 : kOpcodesAMD64) { - // strict check here - if (CompilerKit::find_word(line, opcodeAMD64.fName) && - Detail::algorithm::is_valid_amd64(line)) { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (line.find(name) != std::string::npos) { - if (name == "mov" || name == "xor") { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) { - Detail::print_error("Syntax error: missing right operand.", "CompilerKit"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector<RegMapAMD64> currentRegList; - - for (auto& reg : kRegisterList) { - std::vector<char> regExt = {'e', 'r'}; - - for (auto& ext : regExt) { - std::string registerName; - - if (bits > 16) registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) { - if (registerName[0] == 'r') { - Detail::print_error("invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back({.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) { - /// very tricky to understand. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || currentRegList[1].fName[0] == 'r') { - if (isdigit(currentRegList[0].fName[1]) && isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (name == "mov") { - if (bits == 64 || bits == 32) { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - if (!onlyOneReg) kAppBytes.emplace_back(0x89); - } else if (bits == 16) { - if (hasRBasedRegs) { - Detail::print_error("Invalid combination of operands and registers.", - "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } else { - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - } - } else { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x31); - } - - if (onlyOneReg) { - auto num = GetNumber32(line, ","); - - for (auto& num_idx : num.number) { - if (num_idx == 0) num_idx = 0xFF; - } - - auto modrm = (0x3 << 6 | currentRegList[0].fModRM); - - kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number. - kAppBytes.emplace_back(modrm); - - if (name != "xor") { - kAppBytes.emplace_back(num.number[0]); - kAppBytes.emplace_back(num.number[1]); - kAppBytes.emplace_back(num.number[2]); - kAppBytes.emplace_back(num.number[3]); - } - - break; - } - - if (currentRegList[1].fName[0] == 'r' && currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) { - if (currentRegList[0].fName[0] == 'r' || currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - } else { - if (currentRegList[0].fName[0] != 'r' || currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } - } - - if (name == "int" || name == "into" || name == "intd") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } else if (name == "jmp" || name == "call") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } else if (name == "syscall") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - kAppBytes.emplace_back(0x05); - - break; - } else { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) { - if (foundInstruction) { - Detail::print_error("Syntax error: " + line, file); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) { - kRegisterBitWidth = 64U; - } else if (line.find("bits 32") != std::string::npos) { - kRegisterBitWidth = 32U; - } else if (line.find("bits 16") != std::string::npos) { - kRegisterBitWidth = 16U; - } else if (line.find("org") != std::string::npos) { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) { - if (kOrigin = strtol((line.substr(line.find("org") + strlen("org") + 1)).c_str(), nullptr, - base[i]); - kOrigin) { - if (errno != 0) { - continue; - } else { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Origin Set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += kIPAlignement; - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc deleted file mode 100644 index 4961e61..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc +++ /dev/null @@ -1,587 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerARM64.cc -/// @author Amlal El Mahrouss -/// @brief 'ACORN' Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_ARM64__ -#define __ASM_NEED_ARM64__ 1 -#endif - -#include <CompilerKit/AE.h> -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/Version.h> -#include <CompilerKit/impl/Aarch64.h> -#include <CompilerKit/utils/AsmUtils.h> -#include <algorithm> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <vector> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -constexpr auto cPowerIPAlignment = 0x1U; - -static Char kOutputArch = CompilerKit::kPefArchARM64; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; - -static std::vector<uint8_t> kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector<CompilerKit::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainARM64) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { - kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: " << kDistVersion - << "\nAssemblerPower: " - "Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--h") == 0) { - kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version,/v: print program version.\n"; - kStdOut << "--verbose: print verbose output.\n"; - kStdOut << "--binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerPower: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerPower: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerPower: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderARM64 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerARM64: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerARM64: At least one record is needed to write an object " - "file.\nAssemblerARM64: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerARM64: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerARM64: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n"; - - return NECTI_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_arm64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderARM64::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!Detail::algorithm::is_valid_arm64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_arm64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - return err_str; -} - -bool CompilerKit::EncoderARM64::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderARM64::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment")) return false; - - if (!Detail::algorithm::is_valid_arm64(line)) return false; - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc deleted file mode 100644 index b4f14ea..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc +++ /dev/null @@ -1,911 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerPower.cc -/// @author Amlal El Mahrouss -/// @brief POWER Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_PPC__ -#define __ASM_NEED_PPC__ 1 -#endif - -#include <CompilerKit/AE.h> -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/Version.h> -#include <CompilerKit/impl/PowerPC.h> -#include <CompilerKit/utils/AsmUtils.h> -#include <algorithm> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <vector> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -constexpr auto cPowerIPAlignment = 0x4U; - -static Char kOutputArch = CompilerKit::kPefArchPowerPC; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; - -static std::vector<uint8_t> kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector<CompilerKit::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainPower64) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { - kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion - << "\nAssemblerPower: " - "Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--h") == 0) { - kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version,/v: print program version.\n"; - kStdOut << "--verbose: print verbose output.\n"; - kStdOut << "--binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerPower: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerPower: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerPower: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerPower: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerPower: At least one record is needed to write an object " - "file.\nAssemblerPower: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) kStdOut << "AssemblerPower: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerPower: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "AssemblerPower: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerPower: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n"; - - return NECTI_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_power64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderPowerPC::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!Detail::algorithm::is_valid_power64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_power64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector<std::string> operands_inst = {"stw", "li"}; - - // these don't. - std::vector<std::string> filter_inst = {"blr", "bl", "sc"}; - - for (auto& opcode_risc : kOpcodesPowerPC) { - if (CompilerKit::find_word(line, opcode_risc.name)) { - for (auto& op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode_risc.name); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcode_risc.name)) { - if (!isspace(line[line.find(opcode_risc.name) + strlen(opcode_risc.name)])) { - err_str += "\nMissing space between "; - err_str += opcode_risc.name; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderPowerPC::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment")) return false; - if (!Detail::algorithm::is_valid_power64(line)) return false; - - for (auto& opcode_risc : kOpcodesPowerPC) { - // strict check here - if (CompilerKit::find_word(line, opcode_risc.name)) { - std::string name(opcode_risc.name); - std::string jump_label, cpy_jump_label; - std::vector<size_t> found_registers_index; - - // check funct7 type. - switch (opcode_risc.ops->type) { - default: { - NumberCast32 num(opcode_risc.opcode); - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - break; - } - case BADDR: - case PCREL: { - auto num = GetNumber32(line, name); - - kBytes.emplace_back(num.number[0]); - kBytes.emplace_back(num.number[1]); - kBytes.emplace_back(num.number[2]); - kBytes.emplace_back(0x48); - - break; - } - /// General purpose, float, vector operations. Everything that involve - /// registers. - case G0REG: - case FREG: - case VREG: - case GREG: { - // \brief how many registers we found. - std::size_t found_some_count = 0UL; - std::size_t register_count = 0UL; - std::string opcodeName = opcode_risc.name; - std::size_t register_sum = 0; - - NumberCast64 num(opcode_risc.opcode); - - for (size_t line_index = 0UL; line_index < line.size(); line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - Detail::print_error("invalid register index, r" + reg_str + - "\nnote: The POWER accepts registers from r0 to r32.", - file); - throw std::runtime_error("invalid_register_index"); - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - Detail::print_error("invalid register index, r" + reg_str, file); - throw std::runtime_error("invalid_register_index"); - } - - if (opcodeName == "li") { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - auto num = GetNumber32(line, reg_str); - - kBytes.push_back(num.number[0]); - kBytes.push_back(num.number[1]); - kBytes.push_back(numIndex); - kBytes.push_back(0x38); - - // check if bigger than two. - for (size_t i = 2; i < 4; i++) { - if (num.number[i] > 0) { - Detail::print_warning("number overflow on li operation.", file); - break; - } - } - - break; - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - if (register_sum == 0) { - for (size_t indexReg = 0UL; indexReg < reg_index; ++indexReg) { - register_sum += 0x20; - } - } else { - register_sum += reg_index; - } - } - - if (opcodeName == "mr") { - switch (register_count) { - case 0: { - kBytes.push_back(0x78); - - char numIndex = 0x3; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x8; - } - - kBytes.push_back(numIndex); - - break; - } - case 1: { - char numIndex = 0x1; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - for (size_t i = 0; i != reg_index; i++) { - kBytes[kBytes.size() - 1] += 0x8; - } - - kBytes[kBytes.size() - 1] -= 0x8; - - kBytes.push_back(numIndex); - - if (reg_index >= 10 && reg_index < 20) - kBytes.push_back(0x7d); - else if (reg_index >= 20 && reg_index < 30) - kBytes.push_back(0x7e); - else if (reg_index >= 30) - kBytes.push_back(0x7f); - else - kBytes.push_back(0x7c); - - break; - } - default: - break; - } - - ++register_count; - ++found_some_count; - } - - if (opcodeName == "addi") { - if (found_some_count == 2 || found_some_count == 0) - kBytes.emplace_back(reg_index); - else if (found_some_count == 1) - kBytes.emplace_back(0x00); - - ++found_some_count; - - if (found_some_count > 3) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("cmp") != std::string::npos) { - ++found_some_count; - - if (found_some_count > 3) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("mf") != std::string::npos || - opcodeName.find("mt") != std::string::npos) { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - num.number[2] += numIndex; - - ++found_some_count; - - if (found_some_count > 1) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: Found register: " << register_syntax << "\n"; - kStdOut << "AssemblerPower: Amount of registers in instruction: " - << found_some_count << "\n"; - } - - if (reg_index >= 10 && reg_index < 20) - num.number[3] = 0x7d; - else if (reg_index >= 20 && reg_index < 30) - num.number[3] = 0x7e; - else if (reg_index >= 30) - num.number[3] = 0x7f; - else - num.number[3] = 0x7c; - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - } - - found_registers_index.push_back(reg_index); - } - } - - if (opcodeName == "addi") { - kBytes.emplace_back(0x38); - } - - if (opcodeName.find("cmp") != std::string::npos) { - char rightReg = 0x0; - - for (size_t i = 0; i != found_registers_index[1]; i++) { - rightReg += 0x08; - } - - kBytes.emplace_back(0x00); - kBytes.emplace_back(rightReg); - kBytes.emplace_back(found_registers_index[0]); - kBytes.emplace_back(0x7c); - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - size_t offset = 0UL; - - if (line.find('+') != std::string::npos) { - auto number = GetNumber32(line.substr(line.find("+")), "+"); - offset = number.raw; - } - - kBytes.push_back(offset); - kBytes.push_back(0x00); - kBytes.push_back(register_sum); - - kBytes.emplace_back(0x90); - } - - if (opcodeName == "mr") { - if (register_count == 1) { - Detail::print_error("Too few registers. -> " + line, file); - throw std::runtime_error("too_few_registers"); - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode_risc.ops->type != GREG) { - // remember! register to register! - if (found_some_count == 1) { - Detail::print_error( - "Unrecognized register found.\ntip: each AssemblerPower register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Frontend.cc b/dev/CompilerKit/src/Frontend.cc deleted file mode 100644 index baac34e..0000000 --- a/dev/CompilerKit/src/Frontend.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#include <CompilerKit/Frontend.h> - -/** - * @file Frontend.cc - * @author Amlal El Mahrouss (amlal@nekernel.org) - * @brief Frontend API of NeCTI - * @version 0.0.2 - * - * @copyright Copyright (c) 2025 Amlal El Mahrouss and NeKernel.org Contributors - * - */ - -namespace CompilerKit { -/// find the perfect matching word in a haystack. -/// \param haystack base string -/// \param needle the string we search for. -/// \return if we found it or not. -Bool find_word(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::npos) return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) return true; - - if (index <= 0 || index >= haystack.size()) return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); -} - -/// find a word within strict conditions and returns a range of it. -/// \param haystack -/// \param needle -/// \return position of needle. -SizeType find_word_range(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::npos) return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) { - return index; - } - - return STLString::npos; -} -} // namespace CompilerKit
\ No newline at end of file diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc deleted file mode 100644 index f07fcb0..0000000 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 -/// TODO: none - -#include <CompilerKit/Frontend.h> -#include <CompilerKit/UUID.h> -#include <CompilerKit/impl/64x0.h> -#include <CompilerKit/utils/CompilerUtils.h> -#include <cstdio> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -/* C driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file 64x0-cc.cc -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kExitOK (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief Register map structure, used to keep track of each variable's registers. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontend64x0 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontend64x0() = default; - ~CompilerFrontend64x0() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontend64x0); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "64k C"; } -}; - -static CompilerFrontend64x0* kCompilerFrontend = nullptr; -static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; -static std::vector<Detail::CompilerType> kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::string text_, - std::string file) { - std::string text = text_; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value in struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "public_segment .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return syntaxLeaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontend64x0::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector<std::string> forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("--*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector<CompilerVariableRange> variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - NECTI_COPY_DEFAULT(AssemblyCCInterface); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArch64x0; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector<std::string> keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), - range.size(), needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <CompilerKit/Version.h> - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NECTI_MODULE(CompilerCLang64x0) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerFrontend = new CompilerFrontend64x0(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "--v") == 0 || strcmp(argv[index], "--version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "--verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "--dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "--fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc deleted file mode 100644 index c5b1fb8..0000000 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ /dev/null @@ -1,1286 +0,0 @@ -/* - * ======================================================== - * - * CCompilerARM64 - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 -/// TODO: none - -#include <CompilerKit/Frontend.h> -#include <CompilerKit/UUID.h> -#include <CompilerKit/impl/Aarch64.h> -#include <CompilerKit/utils/CompilerUtils.h> - -#include <cstdio> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -/* C driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file ARM64-cc.cc -/// @brief ARM64 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kExitOK (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief Register map structure, used to keep track of each variable's registers. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontendARM64 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontendARM64() = default; - ~CompilerFrontendARM64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendARM64); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "64k C"; } -}; - -static CompilerFrontendARM64* kCompilerFrontend = nullptr; -static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; -static std::vector<Detail::CompilerType> kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::string text, - std::string file) { - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value in struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "public_segment .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return syntaxLeaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontendARM64::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector<std::string> forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("--*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector<CompilerVariableRange> variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - NECTI_COPY_DEFAULT(AssemblyCCInterface); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAARCH64; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: ARM64 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector<std::string> keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), - range.size(), needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <CompilerKit/Version.h> - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kCExtension ".c" - -NECTI_MODULE(CompilerCLangARM64) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArchAARCH64; - kCompilerFrontend = new CompilerFrontendARM64(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "--v") == 0 || strcmp(argv[index], "--version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "--verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "--dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "--fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kCExtension) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc deleted file mode 100644 index ccc5cf8..0000000 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * ======================================================== - * - * CompilerPower64 - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#include <CompilerKit/Frontend.h> -#include <CompilerKit/UUID.h> -#include <CompilerKit/impl/PowerPC.h> -#include <CompilerKit/utils/CompilerUtils.h> -#include <cstdio> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -#define kExitOK 0 - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file cc.cc -/// @brief POWER64 C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCTURES OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontendPower64 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontendPower64() = default; - ~CompilerFrontendPower64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendPower64); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "POWER C"; } -}; - -static CompilerFrontendPower64* kCompilerFrontend = nullptr; -static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; -static std::vector<Detail::CompilerType> kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::string text_, - std::string file) { - std::string text = text_; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntax_leaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntax_leaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntax_leaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) value.erase(value.find(' '), 1); - - while (value.find("extern_segment") != std::string::npos) - value.erase(value.find("extern_segment"), strlen("extern_segment")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) { - if (value.find(reg.fName) != std::string::npos) { - found = true; - syntax_leaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) syntax_leaf.fUserValue += "r0"; - } - - syntax_leaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntax_leaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntax_leaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction + - " \ndword public_segment .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value inside a struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } else { - substr += "\tli "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - kCompilerVariables.push_back({.fName = substr}); - - if (text[text_index] == ';') break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) { - if (newSubstr[start] == ',') break; - - if (newSubstr[start] == ' ') continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntax_leaf.fUserValue += "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntax_leaf.fUserValue = args; - syntax_leaf.fUserValue += substr; - - syntax_leaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - fnFound = true; - } else { - syntax_leaf.fUserValue.clear(); - - syntax_leaf.fUserValue += "public_segment .code64 "; - - syntax_leaf.fUserValue += substr; - syntax_leaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntax_leaf.fUserValue += "dec "; - syntax_leaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - syntax_leaf.fUserValue.clear(); - } - - auto syntax_leaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntax_leaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - return syntax_leaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontendPower64::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector<std::string> forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("--*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto& forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector<CompilerVariableRange> variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - NECTI_COPY_DEFAULT(AssemblyMountpointCLang); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchPowerPC; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector<std::string> keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment ") != std::string::npos) { - std::string range = "extern_segment "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <CompilerKit/Version.h> - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NECTI_MODULE(CompilerCLangPowerPC) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerFrontend = new CompilerFrontendPower64(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc deleted file mode 100644 index d715a3a..0000000 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ /dev/null @@ -1,906 +0,0 @@ -/* - * ======================================================== - * - * C++ Compiler Driver - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 - -/////////////////////// - -// ANSI ESCAPE CODES // - -/////////////////////// - -/////////////////////// - -// MACROS // - -/////////////////////// - -#define kPrintF printf -#define kPrintErr std::cerr - -#define kExitOK (EXIT_SUCCESS) -#define kExitNO (EXIT_FAILURE) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -#include <CompilerKit/Frontend.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/UUID.h> -#include <CompilerKit/impl/X64.h> -#include <CompilerKit/utils/CompilerUtils.h> -#include <csignal> -#include <cstdlib> - -/* NeKernel C++ Compiler Driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss 2024-2025 */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file CPlusPlusCompilerAMD64.cxx -/// @brief Optimized C++ Compiler Driver. - -///////////////////////////////////// - -// INTERNALS OF THE C++ COMPILER - -///////////////////////////////////// - -/// @internal -// Avoids relative_path which could discard parts of the original. -std::filesystem::path necti_expand_home(const std::filesystem::path& input) { - const std::string& raw = input.string(); - - if (!raw.empty() && raw[0] == '~') { - const char* home = std::getenv("HOME"); - if (!home) home = std::getenv("USERPROFILE"); - - if (!home) throw std::runtime_error("Home directory not found in environment variables"); - - return std::filesystem::path(home) / raw.substr(1); - } - - return input; -} - -struct CompilerRegisterMap final { - CompilerKit::STLString fName{}; - CompilerKit::STLString fReg{}; -}; - -/// \brief Offset based struct/class -struct CompilerStructMap final { - CompilerKit::STLString fName{}; - CompilerKit::STLString fReg{}; - std::vector<std::pair<UInt32, CompilerKit::STLString>> fOffsets; -}; - -/// \brief Compiler state structure. -struct CompilerState final { - std::vector<CompilerRegisterMap> fStackMapVector; - std::vector<CompilerStructMap> fStructMapVector; - CompilerKit::STLString fLastFile{}; - CompilerKit::STLString fLastError{}; -}; - -static CompilerState kState; - -static Int32 kOnClassScope = 0; - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static Int32 kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static std::vector<CompilerKit::CompilerKeyword> kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static CompilerKit::AssemblyFactory kAssembler; -static Boolean kInStruct = false; -static Boolean kOnWhileLoop = false; -static Boolean kOnForLoop = false; -static Boolean kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for the NeKernel C++ driver */ -class CompilerFrontendCPlusPlusAMD64 final CK_COMPILER_FRONTEND { - public: - explicit CompilerFrontendCPlusPlusAMD64() = default; - ~CompilerFrontendCPlusPlusAMD64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendCPlusPlusAMD64); - - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(const CompilerKit::STLString text, - CompilerKit::STLString file) override; - - const char* Language() override; -}; - -/// @internal compiler variables - -static CompilerFrontendCPlusPlusAMD64* kFrontend = nullptr; - -static std::vector<CompilerKit::STLString> kRegisterMap; - -static std::vector<CompilerKit::STLString> kRegisterList = { - "rbx", "rsi", "r10", "r11", "r12", "r13", "r14", "r15", "xmm12", "xmm13", "xmm14", "xmm15", -}; - -/// @brief The PEF calling convention (caller must save rax, rbp) -/// @note callee must return via **rax**. -static std::vector<CompilerKit::STLString> kRegisterConventionCallList = { - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", -}; - -static std::size_t kFunctionEmbedLevel = 0UL; - -/// detail namespaces - -const char* CompilerFrontendCPlusPlusAMD64::Language() { - return "AMD64 C++"; -} - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<CompilerKit::STLString, std::uintptr_t>> kOriginMap; - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @name Compile -/// @brief Generate assembly from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( - CompilerKit::STLString text, CompilerKit::STLString file) { - CompilerKit::SyntaxLeafList::SyntaxLeaf syntax_tree; - - if (text.empty()) return syntax_tree; - - std::size_t index = 0UL; - std::vector<std::pair<CompilerKit::CompilerKeyword, std::size_t>> keywords_list; - - for (auto& keyword : kKeywords) { - if (text.find(keyword.keyword_name) != std::string::npos) { - switch (keyword.keyword_kind) { - case CompilerKit::kKeywordKindCommentInline: { - break; - } - default: - break; - } - - std::size_t pos = text.find(keyword.keyword_name); - if (pos == std::string::npos) continue; - - // can't go before start of string - if (pos > 0 && text[pos - 1] == '+' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - if (pos > 0 && text[pos - 1] == '-' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - // don't go out of range - if ((pos + keyword.keyword_name.size()) < text.size() && - text[pos + keyword.keyword_name.size()] == '=' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - } - } - - for (auto& keyword : keywords_list) { - if (text.find(keyword.first.keyword_name) == CompilerKit::STLString::npos) continue; - - switch (keyword.first.keyword_kind) { - case CompilerKit::KeywordKind::kKeywordKindClass: { - ++kOnClassScope; - break; - } - case CompilerKit::KeywordKind::kKeywordKindIf: { - std::size_t keywordPos = text.find(keyword.first.keyword_name); - std::size_t openParen = text.find("(", keywordPos); - std::size_t closeParen = text.find(")", openParen); - - if (keywordPos == CompilerKit::STLString::npos || - openParen == CompilerKit::STLString::npos || - closeParen == CompilerKit::STLString::npos || closeParen <= openParen) { - Detail::print_error("Malformed if expression: " + text, file); - break; - } - - auto expr = text.substr(openParen + 1, closeParen - openParen - 1); - - if (expr.find(">=") != CompilerKit::STLString::npos) { - auto left = text.substr( - text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, - expr.find("<=") + strlen("<=")); - auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - - // Trim whitespace - while (!right.empty() && (right.back() == ' ' || right.back() == '\t')) { - right.pop_back(); - } - while (!right.empty() && (right.front() == ' ' || right.front() == '\t')) { - right.erase(0, 1); - } - - while (!left.empty() && (left.back() == ' ' || left.back() == '\t')) { - left.pop_back(); - } - while (!left.empty() && (left.front() == ' ' || left.front() == '\t')) { - left.erase(0, 1); - } - - if ((!left.empty() && !isdigit(left[0])) || (!right.empty() && !isdigit(right[0]))) { - auto indexRight = 0UL; - - auto& valueOfVar = (!left.empty() && !isdigit(left[0])) ? left : right; - - if (!valueOfVar.empty()) { - for (auto pairRight : kRegisterMap) { - ++indexRight; - - CompilerKit::STLString instr = "mov "; - - if (pairRight != valueOfVar) { - auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; - - syntax_tree.fUserValue += - instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + - kRegisterList[indexRight + 1] + "\n"; - - goto lc_done_iterarting_on_if; - } - - auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; - - syntax_tree.fUserValue += - instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + - kRegisterList[indexRight + 1] + "\n"; - - break; - } - } - } - - lc_done_iterarting_on_if: - - CompilerKit::STLString symbol_name_fn = text; - - symbol_name_fn.erase(symbol_name_fn.find(keyword.first.keyword_name)); - - for (auto& ch : symbol_name_fn) { - if (ch == ' ') ch = '_'; - } - - syntax_tree.fUserValue += - "jge __OFFSET_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n"; - } - - break; - } - case CompilerKit::KeywordKind::kKeywordKindFunctionStart: { - for (auto& ch : text) { - if (isdigit(ch)) { - goto dont_accept; - } - } - - goto accept; - - dont_accept: - break; - - accept: - CompilerKit::STLString symbol_name_fn = text; - size_t indexFnName = 0; - - // this one is for the type. - for (auto& ch : text) { - ++indexFnName; - - if (ch == '\t') break; - if (ch == ' ') break; - } - - symbol_name_fn = text.substr(indexFnName); - - if (text.find("return ") != CompilerKit::STLString::npos) { - text.erase(0, text.find("return ")); - break; - } - - if (text.ends_with(";") && text.find("return") == CompilerKit::STLString::npos) - goto lc_write_assembly; - else if (text.size() <= indexFnName) - Detail::print_error("Invalid function name: " + symbol_name_fn, file); - - indexFnName = 0; - - for (auto& ch : symbol_name_fn) { - if (ch == ' ' || ch == '\t') { - if (symbol_name_fn[indexFnName - 1] != ')') - Detail::print_error("Invalid function name: " + symbol_name_fn, file); - } - - ++indexFnName; - } - - if (symbol_name_fn.find("(") != CompilerKit::STLString::npos) { - symbol_name_fn.erase(symbol_name_fn.find("(")); - } - - syntax_tree.fUserValue = "public_segment .code64 __NECTI_" + symbol_name_fn + "\n"; - ++kFunctionEmbedLevel; - - kOriginMap.push_back({"__NECTI_" + symbol_name_fn, kOrigin}); - - break; - - lc_write_assembly: - auto it = std::find_if( - kOriginMap.begin(), kOriginMap.end(), - [&symbol_name_fn](std::pair<CompilerKit::STLString, std::uintptr_t> pair) -> bool { - return symbol_name_fn == pair.first; - }); - - if (it != kOriginMap.end()) { - std::stringstream ss; - ss << std::hex << it->second; - - syntax_tree.fUserValue = "jmp " + ss.str() + "\n"; - kOrigin += 1UL; - } - } - case CompilerKit::KeywordKind::kKeywordKindFunctionEnd: { - if (kOnClassScope) --kOnClassScope; - - if (text.ends_with(";")) break; - - --kFunctionEmbedLevel; - - if (kRegisterMap.size() > kRegisterList.size()) { - --kFunctionEmbedLevel; - } - - if (kFunctionEmbedLevel < 1) kRegisterMap.clear(); - - break; - } - case CompilerKit::KeywordKind::kKeywordKindEndInstr: - case CompilerKit::KeywordKind::kKeywordKindVariableInc: - case CompilerKit::KeywordKind::kKeywordKindVariableDec: - case CompilerKit::KeywordKind::kKeywordKindVariableAssign: { - CompilerKit::STLString valueOfVar = ""; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - valueOfVar = text.substr(text.find("+=") + 2); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - valueOfVar = text.substr(text.find("-=") + 2); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableAssign) { - valueOfVar = text.substr(text.find("=") + 1); - } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - break; - } - - while (valueOfVar.find(";") != CompilerKit::STLString::npos && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindEndInstr) { - valueOfVar.erase(valueOfVar.find(";")); - } - - CompilerKit::STLString varName = text; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - varName.erase(varName.find("+=")); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - varName.erase(varName.find("-=")); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableAssign) { - varName.erase(varName.find("=")); - } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - varName.erase(varName.find(";")); - } - - static Boolean typeFound = false; - - for (auto& keyword : kKeywords) { - if (keyword.keyword_kind == CompilerKit::kKeywordKindType) { - if (text.find(keyword.keyword_name) != CompilerKit::STLString::npos) { - if (text[text.find(keyword.keyword_name)] == ' ') { - typeFound = false; - continue; - } - - typeFound = true; - } - } - } - - CompilerKit::STLString instr = "mov "; - - std::vector<CompilerKit::STLString> newVars; - - if (typeFound && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableInc && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableDec) { - if (kRegisterMap.size() > kRegisterList.size()) { - ++kFunctionEmbedLevel; - } - - while (varName.find(" ") != CompilerKit::STLString::npos) { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != CompilerKit::STLString::npos) { - varName.erase(varName.find("\t"), 1); - } - - // Remove whitespace only (keep operators and quotes) - while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { - valueOfVar.erase(0, 1); - } - - constexpr auto kTrueVal = "true"; - constexpr auto kFalseVal = "false"; - - if (valueOfVar == kTrueVal) { - valueOfVar = "1"; - } else if (valueOfVar == kFalseVal) { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) { - ++indexRight; - - if (pairRight != valueOfVar) { - if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + - valueOfVar + ", 0\n\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + - "__NECTI_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } else { - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - } - - goto done; - } - } - - if (((int) indexRight - 1) < 0) { - if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = - "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + - "__NECTI_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } else { - auto mangled = valueOfVar; - - if (mangled.find("(") != std::string::npos) { - auto ret = mangled.erase(mangled.find("(")); - mangled = "__NECTI_"; - mangled += ret; - - syntax_tree.fUserValue = "jmp " + mangled + "\n"; - syntax_tree.fUserValue += - instr + " rax, " + kRegisterList[kRegisterMap.size()] + "\n"; - - goto done; - } - - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size()] + ", " + mangled + "\n"; - kOrigin += 1UL; - } - - goto done; - } - - if (!valueOfVar.empty() && valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && - !isdigit(valueOfVar[0])) { - for (auto pair : kRegisterMap) { - if (pair == valueOfVar) goto done; - } - - Detail::print_error("Variable not declared: " + varName, file); - break; - } - - done: - for (auto& keyword : kKeywords) { - if (keyword.keyword_kind == CompilerKit::kKeywordKindType && - varName.find(keyword.keyword_name) != CompilerKit::STLString::npos) { - varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); - break; - } - } - - newVars.push_back(varName); - - break; - } - - kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); - - if (keyword.second > 0 && - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindTypePtr) { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - instr = "add "; - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - instr = "sub "; - } - - CompilerKit::STLString varErrCpy = varName; - - while (varName.find(" ") != CompilerKit::STLString::npos) { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != CompilerKit::STLString::npos) { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { - valueOfVar.erase(0, 1); - } - - while (valueOfVar.find(" ") != CompilerKit::STLString::npos) { - valueOfVar.erase(valueOfVar.find(" "), 1); - } - - while (valueOfVar.find("\t") != CompilerKit::STLString::npos) { - valueOfVar.erase(valueOfVar.find("\t"), 1); - } - - constexpr auto kTrueVal = "true"; - constexpr auto kFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == kTrueVal) { - valueOfVar = "1"; - } else if (valueOfVar == kFalseVal) { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) { - ++indxReg; - - if (pair != varName) continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) { - ++indexRight; - - if (pairRight != varName) { - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - continue; - } - - syntax_tree.fUserValue = - instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - break; - } - - newVars.push_back(varName); - break; - } - - if (syntax_tree.fUserValue.empty()) { - Detail::print_error("Variable not declared: " + varName, file); - } - - kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); - - break; - } - case CompilerKit::KeywordKind::kKeywordKindReturn: { - try { - auto pos = text.find("return") + strlen("return") + 1; - CompilerKit::STLString subText = text.substr(pos); - if (subText.find(";") == CompilerKit::STLString::npos) break; - - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (!subText.empty() && subText[0] != '\"' && subText[0] != '\'') { - if (!isdigit(subText[0])) { - for (auto pair : kRegisterMap) { - ++indxReg; - - syntax_tree.fUserValue = "mov rax, " + kRegisterList[indxReg - 1] + "\nret\n"; - kOrigin += 1UL; - - break; - } - } else { - syntax_tree.fUserValue = "mov rax, " + subText + "\nret\n"; - kOrigin += 1UL; - - break; - } - } else { - syntax_tree.fUserValue = "__NECTI_LOCAL_RETURN_STRING: db " + subText + - ", 0\nmov rcx, __NECTI_LOCAL_RETURN_STRING\n"; - syntax_tree.fUserValue += "mov rax, rcx\nret\n"; - kOrigin += 1UL; - - break; - } - - if (syntax_tree.fUserValue.empty()) { - if (subText.find("(") != CompilerKit::STLString::npos) { - subText.erase(subText.find("(")); - - auto it = std::find_if( - kOriginMap.begin(), kOriginMap.end(), - [&subText](std::pair<CompilerKit::STLString, std::uintptr_t> pair) -> bool { - return pair.first.find(subText) != CompilerKit::STLString::npos; - }); - - if (it == kOriginMap.end()) - Detail::print_error("Invalid return value: " + subText, file); - - std::stringstream ss; - ss << it->second; - - syntax_tree.fUserValue = "jmp " + ss.str() + "\nret\n"; - kOrigin += 1UL; - break; - } - } - - syntax_tree.fUserValue = "ret\n"; - kOrigin += 1UL; - - break; - } catch (...) { - syntax_tree.fUserValue = "ret\n"; - kOrigin += 1UL; - - break; - } - } - default: { - continue; - } - } - } - - return syntax_tree; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C++ assembler class. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCPlusPlusInterfaceAMD64 final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCPlusPlusInterfaceAMD64() = default; - ~AssemblyCPlusPlusInterfaceAMD64() override = default; - - NECTI_COPY_DEFAULT(AssemblyCPlusPlusInterfaceAMD64); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAMD64; } - - Int32 CompileToFormat(CompilerKit::STLString src, Int32 arch) override { - if (kFrontend == nullptr) return kExitNO; - - CompilerKit::STLString dest = src; - dest += ".pp.masm"; - - std::ofstream out_fp(dest); - std::ifstream src_fp = std::ifstream(src + ".pp"); - - CompilerKit::STLString line_source; - - out_fp << "%bits 64\n"; - out_fp << "%org " << kOrigin << "\n\n"; - - while (std::getline(src_fp, line_source)) { - out_fp << kFrontend->Compile(line_source, src).fUserValue; - } - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { ".cpp", ".cxx", ".cc", ".c++", ".cp" } - -NECTI_MODULE(CompilerCPlusPlusAMD64) { - Boolean skip = false; - - kKeywords.emplace_back("if", CompilerKit::kKeywordKindIf); - kKeywords.emplace_back("else", CompilerKit::kKeywordKindElse); - kKeywords.emplace_back("else if", CompilerKit::kKeywordKindElseIf); - - kKeywords.emplace_back("class", CompilerKit::kKeywordKindClass); - kKeywords.emplace_back("struct", CompilerKit::kKeywordKindClass); - kKeywords.emplace_back("namespace", CompilerKit::kKeywordKindNamespace); - kKeywords.emplace_back("typedef", CompilerKit::kKeywordKindTypedef); - kKeywords.emplace_back("using", CompilerKit::kKeywordKindTypedef); - kKeywords.emplace_back("{", CompilerKit::kKeywordKindBodyStart); - kKeywords.emplace_back("}", CompilerKit::kKeywordKindBodyEnd); - kKeywords.emplace_back("auto", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("int", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("bool", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("unsigned", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("short", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("char", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("long", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("float", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("double", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("void", CompilerKit::kKeywordKindType); - - kKeywords.emplace_back("auto*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("int*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("bool*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("unsigned*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("short*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("char*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("long*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("float*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("double*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("void*", CompilerKit::kKeywordKindTypePtr); - - kKeywords.emplace_back("(", CompilerKit::kKeywordKindFunctionStart); - kKeywords.emplace_back(")", CompilerKit::kKeywordKindFunctionEnd); - kKeywords.emplace_back("=", CompilerKit::kKeywordKindVariableAssign); - kKeywords.emplace_back("+=", CompilerKit::kKeywordKindVariableInc); - kKeywords.emplace_back("-=", CompilerKit::kKeywordKindVariableDec); - kKeywords.emplace_back("const", CompilerKit::kKeywordKindConstant); - kKeywords.emplace_back("*", CompilerKit::kKeywordKindPtr); - kKeywords.emplace_back("->", CompilerKit::kKeywordKindPtrAccess); - kKeywords.emplace_back(".", CompilerKit::kKeywordKindAccess); - kKeywords.emplace_back(",", CompilerKit::kKeywordKindArgSeparator); - kKeywords.emplace_back(";", CompilerKit::kKeywordKindEndInstr); - kKeywords.emplace_back(":", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("public:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("private:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("protected:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("final", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("return", CompilerKit::kKeywordKindReturn); - kKeywords.emplace_back("/*", CompilerKit::kKeywordKindCommentMultiLineStart); - kKeywords.emplace_back("*/", CompilerKit::kKeywordKindCommentMultiLineEnd); - kKeywords.emplace_back("//", CompilerKit::kKeywordKindCommentInline); - kKeywords.emplace_back("==", CompilerKit::kKeywordKindEq); - kKeywords.emplace_back("!=", CompilerKit::kKeywordKindNotEq); - kKeywords.emplace_back(">=", CompilerKit::kKeywordKindGreaterEq); - kKeywords.emplace_back("<=", CompilerKit::kKeywordKindLessEq); - - kErrorLimit = 0; - - kFrontend = new CompilerFrontendCPlusPlusAMD64(); - kAssembler.Mount(new AssemblyCPlusPlusInterfaceAMD64()); - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - // Ensure cleanup on exit - std::atexit([]() { - delete kFrontend; - kFrontend = nullptr; - }); - - for (auto index = 1UL; index < argc; ++index) { - if (!argv[index]) break; - - if (argv[index][0] == '-') { - if (skip) { - skip = false; - continue; - } - - if (strcmp(argv[index], "-cxx-verbose") == 0) { - kVerbose = true; - continue; - } - - if (strcmp(argv[index], "-cxx-dialect") == 0) { - if (kFrontend) std::cout << kFrontend->Language() << "\n"; - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cxx-max-err") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - CompilerKit::STLString err = "Unknown option: "; - err += argv[index]; - - Detail::print_error(err, "cxxdrv"); - - continue; - } - - CompilerKit::STLString argv_i = argv[index]; - - std::vector<CompilerKit::STLString> exts = kExtListCxx; - - for (CompilerKit::STLString ext : exts) { - if (argv_i.ends_with(ext)) { - if (kAssembler.Compile(argv_i, kMachine) != kExitOK) { - return NECTI_INVALID_DATA; - } - - break; - } - } - } - - kAssembler.Unmount(); - - return NECTI_SUCCESS; -} - -// -// Last rev 25-8-7 -// diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc deleted file mode 100644 index 8a503ed..0000000 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ /dev/null @@ -1,678 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - - @file DynamicLinker64PEF.cc - @brief: C++ 64-Bit PEF Linker for NeKernel.org's NeKernel - -======================================== */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @brief NeKernel.org 64-bit PEF Linker. -/// Last Rev: Sat Apr 19 CET 2025 -/// @note Do not look up for anything with .code64/.data64/.zero64! -/// It will be loaded when the program loader will start the image. - -#include <CompilerKit/AE.h> -#include <CompilerKit/Compiler.h> -#include <CompilerKit/Defines.h> -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/PEF.h> -#include <CompilerKit/UUID.h> -#include <CompilerKit/Version.h> -#include <CompilerKit/utils/CompilerUtils.h> - -#define kLinkerVersionStr "NeCTI 64-Bit Linker (Preferred Executable Format)" - -#define kPefNoCpu (0U) -#define kPefNoSubCpu (0U) - -#define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId (0x5046FF) -#define kLinkerAbiContainer "__PEFContainer:ABI:" - -#define kPrintF printf -#define kLinkerSplash() kConsoleOut << kLinkerVersionStr << std::endl - -/// @brief PEF stack size symbol. -#define kLinkerStackSizeSymbol "__PEFSizeOfReserveStack" - -#define kConsoleOut \ - (std::cout << "\e[0;31m" \ - << "ld64: " \ - << "\e[0;97m") - -enum { - kABITypeNull = 0, - kABITypeStart = 0x1010, /* The start of ABI list. */ - kABITypeNE = 0x5046, /* PF (NeKernel.org's PEF ABI) */ - kABITypeInvalid = 0xFFFF, -}; - -static CompilerKit::STLString kOutput = "a" kPefExt; -static Int32 kAbi = kABITypeNE; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArchInvalid; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; - -/* ld64 is to be found, mld is to be found at runtime. */ -static const Char* kLdDefineSymbol = ":UndefinedSymbol:"; -static const Char* kLdDynamicSym = ":RuntimeSymbol:"; - -static CompilerKit::STLString kLinkerStart = kPefStart; - -/* object code and list. */ -static std::vector<CompilerKit::STLString> kObjectList; -static std::vector<Detail::DynamicLinkerBlob> kObjectBytes; - -/// @brief NE 64-bit Linker. -/// @note This linker is made for PEF executable, thus NE based OSes. -NECTI_MODULE(DynamicLinker64PEF) { - bool is_executable = true; - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - /** - * @brief parse flags and trigger options. - */ - for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) { - if (std::strcmp(argv[linker_arg], "-help") == 0) { - kLinkerSplash(); - - kConsoleOut << "-version: Show linker version.\n"; - kConsoleOut << "-help: Show linker help.\n"; - kConsoleOut << "-verbose: Enable linker trace.\n"; - kConsoleOut << "-dylib: Output as a Dynamic PEF.\n"; - kConsoleOut << "-fat: Output as a FAT PEF.\n"; - kConsoleOut << "-32k: Output as a 32x0 PEF.\n"; - kConsoleOut << "-64k: Output as a 64x0 PEF.\n"; - kConsoleOut << "-amd64: Output as a AMD64 PEF.\n"; - kConsoleOut << "-rv64: Output as a RISC-V PEF.\n"; - kConsoleOut << "-power64: Output as a POWER PEF.\n"; - kConsoleOut << "-arm64: Output as a ARM64 PEF.\n"; - kConsoleOut << "-output: Select the output file name.\n"; - - return NECTI_SUCCESS; - } else if (std::strcmp(argv[linker_arg], "-version") == 0) { - kLinkerSplash(); - - return NECTI_SUCCESS; - } else if (std::strcmp(argv[linker_arg], "-fat") == 0) { - kFatBinaryEnable = true; - - continue; - } else if (std::strcmp(argv[linker_arg], "-64k") == 0) { - kArch = CompilerKit::kPefArch64000; - - continue; - } else if (std::strcmp(argv[linker_arg], "-amd64") == 0) { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } else if (std::strcmp(argv[linker_arg], "-start") == 0) { - if (argv[linker_arg + 1] == nullptr || argv[linker_arg + 1][0] == '-') continue; - - kLinkerStart = argv[linker_arg + 1]; - linker_arg += 1; - - continue; - } else if (std::strcmp(argv[linker_arg], "-32k") == 0) { - kArch = CompilerKit::kPefArch32000; - - continue; - } else if (std::strcmp(argv[linker_arg], "-power64") == 0) { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } else if (std::strcmp(argv[linker_arg], "-riscv64") == 0) { - kArch = CompilerKit::kPefArchRISCV; - - continue; - } else if (std::strcmp(argv[linker_arg], "-arm64") == 0) { - kArch = CompilerKit::kPefArchARM64; - - continue; - } else if (std::strcmp(argv[linker_arg], "-verbose") == 0) { - kVerbose = true; - - continue; - } else if (std::strcmp(argv[linker_arg], "-dylib") == 0) { - if (kOutput.empty()) { - continue; - } - - if (kOutput.find(kPefExt) != CompilerKit::STLString::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } else if (std::strcmp(argv[linker_arg], "-output") == 0) { - if ((linker_arg + 1) > argc) continue; - - kOutput = argv[linker_arg + 1]; - ++linker_arg; - - continue; - } else { - if (argv[linker_arg][0] == '-') { - kConsoleOut << "unknown flag: " << argv[linker_arg] << "\n"; - return EXIT_FAILURE; - } - - kObjectList.emplace_back(argv[linker_arg]); - - continue; - } - } - - if (kOutput.empty()) { - kConsoleOut << "no output filename set." << std::endl; - return NECTI_EXEC_ERROR; - } else if (kObjectList.empty()) { - kConsoleOut << "no input files." << std::endl; - return NECTI_EXEC_ERROR; - } else { - namespace FS = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) { - if (!FS::exists(obj)) { - // if filesystem doesn't find file - // -> throw error. - kConsoleOut << "no such file: " << obj << std::endl; - return NECTI_EXEC_ERROR; - } - } - } - - // PEF expects a valid target architecture when outputing a binary. - if (kArch == CompilerKit::kPefArchInvalid) { - kConsoleOut << "no target architecture set, can't continue." << std::endl; - return NECTI_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = is_executable ? CompilerKit::kPefKindExec : CompilerKit::kPefKindDylib; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Amlal El Mahrouss Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - pef_container.Checksum = 0UL; - - std::ofstream output_fc(kOutput, std::ofstream::binary); - - if (output_fc.bad()) { - if (kVerbose) { - kConsoleOut << "error: " << strerror(errno) << "\n"; - } - - return NECTI_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector<CompilerKit::PEFCommandHeader> command_headers; - CompilerKit::Utils::AEReadableProtocol reader_protocol{}; - - for (const auto& objectFile : kObjectList) { - if (!std::filesystem::exists(objectFile)) continue; - - CompilerKit::AEHeader hdr{}; - - reader_protocol.file_pointer_ = std::ifstream(objectFile, std::ifstream::binary); - reader_protocol.file_pointer_ >> hdr; - - if (hdr.fMagic[0] == kAEMag0 && hdr.fMagic[1] == kAEMag1 && - hdr.fSize == sizeof(CompilerKit::AEHeader)) { - if (hdr.fArch != kArch) { - if (kVerbose) kConsoleOut << "is this a FAT binary? : "; - - if (!kFatBinaryEnable) { - if (kVerbose) kConsoleOut << "not a FAT binary.\n"; - - kConsoleOut << "object " << objectFile - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - return NECTI_FAT_ERROR; - } else { - if (kVerbose) { - kConsoleOut << "Architecture matches what we expect.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= hdr.fArch; - std::size_t cnt = hdr.fCount; - - if (kVerbose) kConsoleOut << "header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - Char* raw_ae_records = new Char[cnt * sizeof(CompilerKit::AERecordHeader)]; - - if (!raw_ae_records) { - if (kVerbose) kConsoleOut << "allocation failed for records of count: " << cnt << "\n"; - } - - std::memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto* ae_records = reader_protocol.Read(raw_ae_records, cnt); - - size_t org = kLinkerDefaultOrigin; - - for (size_t ae_record_index = 0; ae_record_index < cnt; ++ae_record_index) { - CompilerKit::PEFCommandHeader command_header{0}; - std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; - - std::memcpy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); - - CompilerKit::STLString cmd_hdr_name(command_header.Name); - - // check this header if it's any valid. - if (cmd_hdr_name.find(kPefCode64) == CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefData64) == CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefZero64) == CompilerKit::STLString::npos) { - if (cmd_hdr_name.find(kLinkerStart) == CompilerKit::STLString::npos && - *command_header.Name == 0) { - if (cmd_hdr_name.find(kLdDefineSymbol) != CompilerKit::STLString::npos) { - goto ld_mark_header; - } else { - continue; - } - } - } - - if (cmd_hdr_name.find(kLinkerStart) != CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefCode64) != CompilerKit::STLString::npos) { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offset_of_obj; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.VirtualSize = ae_records[ae_record_index].fSize; - command_header.Cpu = hdr.fArch; - command_header.VirtualAddress = org; - command_header.SubCpu = hdr.fSubArch; - command_header.OffsetSize = ae_records[ae_record_index].fSize; - - org += command_header.VirtualSize; - - if (kVerbose) { - kConsoleOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; - kConsoleOut << "Offset: " << command_header.Offset << "\n"; - } - - command_headers.emplace_back(command_header); - } - - delete[] raw_ae_records; - raw_ae_records = nullptr; - - std::vector<char> bytes; - bytes.resize(hdr.fCodeSize); - - reader_protocol.file_pointer_.seekg(std::streamsize(hdr.fStartCode)); - reader_protocol.file_pointer_.read(bytes.data(), std::streamsize(hdr.fCodeSize)); - - kObjectBytes.push_back({.mBlob = bytes, .mOffset = hdr.fStartCode}); - - // Blob was written, close fp. - - reader_protocol.file_pointer_.close(); - - continue; - } - - kConsoleOut << "not an object container: " << objectFile << std::endl; - - // don't continue, it is a fatal error. - return NECTI_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - output_fc << pef_container; - - if (kVerbose) { - kConsoleOut << "wrote container to: " << output_fc.tellp() << ".\n"; - } - - output_fc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector<CompilerKit::STLString> not_found; - std::vector<CompilerKit::STLString> symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - CompilerKit::STLString cmd_hdr_name; - - for (auto& command_hdr : command_headers) { - // check if this symbol needs to be resolved. - if (CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_hdr.Name).find(kLdDynamicSym) == - CompilerKit::STLString::npos) { - if (kVerbose) kConsoleOut << "Found undefined symbol: " << command_hdr.Name << "\n"; - - cmd_hdr_name = command_hdr.Name; - - if (auto it = std::find(not_found.begin(), not_found.end(), cmd_hdr_name); - it == not_found.end()) { - not_found.emplace_back(cmd_hdr_name); - } - } - - symbols.emplace_back(command_hdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < command_headers.size(); ++not_found_idx) { - if (const auto it = std::find(not_found.begin(), not_found.end(), - CompilerKit::STLString(command_headers[not_found_idx].Name)); - it != not_found.end()) { - CompilerKit::STLString symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == CompilerKit::STLString::npos) continue; - - // erase the lookup prefix. - symbol_imp.erase(0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != CompilerKit::STLString::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto& command_hdr : command_headers) { - if (CompilerKit::STLString(command_hdr.Name).find(symbol_imp) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) == - CompilerKit::STLString::npos) { - CompilerKit::STLString undefined_symbol = command_hdr.Name; - auto result_of_sym = undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) { - if (result_of_sym[i] != symbol_imp[i]) goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) kConsoleOut << "Found symbol: " << command_hdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) { - if (kVerbose) - kConsoleOut << "Undefined entrypoint: " << kLinkerStart - << ", you may have forget to link " - "against the C++ runtime library.\n"; - - kConsoleOut << "Undefined entrypoint " << kLinkerStart << " for executable: " << kOutput - << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader date_cmd_hdr{}; - - time_t timestamp = time(nullptr); - - CompilerKit::STLString timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size()); - - date_cmd_hdr.Flags = 0; - date_cmd_hdr.Kind = CompilerKit::kPefZero; - date_cmd_hdr.Offset = output_fc.tellp(); - date_cmd_hdr.VirtualSize = timeStampStr.size(); - - command_headers.push_back(date_cmd_hdr); - - CompilerKit::PEFCommandHeader abi_cmd_hdr{}; - - CompilerKit::STLString abi = kLinkerAbiContainer; - - switch (kArch) { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "_NEP"; - break; - } - default: { - abi += "_IDK"; - break; - } - } - - std::memcpy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); - - abi_cmd_hdr.VirtualSize = abi.size(); - abi_cmd_hdr.Offset = output_fc.tellp(); - abi_cmd_hdr.Flags = 0; - abi_cmd_hdr.Kind = CompilerKit::kPefLinkerID; - - command_headers.push_back(abi_cmd_hdr); - - CompilerKit::PEFCommandHeader stack_cmd_hdr{0}; - - stack_cmd_hdr.Cpu = kArch; - stack_cmd_hdr.Flags = 0; - stack_cmd_hdr.VirtualSize = sizeof(uintptr_t); - stack_cmd_hdr.Offset = 0; - - std::memcpy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); - - command_headers.push_back(stack_cmd_hdr); - - CompilerKit::PEFCommandHeader uuid_cmd_hdr{}; - - std::random_device rd; - - auto seedData = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - std::memcpy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - std::memcpy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); - - uuid_cmd_hdr.VirtualSize = strlen(uuid_cmd_hdr.Name); - uuid_cmd_hdr.Offset = output_fc.tellp(); - uuid_cmd_hdr.Flags = CompilerKit::kPefLinkerID; - uuid_cmd_hdr.Kind = CompilerKit::kPefZero; - - command_headers.push_back(uuid_cmd_hdr); - - // prepare a symbol vector. - std::vector<CompilerKit::STLString> undef_symbols; - std::vector<CompilerKit::STLString> dupl_symbols; - std::vector<CompilerKit::STLString> resolve_symbols; - - constexpr Int32 kPaddingOffset = 16; - - size_t previous_offset = - (command_headers.size() * sizeof(CompilerKit::PEFCommandHeader)) + kPaddingOffset; - - CompilerKit::PEFCommandHeader end_exec_hdr; - - end_exec_hdr.Offset = output_fc.tellp(); - end_exec_hdr.Flags = CompilerKit::kPefLinkerID; - end_exec_hdr.Kind = CompilerKit::kPefZero; - - std::memcpy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); - - end_exec_hdr.VirtualSize = strlen(end_exec_hdr.Name); - - command_headers.push_back(end_exec_hdr); - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; commandHeaderIndex < command_headers.size(); - ++commandHeaderIndex) { - if (CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDefineSymbol) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDynamicSym) == - CompilerKit::STLString::npos) { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - CompilerKit::STLString symbol_name = command_headers[commandHeaderIndex].Name; - - if (!symbol_name.empty()) { - undef_symbols.emplace_back(symbol_name); - } - - command_headers[commandHeaderIndex].Offset += previous_offset; - previous_offset += command_headers[commandHeaderIndex].VirtualSize; - - CompilerKit::STLString name = command_headers[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kLinkerStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kLinkerStart) != CompilerKit::STLString::npos && - name.find(kPefCode64) != CompilerKit::STLString::npos) { - pef_container.Start = command_headers[commandHeaderIndex].Offset; - auto tellCurPos = output_fc.tellp(); - - output_fc.seekp(0); - output_fc << pef_container; - - output_fc.seekp(tellCurPos); - } - - if (kVerbose) { - kConsoleOut << "Command name: " << name << "\n"; - kConsoleOut << "VirtualAddress of command content: " - << command_headers[commandHeaderIndex].Offset << "\n"; - } - - output_fc << command_headers[commandHeaderIndex]; - - for (size_t sub_command_header_index = 0UL; sub_command_header_index < command_headers.size(); - ++sub_command_header_index) { - if (sub_command_header_index == commandHeaderIndex) continue; - - if (CompilerKit::STLString(command_headers[sub_command_header_index].Name) - .find(kLdDefineSymbol) != CompilerKit::STLString::npos && - CompilerKit::STLString(command_headers[sub_command_header_index].Name) - .find(kLdDynamicSym) == CompilerKit::STLString::npos) { - if (kVerbose) { - kConsoleOut << "Ignoring :UndefinedSymbol: headers...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto& command_hdr = command_headers[sub_command_header_index]; - - if (command_hdr.Name == CompilerKit::STLString(command_headers[commandHeaderIndex].Name)) { - if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(), command_hdr.Name) == - dupl_symbols.cend()) { - dupl_symbols.emplace_back(command_hdr.Name); - } - - if (kVerbose) kConsoleOut << "Found duplicate symbols of: " << command_hdr.Name << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!dupl_symbols.empty()) { - for (auto& symbol : dupl_symbols) { - kConsoleOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; - } - - return NECTI_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto& struct_of_blob : kObjectBytes) { - output_fc.write(struct_of_blob.mBlob.data(), struct_of_blob.mBlob.size()); - } - - if (kVerbose) { - kConsoleOut << "Wrote contents of: " << kOutput << "\n"; - } - - // step 3: check if we have those symbols - - std::vector<CompilerKit::STLString> unreferenced_symbols; - - for (auto& command_hdr : command_headers) { - if (auto it = - std::find(not_found.begin(), not_found.end(), CompilerKit::STLString(command_hdr.Name)); - it != not_found.end()) { - unreferenced_symbols.emplace_back(command_hdr.Name); - } - } - - if (!unreferenced_symbols.empty()) { - for (auto& unreferenced_symbol : unreferenced_symbols) { - kConsoleOut << "Undefined symbol " << unreferenced_symbol << "\n"; - } - - return NECTI_EXEC_ERROR; - } - - if ((!kStartFound || kDuplicateSymbols) && - (std::filesystem::exists(kOutput) || !unreferenced_symbols.empty())) { - if (kVerbose) { - kConsoleOut << "File: " << kOutput << " is corrupt now...\n"; - } - - return NECTI_EXEC_ERROR; - } - - return NECTI_SUCCESS; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc deleted file mode 100644 index ed53782..0000000 --- a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc +++ /dev/null @@ -1,893 +0,0 @@ -/* - * ======================================================== - * - * C++ Preprocessor Driver - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/Frontend.h> -#include <algorithm> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <stdexcept> -#include <vector> - -#define kMacroPrefix '#' - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file CPlusPlusPreprocessor.cc -/// @brief Preprocessor. - -typedef Int32 (*bpp_parser_fn_t)(CompilerKit::STLString& line, std::ifstream& hdr_file, - std::ofstream& pp_out); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Preprocessor internal types. - -///////////////////////////////////////////////////////////////////////////////////////// - -namespace Detail { -enum { - kInvalid = 0, - kEqual = 100, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, - kCount = 6, -}; - -struct bpp_macro_condition final { - int32_t fType; - CompilerKit::STLString fTypeName; - - void Print() { - std::cout << "type: " << fType << "\n"; - std::cout << "type_name: " << fTypeName << "\n"; - } -}; - -struct bpp_macro final { - std::vector<CompilerKit::STLString> fArgs; - CompilerKit::STLString fName; - CompilerKit::STLString fValue; - - void Print() { - std::cout << "name: " << fName << "\n"; - std::cout << "value: " << fValue << "\n"; - - for (auto& arg : fArgs) { - std::cout << "arg: " << arg << "\n"; - } - } -}; -} // namespace Detail - -static std::vector<CompilerKit::STLString> kFiles; -static std::vector<Detail::bpp_macro> kMacros; -static std::vector<CompilerKit::STLString> kIncludes; - -static CompilerKit::STLString kWorkingDir = ""; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_if_condition -// @brief parse #if condition - -///////////////////////////////////////////////////////////////////////////////////////// - -int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, - bool& inactive_code, bool& defined, - CompilerKit::STLString& macro_str) { - if (cond.fType == Detail::kEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { - if (macro.fValue == "0") { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } else if (cond.fType == Detail::kNotEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != CompilerKit::STLString::npos) { - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - CompilerKit::STLString number; - - for (auto& macro_num : kMacros) { - if (substr_macro.find(macro_num.fName) != CompilerKit::STLString::npos) { - for (size_t i = 0; i < macro_num.fName.size(); ++i) { - if (isdigit(macro_num.fValue[i])) { - number += macro_num.fValue[i]; - } else { - number.clear(); - break; - } - } - - break; - } - } - - size_t y = 2; - - /* last try */ - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - size_t rhs = atol(macro.fValue.c_str()); - size_t lhs = atol(number.c_str()); - - if (lhs == 0) { - number.clear(); - ++y; - - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - lhs = atol(number.c_str()); - } - - if (cond.fType == Detail::kGreaterThan) { - if (lhs < rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kGreaterEqThan) { - if (lhs <= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kLesserEqThan) { - if (lhs >= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kLesserThan) { - if (lhs > rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief stores every included file here. - -///////////////////////////////////////////////////////////////////////////////////////// - -std::vector<CompilerKit::STLString> kAllIncludes; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_file -// @brief parse file to preprocess it. - -///////////////////////////////////////////////////////////////////////////////////////// - -void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) { - CompilerKit::STLString hdr_line; - CompilerKit::STLString line_after_include; - - bool inactive_code = false; - bool defined = false; - - try { - while (std::getline(hdr_file, hdr_line)) { - if (inactive_code) { - if (hdr_line.find("#endif") == CompilerKit::STLString::npos) { - continue; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("#endif") != CompilerKit::STLString::npos) { - inactive_code = false; - } - } - - if (hdr_line.find("*/") != CompilerKit::STLString::npos) { - hdr_line.erase(hdr_line.find("*/"), strlen("*/")); - } - - if (hdr_line.find("/*") != CompilerKit::STLString::npos) { - inactive_code = true; - - // get rid of comment. - hdr_line.erase(hdr_line.find("/*")); - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != CompilerKit::STLString::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = false; - - continue; - } - - continue; - } - - if (!defined && inactive_code) { - continue; - } - - if (defined && inactive_code) { - continue; - } - - for (auto macro : kMacros) { - if (CompilerKit::find_word(hdr_line, macro.fName)) { - if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != - CompilerKit::STLString::npos) { - if (!macro.fArgs.empty()) { - CompilerKit::STLString symbol_val = macro.fValue; - std::vector<CompilerKit::STLString> args; - - size_t x_arg_indx = 0; - - CompilerKit::STLString line_after_define = hdr_line; - CompilerKit::STLString str_arg; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ' ' || subc == '\t') continue; - - if (subc == ',' || subc == ')') { - if (str_arg.empty()) continue; - - args.push_back(str_arg); - - str_arg.clear(); - - continue; - } - - str_arg.push_back(subc); - } - } - - for (auto arg : macro.fArgs) { - if (symbol_val.find(macro.fArgs[x_arg_indx]) != CompilerKit::STLString::npos) { - symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), - macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); - ++x_arg_indx; - } else { - throw std::runtime_error("cppdrv: Internal error."); - } - } - - auto len = macro.fName.size(); - len += symbol_val.size(); - len += 2; // ( and ) - - hdr_line.erase(hdr_line.find(")"), 1); - - hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), - len, symbol_val); - } else { - auto value = macro.fValue; - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), value); - } - } - } - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("define ") != CompilerKit::STLString::npos) { - auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); - - CompilerKit::STLString macro_value; - CompilerKit::STLString macro_key; - - std::size_t pos = 0UL; - - std::vector<CompilerKit::STLString> args; - bool on_args = false; - - for (auto& ch : line_after_define) { - ++pos; - - if (ch == '(') { - on_args = true; - continue; - } - - if (ch == ')') { - on_args = false; - continue; - } - - if (ch == '\\') continue; - - if (on_args) continue; - - if (ch == ' ') { - for (size_t i = pos; i < line_after_define.size(); i++) { - macro_value += line_after_define[i]; - } - - break; - } - - macro_key += ch; - } - - CompilerKit::STLString str; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ',' || subc == ')') { - if (str.empty()) continue; - - args.push_back(str); - - str.clear(); - - continue; - } - - str.push_back(subc); - } - } - - Detail::bpp_macro macro; - - macro.fArgs = args; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.emplace_back(macro); - - continue; - } - - if (hdr_line[0] != kMacroPrefix) { - if (inactive_code) { - continue; - } - - pp_out << hdr_line << std::endl; - - continue; - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifndef") != CompilerKit::STLString::npos) { - auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_ifndef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = true; - inactive_code = false; - continue; - } - - if (macro == "1") { - defined = false; - inactive_code = true; - - continue; - } - - bool found = false; - - defined = true; - inactive_code = false; - - for (auto& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - found = true; - break; - } - } - - if (found) { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != CompilerKit::STLString::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = true; - - continue; - } else { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifdef") != CompilerKit::STLString::npos) { - auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_ifdef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - defined = false; - inactive_code = true; - - for (auto& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - defined = true; - inactive_code = false; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != CompilerKit::STLString::npos) { - inactive_code = true; - - std::vector<Detail::bpp_macro_condition> bpp_macro_condition_list = { - { - .fType = Detail::kEqual, - .fTypeName = "==", - }, - { - .fType = Detail::kNotEqual, - .fTypeName = "!=", - }, - { - .fType = Detail::kLesserThan, - .fTypeName = "<", - }, - { - .fType = Detail::kGreaterThan, - .fTypeName = ">", - }, - { - .fType = Detail::kLesserEqThan, - .fTypeName = "<=", - }, - { - .fType = Detail::kGreaterEqThan, - .fTypeName = ">=", - }, - }; - - int32_t good_to_go = 0; - - for (auto& macro_condition : bpp_macro_condition_list) { - if (hdr_line.find(macro_condition.fTypeName) != CompilerKit::STLString::npos) { - for (auto& found_macro : kMacros) { - if (hdr_line.find(found_macro.fName) != CompilerKit::STLString::npos) { - good_to_go = bpp_parse_if_condition(macro_condition, found_macro, inactive_code, - defined, hdr_line); - - break; - } - } - } - } - - if (good_to_go) continue; - - auto line_after_if = hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_if) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - // last try, is it defined to be one? - for (auto& macro_ref : kMacros) { - if (macro_ref.fName.find(macro) != CompilerKit::STLString::npos && - macro_ref.fValue == "1") { - inactive_code = false; - defined = true; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - CompilerKit::STLString message; - - for (auto& ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - std::cout << "warn: " << message << std::endl; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - CompilerKit::STLString message; - - for (auto& ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - throw std::runtime_error("error: " + message); - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("include ") != CompilerKit::STLString::npos) { - line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); - - if (it != kAllIncludes.cend()) { - continue; - } - - CompilerKit::STLString path; - - kAllIncludes.push_back(line_after_include); - - bool enable = false; - bool not_local = false; - - for (auto& ch : line_after_include) { - if (ch == ' ') continue; - - if (ch == '<') { - not_local = true; - enable = true; - - continue; - } - - if (ch == '\"') { - not_local = false; - enable = true; - continue; - } - - if (enable) { - path += ch; - } - } - - if (not_local) { - bool open = false; - - if (path.ends_with('>')) { - path.erase(path.find('>')); - } - - if (path.ends_with('"')) { - path.erase(path.find('"')); - } - - for (auto& include : kIncludes) { - CompilerKit::STLString header_path = include; - header_path.push_back('/'); - header_path += path; - - std::ifstream header(header_path); - - if (!header.is_open()) continue; - - open = true; - - bpp_parse_file(header, pp_out); - - break; - } - - if (!open) { - throw std::runtime_error("cppdrv: no such include file: " + path); - } - } else { - std::ifstream header(path); - - if (!header.is_open()) throw std::runtime_error("cppdrv: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } else { - std::cerr << ("cppdrv: unknown pre-processor directive, " + hdr_line) << "\n"; - continue; - } - } - } catch (std::out_of_range& oor) { - return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief main entrypoint of app. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(CPlusPlusPreprocessorMain) { - try { - bool skip = false; - bool double_skip = false; - - Detail::bpp_macro macro_1; - - macro_1.fName = "__true"; - macro_1.fValue = "1"; - - kMacros.push_back(macro_1); - - Detail::bpp_macro macro_unreachable; - - macro_unreachable.fName = "__unreachable"; - macro_unreachable.fValue = "__compilerkit_unreachable"; - - kMacros.push_back(macro_unreachable); - - Detail::bpp_macro macro_unused; - - macro_unreachable.fName = "__unused"; - macro_unreachable.fValue = "__compilerkit_unused"; - - kMacros.push_back(macro_unused); - - Detail::bpp_macro macro_0; - - macro_0.fName = "__false"; - macro_0.fValue = "0"; - - kMacros.push_back(macro_0); - - Detail::bpp_macro macro_zka; - - macro_zka.fName = "__NECTI__"; - macro_zka.fValue = "1"; - - kMacros.push_back(macro_zka); - - Detail::bpp_macro macro_cxx; - - macro_cxx.fName = "__cplusplus"; - macro_cxx.fValue = "202302L"; - - kMacros.push_back(macro_cxx); - - Detail::bpp_macro macro_size_t; - macro_size_t.fName = "__SIZE_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINT32_TYPE__"; - macro_size_t.fValue = "unsigned int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINTPTR_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (double_skip) { - ++index; - double_skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-cpp-ver") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-help") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - printf("%s\n", "-cpp-working-dir <path>: set directory to working path."); - printf("%s\n", "-cpp-include-dir <path>: add directory to include path."); - printf("%s\n", "-cpp-def <name> <value>: define a macro."); - printf("%s\n", "-cpp-ver: print the version."); - printf("%s\n", "-cpp-help: show help (this current command)."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-include-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - - skip = true; - - kIncludes.push_back(inc); - } - - if (strcmp(argv[index], "-cpp-working-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } - - if (strcmp(argv[index], "-cpp-def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) { - CompilerKit::STLString macro_key = argv[index + 1]; - - CompilerKit::STLString macro_value; - bool is_string = false; - - for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); ++argv_find_len) { - if (!isdigit(argv[index][argv_find_len])) { - is_string = true; - macro_value += "\""; - - break; - } - } - - macro_value += argv[index + 2]; - - if (is_string) macro_value += "\""; - - Detail::bpp_macro macro; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.push_back(macro); - - double_skip = true; - } - - continue; - } - - kFiles.emplace_back(argv[index]); - } - - if (kFiles.empty()) return NECTI_EXEC_ERROR; - - for (auto& file : kFiles) { - if (!std::filesystem::exists(file)) continue; - - std::ifstream file_descriptor(file); - std::ofstream file_descriptor_pp(file + ".pp"); - - bpp_parse_file(file_descriptor, file_descriptor_pp); - } - - return NECTI_SUCCESS; - } catch (const std::runtime_error& e) { - std::cout << e.what() << '\n'; - } - - return NECTI_EXEC_ERROR; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/StringKit.cc b/dev/CompilerKit/src/StringKit.cc deleted file mode 100644 index d612947..0000000 --- a/dev/CompilerKit/src/StringKit.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/** - * @file StringKit.cc - * @author Amlal (amlal@nekernel.org) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) Amlal El Mahrouss - * - */ - -#include <CompilerKit/StringKit.h> - -namespace CompilerKit { - -Char* BasicString::Data() { - return m_Data; -} - -const Char* BasicString::CData() const { - return m_Data; -} - -SizeType BasicString::Length() const { - return strlen(m_Data); -} - -bool BasicString::operator==(const BasicString& rhs) const { - const SizeType len = Length(); - if (rhs.Length() != len) return false; - return memcmp(m_Data, rhs.m_Data, len) == 0; -} - -bool BasicString::operator==(const Char* rhs) const { - const SizeType rhs_len = string_length(rhs); - const SizeType len = Length(); - if (rhs_len != len) return false; - return memcmp(m_Data, rhs, len) == 0; -} - -bool BasicString::operator!=(const BasicString& rhs) const { - return !(*this == rhs); -} - -bool BasicString::operator!=(const Char* rhs) const { - return !(*this == rhs); -} - -BasicString StringBuilder::Construct(const Char* data) { - if (!data || *data == 0) return BasicString(0); - - BasicString view(strlen(data)); - view += data; - - return view; -} - -BasicString StringBuilder::FromInt(const char* fmt, int i) { - if (!fmt) return BasicString(0); - - Char result[sizeof(int64_t)] = {0}; - if (!to_str(result, sizeof(int64_t), i)) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(result); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += result; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString StringBuilder::FromBool(const char* fmt, bool val) { - if (!fmt) return BasicString(0); - - const Char* boolean_expr = val ? "true" : "false"; - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(boolean_expr); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += boolean_expr; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -bool StringBuilder::Equals(const char* lhs, const char* rhs) { - const SizeType lhs_len = string_length(lhs); - const SizeType rhs_len = string_length(rhs); - - if (lhs_len != rhs_len) return false; - return memcmp(lhs, rhs, lhs_len) == 0; -} - -BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { - if (!fmt || !fmtRight) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType rhs_len = string_length(fmtRight); - - BasicString output(fmt_len + rhs_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += fmtRight; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString& BasicString::operator+=(const Char* rhs) { - const SizeType rhs_len = strlen(rhs); - if (this->m_Cur + rhs_len >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); - - this->m_Cur += rhs_len; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(const BasicString& rhs) { - if (this->m_Cur + rhs.m_Cur >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), rhs.m_Cur); - this->m_Cur += rhs.m_Cur; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(const Char ch) { - if (this->m_Cur + 1 >= this->m_Sz) { - throw std::runtime_error("out_of_bounds.."); - } - - this->m_Data[this->m_Cur++] = ch; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -} // namespace CompilerKit diff --git a/dev/CompilerKit/utils/AsmUtils.h b/dev/CompilerKit/utils/AsmUtils.h deleted file mode 100644 index 897fcbe..0000000 --- a/dev/CompilerKit/utils/AsmUtils.h +++ /dev/null @@ -1,92 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Compiler.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/utils/CompilerUtils.h> - -using namespace CompilerKit; - -/// @brief Get Number from lineBuffer. -/// @param lineBuffer the lineBuffer to fetch from. -/// @param numberKey where to seek that number. -/// @return -static NumberCast32 GetNumber32(STLString lineBuffer, STLString 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) { - Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) { - kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number:" + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); - 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/CompilerKit/utils/CompilerUtils.h b/dev/CompilerKit/utils/CompilerUtils.h deleted file mode 100644 index 1b086ee..0000000 --- a/dev/CompilerKit/utils/CompilerUtils.h +++ /dev/null @@ -1,116 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Compiler.h> -#include <CompilerKit/ErrorID.h> -#include <CompilerKit/Frontend.h> -#include <CompilerKit/Version.h> -#include <ThirdParty/Dialogs.h> -#include <iostream> - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" - -#define kZero128Section ".zero128" -#define kCode128Section ".code128" -#define kData128Section ".data128" - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kRed << "drv: " << kWhite) -#define kStdErr (std::cout << kYellow << "drv: " << kWhite) - -inline static UInt32 kErrorLimit = 10; -inline static UInt32 kAcceptableErrors = 0; -inline static bool kVerbose = false; -inline static bool kOutputAsBinary = false; - -namespace Detail { -/// @brief Linker specific blob metadata structure -struct DynamicLinkerBlob final { - std::vector<Char> mBlob{}; // PEF code/bss/data blob. - UIntPtr mOffset{0UL}; // the offset of the PEF container header... -}; - -inline void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(NECTI_EXEC_ERROR); - - ++kAcceptableErrors; -} - -inline void print_warning(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdOut << kYellow << reason << kBlank << std::endl; -} - -/// @internal -/// @brief Handler for SIGSEGV signal. -inline void drvi_crash_handler(std::int32_t id) { - CompilerKit::STLString verbose_header = "LIBCOMPILER CRASH REPORT - "; - verbose_header += kDistVersion; - verbose_header += " - "; - verbose_header += CompilerKit::current_date(); - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::cout << verbose_header << std::endl; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - kStdOut << "DATE: " << CompilerKit::current_date() << std::endl; - kStdOut << "VERSION: " << kDistVersion << std::endl; - kStdOut << "ERRNO: " << errno << std::endl; - kStdOut << "ERRNO(STRING): " << strerror(errno) << std::endl; - - switch (id) { - case SIGSEGV: { - kStdOut << "SIGNAL: Segmentation Fault." << kBlank << std::endl; - break; - } - case SIGABRT: { - kStdOut << "SIGNAL: Aborted." << kBlank << std::endl; - break; - } - } - - std::cout << kWhite; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::cout << verbose_header << std::endl; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::exit(NECTI_EXEC_ERROR); -} -} // namespace Detail diff --git a/dev/CompilerKit/utils/DylibHelpers.h b/dev/CompilerKit/utils/DylibHelpers.h deleted file mode 100644 index ab58fc7..0000000 --- a/dev/CompilerKit/utils/DylibHelpers.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include <CompilerKit/Defines.h> -#include <dlfcn.h> -#include <mutex> - -struct CompilerKitDylibTraits; - -typedef Int32 (*CompilerKitEntrypoint)(Int32 argc, Char const* argv[]); -typedef VoidPtr CompilerKitDylib; - -struct CompilerKitDylibTraits final { - CompilerKitDylib fDylib{nullptr}; - CompilerKitEntrypoint fEntrypoint{nullptr}; - std::mutex fMutex; - - CompilerKitDylibTraits& operator()(const Char* path, const Char* fEntrypoint) { - std::lock_guard<std::mutex> lock(this->fMutex); - - if (!path || !fEntrypoint) return *this; - - if (this->fDylib) { - dlclose(this->fDylib); - this->fDylib = nullptr; - } - - this->fDylib = dlopen(path, RTLD_LAZY); - - if (!this->fDylib) { - return *this; - } - - this->fEntrypoint = (CompilerKitEntrypoint) dlsym(this->fDylib, fEntrypoint); - - if (!this->fEntrypoint) { - dlclose(this->fDylib); - this->fDylib = nullptr; - - return *this; - } - - return *this; - } - - NECTI_COPY_DELETE(CompilerKitDylibTraits); - - CompilerKitDylibTraits() = default; - - ~CompilerKitDylibTraits() { - if (this->fDylib) { - dlclose(this->fDylib); - this->fDylib = nullptr; - } - - this->fEntrypoint = nullptr; - } -}; diff --git a/dev/DebuggerKit/CommonCLI.inl b/dev/DebuggerKit/CommonCLI.inl deleted file mode 100644 index e06a9b9..0000000 --- a/dev/DebuggerKit/CommonCLI.inl +++ /dev/null @@ -1,23 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -#define kStdOut (std::cout << kRed << "dbg: " << kWhite) - -static Bool kKeepRunning = false; - -#ifdef DK_NEKERNEL_DEBUGGER -static DebuggerKit::NeKernel::NeKernelContract kKernelDebugger; -#else -static DebuggerKit::POSIX::POSIXMachContract kUserDebugger; -#endif - -static DebuggerKit::ProcessID kPID = 0L; -static DebuggerKit::CAddress kActiveAddress = nullptr; -static CompilerKit::STLString kPath = ""; diff --git a/dev/DebuggerKit/DebuggerContract.h b/dev/DebuggerKit/DebuggerContract.h deleted file mode 100644 index 2114041..0000000 --- a/dev/DebuggerKit/DebuggerContract.h +++ /dev/null @@ -1,52 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <DebuggerKit/Platform.h> - -#define DK_DEBUGGER_CONTRACT : public ::DebuggerKit::DebuggerContract - -namespace DebuggerKit { -class DebuggerContract; - -/// =========================================================== /// -/// \brief Process ID -/// =========================================================== /// -typedef uint64_t ProcessID; - -/// =========================================================== /// -/// \brief Address type, a la BSD. -/// =========================================================== /// -typedef char* CAddress; - -/// =========================================================== /// -/// \brief Debugger contract class in C++, as per the design states. -/// \author Amlal El Mahrouss -/// =========================================================== /// -class DebuggerContract { - public: - explicit DebuggerContract() = default; - virtual ~DebuggerContract() = default; - - public: - DebuggerContract& operator=(const DebuggerContract&) = default; - DebuggerContract(const DebuggerContract&) = default; - - public: - virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept = 0; - virtual bool BreakAt(std::string symbol) noexcept = 0; - virtual bool Break() noexcept = 0; - virtual bool Continue() noexcept = 0; - virtual bool Detach() noexcept = 0; - - virtual std::unordered_map<uintptr_t, uintptr_t>& Get() { return m_breakpoints; } - - protected: - ProcessID m_pid{(ProcessID)~0}; - std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; -}; -} // namespace DebuggerKit diff --git a/dev/DebuggerKit/NeKernelContract.h b/dev/DebuggerKit/NeKernelContract.h deleted file mode 100644 index d048303..0000000 --- a/dev/DebuggerKit/NeKernelContract.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifndef DK_NEKERNEL_CONTRACT_H -#define DK_NEKERNEL_CONTRACT_H - -/// @brief NeKernel Debugging Protocol -/// @author Amlal El Mahrouss - -#ifdef DK_NEKERNEL_DEBUGGER - -#include <CompilerKit/Defines.h> -#include <DebuggerKit/DebuggerContract.h> - -namespace DebuggerKit::NeKernel { -class NeKernelContract; - -namespace Detail { - inline constexpr auto kDebugCmdLen = 256U; - inline constexpr auto kDebugPort = 51820; - inline constexpr auto kDebugMagic = "NE1.0.0;"; - inline constexpr uint16_t kDebugVersion = 0x0100; - inline constexpr auto kDebugDelim = ';'; - inline constexpr auto kDebugEnd = '\r'; - typedef int64_t dk_socket_type; -} // namespace Detail - -/// =========================================================== /// -/// \brief NeKernel Debugger Contract -/// \author Amlal El Mahrouss -/// =========================================================== /// -class NeKernelContract final DK_DEBUGGER_CONTRACT { - public: - NeKernelContract(); - virtual ~NeKernelContract() override; - - public: - NeKernelContract& operator=(const NeKernelContract&) = default; - NeKernelContract(const NeKernelContract&) = default; - - public: - bool Attach(CompilerKit::STLString path, CompilerKit::STLString arg_v, - ProcessID& pid) noexcept override; - bool BreakAt(CompilerKit::STLString symbol) noexcept override; - bool Break() noexcept override; - bool Continue() noexcept override; - bool Detach() noexcept override; - - private: - CompilerKit::STLString m_kernel_path{}; - Detail::dk_socket_type m_socket{0}; -}; -} // namespace DebuggerKit::NeKernel - -#endif // ifdef DK_NEKERNEL_DEBUGGER - -#endif // DK_NEKERNEL_CONTRACT_H diff --git a/dev/DebuggerKit/POSIXMachContract.h b/dev/DebuggerKit/POSIXMachContract.h deleted file mode 100644 index 5bd4ba8..0000000 --- a/dev/DebuggerKit/POSIXMachContract.h +++ /dev/null @@ -1,147 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#ifdef DK_MACH_DEBUGGER - -/// @file POSIXMachContract.h -/// @brief POSIX Mach debugger. - -#include <DebuggerKit/DebuggerContract.h> - -CK_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, - vm_offset_t data, mach_msg_type_number_t dataCnt); - -CK_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, - mach_vm_size_t size, boolean_t set_maximum, - vm_prot_t new_protection); - -#define PTRACE_ATTACH PT_ATTACHEXC -#define PTRACE_DETACH PT_DETACH -#define PTRACE_POKETEXT PT_WRITE_I -#define PTRACE_CONT PT_CONTINUE -#define PTRACE_PEEKTEXT PT_READ_I - -namespace DebuggerKit::POSIX { -/// =========================================================== /// -/// \brief POSIXMachContract engine class in C++ -/// \author Amlal El Mahrouss -/// =========================================================== /// -class POSIXMachContract final DK_DEBUGGER_CONTRACT { - public: - explicit POSIXMachContract() = default; - ~POSIXMachContract() override = default; - - public: - POSIXMachContract& operator=(const POSIXMachContract&) = default; - POSIXMachContract(const POSIXMachContract&) = default; - - public: - Bool Attach(CompilerKit::STLString path, CompilerKit::STLString argv, - ProcessID& pid) noexcept override { - pid = fork(); - - if (pid == 0) { - if (argv.empty()) { - ptrace(PT_TRACE_ME, 0, nullptr, 0); - kill(getpid(), SIGSTOP); - } - - std::vector<char*> argv_arr; - - argv_arr.push_back(const_cast<char*>(path.c_str())); - argv_arr.push_back(const_cast<char*>(argv.c_str())); - argv_arr.push_back(nullptr); - - execv(path.c_str(), argv_arr.data()); - - _exit(1); - } - - m_path = path; - m_pid = pid; - - pid = this->m_pid; - - return true; - } - - void SetPath(CompilerKit::STLString path) noexcept { - if (path.empty()) { - return; - } - - m_path = path; - } - - Bool BreakAt(CompilerKit::STLString symbol) noexcept override { - if (!m_path.empty() && std::filesystem::exists(m_path) && - std::filesystem::is_regular_file(m_path)) { - auto handle = dlopen(m_path.c_str(), RTLD_LAZY); - - if (handle == nullptr) { - return false; - } - - auto addr = dlsym(handle, symbol.c_str()); - - if (addr == nullptr) { - return false; - } - - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - - uint32_t brk_inst = 0xD43E0000; - - mach_vm_protect(task, (mach_vm_address_t) addr, sizeof(uint32_t), false, - VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); - - mach_vm_write(task, (mach_vm_address_t) addr, (vm_offset_t) &brk_inst, sizeof(addr)); - - return true; - } - - return false; - } - - Bool Break() noexcept override { - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - - kern_return_t ret = task_suspend(task); - - return ret == KERN_SUCCESS; - } - - Bool Continue() noexcept override { - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - - kern_return_t ret = task_resume(task); - - return ret == KERN_SUCCESS; - } - - Bool Detach() noexcept override { - this->Continue(); - - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); - - kern_return_t kr = mach_port_deallocate(mach_task_self(), task); - - return kr = KERN_SUCCESS; - } - - private: - ProcessID m_pid{0}; - CompilerKit::STLString m_path; -}; -} // namespace DebuggerKit::POSIX - -#endif diff --git a/dev/DebuggerKit/Platform.h b/dev/DebuggerKit/Platform.h deleted file mode 100644 index f878845..0000000 --- a/dev/DebuggerKit/Platform.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -/// =========================================================== /// -/// @author Amlal El Mahrouss -/// =========================================================== /// - -#include <CompilerKit/Defines.h> - -#include <arpa/inet.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/un.h> - -#include <sys/ptrace.h> -#include <sys/types.h> -#include <sys/user.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <filesystem> -#include <iostream> - -#include <dlfcn.h> -#include <mach-o/dyld.h> -#include <mach/mach.h> -#include <mach/mach_error.h> -#include <signal.h> - -#include <cstdint> -#include <string> -#include <unordered_map>
\ No newline at end of file diff --git a/dev/DebuggerKit/Version.h b/dev/DebuggerKit/Version.h deleted file mode 100644 index 8f3168a..0000000 --- a/dev/DebuggerKit/Version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#define kDistVersion "v0.0.7-debuggerkit" -#define kDistVersionBCD 0x0001 - -#define ToString(X) Stringify(X) -#define Stringify(X) #X - -#define kDistRelease ToString(kDistReleaseBranch) diff --git a/dev/DebuggerKit/dk-nekernel.json b/dev/DebuggerKit/dk-nekernel.json deleted file mode 100644 index 9c3d311..0000000 --- a/dev/DebuggerKit/dk-nekernel.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../DebuggerKit", - "../" - ], - "sources_path": ["src/*.cc"], - "output_name": "/usr/local/lib/libDebuggerKit.dylib", - "compiler_flags": ["-fPIC", "-shared"], - "cpp_macros": [ - "__NECTI__=202505", - "DK_USE_STRUCTS=1", - "DK_NEKERNEL_DEBUGGER", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} diff --git a/dev/DebuggerKit/dk-osx.json b/dev/DebuggerKit/dk-osx.json deleted file mode 100644 index c220756..0000000 --- a/dev/DebuggerKit/dk-osx.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../DebuggerKit", - "../" - ], - "sources_path": ["src/*.cc"], - "output_name": "/usr/local/lib/libDebuggerKit.dylib", - "compiler_flags": ["-fPIC", "-shared"], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "DEBUGGERKIT_POSIX", - "DK_MACH_DEBUGGER", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} diff --git a/dev/DebuggerKit/src/NeKernelContract.cc b/dev/DebuggerKit/src/NeKernelContract.cc deleted file mode 100644 index 38f327d..0000000 --- a/dev/DebuggerKit/src/NeKernelContract.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifdef DK_NEKERNEL_DEBUGGER - -/// @author Amlal El Mahrouss -/// @brief Kernel Debugger Protocol - -#include <CompilerKit/Defines.h> -#include <DebuggerKit/NeKernelContract.h> -#include <DebuggerKit/Platform.h> -#include <ThirdParty/Dialogs.h> - -using namespace DebuggerKit::NeKernel; -using namespace DebuggerKit::NeKernel::Detail; - -NeKernelContract::NeKernelContract() = default; - -NeKernelContract::~NeKernelContract() = default; - -Bool NeKernelContract::Attach(CompilerKit::STLString path, CompilerKit::STLString argv, - ProcessID& pid) noexcept { - if (path.empty() || argv.empty()) return NO; - - m_socket = ::socket(AF_INET, SOCK_STREAM, 0); - - if (m_socket == -1) return NO; - - struct sockaddr_in server_addr; - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(kDebugPort); - - if (::inet_pton(AF_INET, argv.c_str(), &server_addr.sin_addr) <= 0) return NO; - - auto ret = (::connect(m_socket, (struct sockaddr*) &server_addr, sizeof(server_addr)) == -1); - - if (ret) return NO; - - CompilerKit::STLString pkt = Detail::kDebugMagic; - pkt += ";\r"; - - ret = ::send(m_socket, pkt.data(), pkt.size(), 0) > 0; - return ret; -} - -Bool NeKernelContract::BreakAt(CompilerKit::STLString symbol) noexcept { - CompilerKit::STLString pkt = Detail::kDebugMagic; - pkt += ";SYM="; - pkt += symbol; - pkt += ";\r"; - - if (pkt.size() > kDebugCmdLen) return NO; - - auto ret = ::send(m_socket, pkt.data(), pkt.size(), 0) > 0; - return ret; -} - -Bool NeKernelContract::Break() noexcept { - CompilerKit::STLString pkt = Detail::kDebugMagic; - pkt += ";BRK=1;\r"; - - auto ret = ::send(m_socket, pkt.data(), pkt.size(), 0) > 0; - return ret; -} - -Bool NeKernelContract::Continue() noexcept { - CompilerKit::STLString pkt = Detail::kDebugMagic; - pkt += ";CONT=1;\r"; - - auto ret = ::send(m_socket, pkt.data(), pkt.size(), 0) > 0; - return ret; - return NO; -} - -Bool NeKernelContract::Detach() noexcept { - CompilerKit::STLString pkt = Detail::kDebugMagic; - pkt += ";DTCH=1;\r"; - - auto ret = ::send(m_socket, pkt.data(), pkt.size(), 0) > 0; - - if (ret) ::close(m_socket); - - return ret; -} - -#endif // DK_NEKERNEL_DEBUGGER diff --git a/dev/DebuggerKit/src/NeKernelContractCLI.cc b/dev/DebuggerKit/src/NeKernelContractCLI.cc deleted file mode 100644 index fc13a53..0000000 --- a/dev/DebuggerKit/src/NeKernelContractCLI.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifdef DK_NEKERNEL_DEBUGGER - -#include <CompilerKit/Defines.h> -#include <DebuggerKit/NeKernelContract.h> -#include <ThirdParty/Dialogs.h> -#include <string> - -#include <DebuggerKit/CommonCLI.inl> - -using namespace DebuggerKit::NeKernel; - -static void dbgi_ctrlc_handler(std::int32_t _) { - if (!kPID || kPath.empty()) { - return; - } - - kKernelDebugger.Break(); - - pfd::notify("Debugger Event", "Breakpoint hit!"); - - kKeepRunning = false; -} - -NECTI_MODULE(DebuggerNeKernel) { - pfd::notify("Debugger Event", - "NeCTI Debugger\n(C) 2025 Amlal El Mahrouss and NeKernel.org contributors, all " - "rights reserved."); - - if (argc >= 5 && std::string(argv[1]) == "-k" && argv[2] != nullptr && - std::string(argv[3]) == "-ip" && argv[4] != nullptr) { - kPath = argv[2]; - kPath += ":"; - kPath += argv[4]; - - kStdOut << "[+] KIP (Kernel:IP) set to: " << kPath << "\n"; - - CompilerKit::install_signal(SIGINT, dbgi_ctrlc_handler); - - kKernelDebugger.Attach(kPath, argv[4], kPID); - - while (YES) { - if (kKeepRunning) { - continue; - } - - std::string cmd; - if (!std::getline(std::cin, cmd)) break; - - if (cmd == "c" || cmd == "cont" || cmd == "continue") { - if (kKernelDebugger.Continue()) { - kKeepRunning = true; - - kStdOut << "[+] Continuing...\n"; - - pfd::notify("Debugger Event", "Continuing..."); - } - } - - if (cmd == "d" || cmd == "detach") kKernelDebugger.Detach(); - - if (cmd == "start") { - kStdOut << "[?] Enter a argument to use: "; - std::getline(std::cin, cmd); - - kKernelDebugger.Attach(kPath, cmd, kPID); - } - - if (cmd == "exit") { - if (kPID > 0) kKernelDebugger.Detach(); - - break; - } - - if (cmd == "break" || cmd == "b") { - kStdOut << "[?] Enter a symbol to break on: "; - - std::getline(std::cin, cmd); - - if (kKernelDebugger.BreakAt(cmd)) { - pfd::notify("Debugger Event", "Add BreakAt at: " + cmd); - } - } - } - - return EXIT_SUCCESS; - } - - kStdOut << "usage: " << argv[0] << " -k <kernel_path> -ip <ip4>\n"; - kStdOut << "example: " << argv[0] << " -k /path/to/ne_kernel -ip 127.0.0.1\n"; - - return EXIT_FAILURE; -} - -#endif // DK_NEKERNEL_DEBUGGER diff --git a/dev/DebuggerKit/src/POSIXMachContractCLI.cc b/dev/DebuggerKit/src/POSIXMachContractCLI.cc deleted file mode 100644 index 77fe844..0000000 --- a/dev/DebuggerKit/src/POSIXMachContractCLI.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifdef DK_MACH_DEBUGGER - -#include <CompilerKit/Defines.h> -#include <DebuggerKit/POSIXMachContract.h> -#include <ThirdParty/Dialogs.h> -#include <DebuggerKit/CommonCLI.inl> - -/// @internal -/// @brief Handles CTRL-C signal on debugger. -static void dbgi_ctrlc_handler(std::int32_t _) { - if (!kPID) { - return; - } - - kUserDebugger.Break(); - - pfd::notify("Debugger Event", "Breakpoint hit!"); - - kKeepRunning = false; -} - -NECTI_MODULE(DebuggerMachPOSIX) { - pfd::notify( - "Debugger Event", - "Userland Debugger\n(C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license."); - - if (argc >= 3 && std::string(argv[1]) == "-p" && argv[2] != nullptr) { - kPath = argv[2]; - kUserDebugger.SetPath(kPath); - - kStdOut << "[+] Image set to: " << kPath << "\n"; - } else { - kStdOut << "usage: " << argv[0] << " -p <path>\n"; - kStdOut << "example: " << argv[0] << " -p /path/to/program\n"; - - return EXIT_FAILURE; - } - - CompilerKit::install_signal(SIGINT, dbgi_ctrlc_handler); - - while (YES) { - if (kKeepRunning) { - continue; - } - - std::string cmd; - if (!std::getline(std::cin, cmd)) break; - - if (cmd == "c" || cmd == "cont" || cmd == "continue") { - if (kUserDebugger.Continue()) { - kKeepRunning = true; - - kStdOut << "[+] Continuing...\n"; - - pfd::notify("Debugger Event", "Continuing..."); - } - } - - if (cmd == "d" || cmd == "detach") kUserDebugger.Detach(); - - if (cmd == "start") { - kStdOut << "[?] Enter a argument to use: "; - std::getline(std::cin, cmd); - - kUserDebugger.Attach(kPath, cmd, kPID); - } - - if (cmd == "exit") { - if (kPID > 0) kUserDebugger.Detach(); - - break; - } - - if (cmd == "break" || cmd == "b") { - kStdOut << "[?] Enter a symbol to break on: "; - - std::getline(std::cin, cmd); - - if (kUserDebugger.BreakAt(cmd)) { - pfd::notify("Debugger Event", "Add BreakAt at: " + cmd); - } - } - } - - return EXIT_SUCCESS; -} - -#endif
\ No newline at end of file diff --git a/dev/LibC++/.gitignore b/dev/LibC++/.gitignore deleted file mode 100644 index 5fa1170..0000000 --- a/dev/LibC++/.gitignore +++ /dev/null @@ -1 +0,0 @@ -stdcxx/ diff --git a/dev/LibC++/__abi+unreachable.cc b/dev/LibC++/__abi+unreachable.cc deleted file mode 100644 index 1fc9830..0000000 --- a/dev/LibC++/__abi+unreachable.cc +++ /dev/null @@ -1,17 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#include <LibC++/__abi.h> -#include <LibC++/base_process.h> - -static const int32_t __unreachable_code = 34; - -extern "C" void __compilerkit_unreachable(void) { - std::base_process::signal(__unreachable_code); - - while (1) - ; -}
\ No newline at end of file diff --git a/dev/LibC++/__abi.h b/dev/LibC++/__abi.h deleted file mode 100644 index 70afae5..0000000 --- a/dev/LibC++/__abi.h +++ /dev/null @@ -1,15 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/defines.h> - -__init_decl() - -extern void __compilerkit_unreachable(void); - -__fini_decl()
\ No newline at end of file diff --git a/dev/LibC++/__power64.inc b/dev/LibC++/__power64.inc deleted file mode 100644 index c06863a..0000000 --- a/dev/LibC++/__power64.inc +++ /dev/null @@ -1,39 +0,0 @@ -# Path: LibC++/__power64.inc -# Language: CompilerKit POWER Assembly support for GNU. -# Build Date: 2024-6-4 - -#ifdef __NECTI__ - -#ifdef __ASSEMBLER__ - -#define lda li -#define sta stw -#define ldw li - -#define r0 0 -#define r1 1 -#define r2 2 -#define r3 3 -#define r4 4 -#define r5 5 -#define r6 6 -#define r7 7 -#define r8 8 -#define r9 9 -#define r10 10 -#define r11 11 -#define r12 12 -#define r13 13 -#define r14 14 -#define r15 15 -#define r16 16 -#define r17 17 -#define r18 18 -#define r19 19 -#define r20 20 - -#define nop mr 0, 0 - -#endif - -#endif diff --git a/dev/LibC++/base_alloc.h b/dev/LibC++/base_alloc.h deleted file mode 100644 index ea5b5b2..0000000 --- a/dev/LibC++/base_alloc.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/defines.h> - -namespace std::base_alloc { -/// @brief allocate a new class. -/// @tparam KindClass the class type to allocate. -template <typename KindClass, typename... Args> -inline KindClass* allocate(Args&&... args) { - return new KindClass(forward(args)...); -} - -/// @brief allocate a new class. -/// @note aborts on error. -/// @tparam KindClass the class type to allocate. -template <typename KindClass, typename... Args> -inline KindClass* allocate_nothrow(Args&&... args) noexcept { - return allocate(forward(args)...); -} - -/// @brief free a class. -/// @tparam KindClass the class type to allocate. -template <typename KindClass> -inline void release(KindClass ptr) { - if (!ptr) return; - - delete ptr; -} - -/// @brief destroy and free a class. -/// @note aborts on error. -/// @tparam KindClass the class type to allocate. -template <typename KindClass> -inline void release_nothrow(KindClass ptr) noexcept { - release(ptr); -} -} // namespace std::base_alloc diff --git a/dev/LibC++/base_exception.h b/dev/LibC++/base_exception.h deleted file mode 100644 index 8747688..0000000 --- a/dev/LibC++/base_exception.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/__abi.h> -#include <LibC++/base_process.h> -#include <LibC++/defines.h> -#include <iostream> - -/// @author Amlal El Mahrouss (amlal@nekernel.org) - -namespace std::base_exception::abi { -inline constexpr int __terminate_id = 33; - -/// @note This function is internal, don't call it. -extern void __unwind_object_list(); - -inline void __throw_general(const char* what) { - std::cout << "LibC++: Unwinding exception of kind: " << what << ", aborting here..." << std::endl; - __unwind_object_list(); - base_process::exit(__terminate_id); -} - -inline void __throw_domain_error(const char* what) { - __throw_general(what); - __builtin_unreachable(); // prevent from continuing. -} - -inline void __throw_bad_array_new_length(const char* what) { - __throw_general(what); - __builtin_unreachable(); // prevent from continuing. -} -} // namespace std::base_exception::abi diff --git a/dev/LibC++/base_math.h b/dev/LibC++/base_math.h deleted file mode 100644 index 60b260e..0000000 --- a/dev/LibC++/base_math.h +++ /dev/null @@ -1,88 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/defines.h> - -#ifndef NAN -#define NAN (__builtin_nanf("")) -#endif // !NAN - -/// @file Math.h -/// @brief Math functions. - -#ifdef __LIBCXX_USE_DOUBLE__ -typedef double real_type; -#else -typedef float real_type; -#endif - -namespace std::base_math { -inline constexpr static auto not_a_number = NAN; - -/// =========================================================== /// -/// @brief Power function, with Repeat argument. -/// =========================================================== /// -template <size_t Exponent> -inline real_type pow(real_type in) { - if (Exponent == 0) return 1; // Any number to the power of 0 is 1. - - if (Exponent == 1) return in; // Any number to the power of 1 is itself. - - size_t cnt = Exponent; - - real_type result = 1; - - for (auto i = 0; i < cnt; ++i) result *= in; - - return result; -} - -/// =========================================================== /// -/// @brief Square root function. -/// =========================================================== /// -inline real_type sqrt(real_type in) { - if (in == 0) return 0; - if (in == not_a_number) return not_a_number; - - auto constexpr const static Base = 2; - - auto x = in / Base; - - for (int i = 0; i < 10; ++i) { - x = (x + in / x) / Base; - } - - return x; -} - -/// =========================================================== /// -/// @brief Square of function, with Base template argument. -/// @param of Base argument to find the square of. -/// =========================================================== /// -template <size_t Base> -inline real_type surd(real_type in) { - if (in == 0) return 0; - if (in == 1) return 1; - - if (Base == 1) return in; - if (Base == 2) return sqrt(in); - - return not_a_number; -} - -/// =========================================================== /// -/// @brief Linear interpolation equation solver. -/// @param from where? -/// @param to to? -/// @param Updated diff value according to difference. -/// =========================================================== /// -inline real_type lerp(real_type to, real_type from, real_type stat) { - real_type diff = (to - from); - return from + (diff * stat); -} -} // namespace std::base_math diff --git a/dev/LibC++/base_process.h b/dev/LibC++/base_process.h deleted file mode 100644 index f9b0596..0000000 --- a/dev/LibC++/base_process.h +++ /dev/null @@ -1,45 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/defines.h> - -__init_decl() - -/// @brief CRT exit, with exit code (!!! exits all threads. !!!) -/// @param code the exit code. -/// @return the return > 0 for non successful. -extern int exit_(int code); - -/// @brief CRT signal handler. -/// @param code the signal code. -extern void signal_(int code); - -extern void (*__atexit_cdecl_ptr)(void); -extern void (**__atexit_lst_ptr)(void); -extern size_t __atexit_lst_cnt; - -__fini_decl() - -/// @brief Standard C++ namespace -namespace std::base_process { -inline int signal(int code) { - signal_(code); - return -1; -} - -inline int32_t exit(const int32_t& code) { - for (auto idx = 0UL; idx < __atexit_lst_cnt; ++idx) { - __atexit_lst_ptr[idx](); - } - - if (__atexit_cdecl_ptr) __atexit_cdecl_ptr(); - - exit_(code); - return -1; -} -} // namespace std::base_process diff --git a/dev/LibC++/defines.h b/dev/LibC++/defines.h deleted file mode 100644 index b8ef10c..0000000 --- a/dev/LibC++/defines.h +++ /dev/null @@ -1,76 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifndef __NECTI_DEFINES_H__ -#define __NECTI_DEFINES_H__ - -#define __ATTRIBUTE(X) __attribute__((X)) - -typedef __SIZE_TYPE__ size_t; -typedef __INT64_TYPE__ ssize_t; -typedef __INT32_TYPE__ int32_t; - -typedef void* ptr_type; -typedef __SIZE_TYPE__ size_type; - -typedef __INT64_TYPE__ ptrdiff_t; -typedef size_t uintptr_t; -typedef void* voidptr_t; -typedef void* any_t; -typedef char* caddr_t; - -#ifndef NULL -#define NULL ((voidptr_t) 0) -#endif // !null - -#define __alloca(sz) __ck_alloca(sz) - -#define __deref(ptr) (*(ptr)) - -#ifdef __cplusplus -#define __init_decl() extern "C" { -#define __fini_decl() \ - } \ - ; -#else -#define __init_decl() -#define __fini_decl() -#endif - -#if __has_builtin(__builtin_alloca) -#define alloca(sz) __builtin_alloca(sz) -#ifdef __alloca -#undef __alloca -#endif -#define __alloca alloca -#else -#warning !! alloca not detected !! -#endif - -typedef long long off_t; -typedef unsigned long long uoff_t; - -typedef union float_cast { - struct { - unsigned int mantissa : 23; - unsigned int exponent : 8; - unsigned int sign : 1; - }; - - float f; -} __ATTRIBUTE(packed) float_cast_t; - -typedef union double_cast { - struct { - unsigned long long int mantissa : 52; - unsigned int exponent : 11; - unsigned int sign : 1; - }; - - double f; -} __ATTRIBUTE(packed) double_cast_t; - -#endif /* __NECTI_DEFINES_H__ */ diff --git a/dev/LibC++/filesystem.h b/dev/LibC++/filesystem.h deleted file mode 100644 index 807ab0d..0000000 --- a/dev/LibC++/filesystem.h +++ /dev/null @@ -1,21 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifndef __NECTI_FS_H__ -#define __NECTI_FS_H__ - -#include <LibC++/defines.h> - -/// @brief Filesystem module for LibC++ - -namespace std { -class path; -class filesystem_error; -class directory_entry; -class directory_iterator; -} // namespace std - -#endif // __NECTI_FS_H__
\ No newline at end of file diff --git a/dev/LibC++/make_hdrs.sh b/dev/LibC++/make_hdrs.sh deleted file mode 100755 index 5e8907e..0000000 --- a/dev/LibC++/make_hdrs.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh - -outputDir=libCxx/ - -mkdir -p $outputDir - -for f in *.h; do - -#This line splits the file name on the delimiter "." -baseName=`echo $f | cut -d "." -f 1` -cp $f $outputDir$baseName - -done diff --git a/dev/LibC++/new.cc b/dev/LibC++/new.cc deleted file mode 100644 index 85ae82e..0000000 --- a/dev/LibC++/new.cc +++ /dev/null @@ -1,7 +0,0 @@ -/* ======================================== - - Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. - -======================================== */ - -#include <LibC++/new.h> diff --git a/dev/LibC++/new.h b/dev/LibC++/new.h deleted file mode 100644 index 37e2a26..0000000 --- a/dev/LibC++/new.h +++ /dev/null @@ -1,44 +0,0 @@ -/* ======================================== - - Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. - -======================================== */ - -#pragma once - -#include <LibC++/defines.h> - -namespace std { -struct placement_new; - -/// ========================================================= -/// @brief Disambugate non-throwing allocation functions. -/// ========================================================= -struct nothrow_t { - explicit nothrow_t() = default; -}; - -/// ========================================================= -/// @brief Placement new metadata. -/// ========================================================= -struct placement_new final { - void* __base{}; - int32_t __align{}; - size_t __size{}; -}; - -using placement_new_t = placement_new; -} // namespace std - -void* operator new(size_t); -void* operator new[](size_t); - -void* operator new(size_t, const std::nothrow_t&) noexcept; -void* operator new(size_t, void*) noexcept; -void* operator new[](size_t, const std::nothrow_t&) noexcept; -void* operator new[](size_t, void*) noexcept; - -void operator delete(void*) noexcept; -void operator delete(void*, size_t) noexcept; - -void operator delete[](void*) noexcept; diff --git a/dev/LibC++/utility.h b/dev/LibC++/utility.h deleted file mode 100644 index 62096f5..0000000 --- a/dev/LibC++/utility.h +++ /dev/null @@ -1,30 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - -======================================== */ - -#ifndef LIBCXX_UTILITY_H -#define LIBCXX_UTILITY_H - -namespace std { -/// @brief Forward object. -/// @tparam Args the object type. -/// @param arg the object. -/// @return object's rvalue -template <typename Args> -inline auto forward(Args& arg) -> Args&& { - return static_cast<const Args&&>(arg); -} - -/// @brief Move object. -/// @tparam Args the object type. -/// @param arg the object. -/// @return object's rvalue -template <typename Args> -inline auto move(Args&& arg) -> Args&& { - return static_cast<Args&&>(arg); -} -} // namespace std - -#endif // LIBCXX_UTILITY_H diff --git a/dev/ThirdParty/Dialogs.h b/dev/ThirdParty/Dialogs.h deleted file mode 100644 index 7e0b5eb..0000000 --- a/dev/ThirdParty/Dialogs.h +++ /dev/null @@ -1,1739 +0,0 @@ -// -// Portable File Dialogs -// -// Copyright © 2018–2022 Sam Hocevar <sam@hocevar.net> -// -// This library is free software. It comes without any warranty, to -// the extent permitted by applicable law. You can redistribute it -// and/or modify it under the terms of the Do What the Fuck You Want -// to Public License, Version 2, as published by the WTFPL Task Force. -// See http://www.wtfpl.net/ for more details. -// - -#pragma once - -#if _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include <commdlg.h> -#include <shellapi.h> -#include <shlobj.h> -#include <shobjidl.h> // IFileDialog -#include <strsafe.h> -#include <userenv.h> // GetUserProfileDirectory() -#include <windows.h> -#include <future> // std::async - -#elif __EMSCRIPTEN__ -#include <emscripten.h> - -#else -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 2 // for popen() -#endif -#ifdef __APPLE__ -#ifndef _DARWIN_C_SOURCE -#define _DARWIN_C_SOURCE -#endif -#endif -#include <fcntl.h> // fcntl() -#include <pwd.h> // getpwnam() -#include <sys/stat.h> // stat() -#include <sys/wait.h> // waitpid() -#include <unistd.h> // read(), pipe(), dup2(), getuid() -#include <csignal> // ::kill, std::signal -#include <cstdio> // popen() -#include <cstdlib> // std::getenv() -#endif - -#include <chrono> // std::chrono -#include <iostream> // std::ostream -#include <map> // std::map -#include <memory> // std::shared_ptr -#include <regex> // std::regex -#include <set> // std::set -#include <string> // std::string -#include <thread> // std::mutex, std::this_thread - -// Versions of mingw64 g++ up to 9.3.0 do not have a complete IFileDialog -#ifndef PFD_HAS_IFILEDIALOG -#define PFD_HAS_IFILEDIALOG 1 -#if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION -#if __GXX_ABI_VERSION <= 1013 -#undef PFD_HAS_IFILEDIALOG -#define PFD_HAS_IFILEDIALOG 0 -#endif -#endif -#endif - -namespace pfd { - -enum class button { - cancel = -1, - ok, - yes, - no, - abort, - retry, - ignore, -}; - -enum class choice { - ok = 0, - ok_cancel, - yes_no, - yes_no_cancel, - retry_cancel, - abort_retry_ignore, -}; - -enum class icon { - info = 0, - warning, - error, - question, -}; - -// Additional option flags for various dialog constructors -enum class opt : uint8_t { - none = 0, - // For file open, allow multiselect. - multiselect = 0x1, - // For file save, force overwrite and disable the confirmation dialog. - force_overwrite = 0x2, - // For folder select, force path to be the provided argument instead - // of the last opened directory, which is the Microsoft-recommended, - // user-friendly behaviour. - force_path = 0x4, -}; - -inline opt operator|(opt a, opt b) { - return opt(uint8_t(a) | uint8_t(b)); -} -inline bool operator&(opt a, opt b) { - return bool(uint8_t(a) & uint8_t(b)); -} - -// The settings class, only exposing to the user a way to set verbose mode -// and to force a rescan of installed desktop helpers (zenity, kdialog…). -class settings { - public: - static bool available(); - - static void verbose(bool value); - static void rescan(); - - protected: - explicit settings(bool resync = false); - - bool check_program(std::string const& program); - - inline bool is_osascript() const; - inline bool is_zenity() const; - inline bool is_kdialog() const; - - enum class flag { - is_scanned = 0, - is_verbose, - - has_zenity, - has_matedialog, - has_qarma, - has_kdialog, - is_vista, - - max_flag, - }; - - // Static array of flags for internal state - bool const& flags(flag in_flag) const; - - // Non-const getter for the static array of flags - bool& flags(flag in_flag); -}; - -// Internal classes, not to be used by client applications -namespace internal { - - // Process wait timeout, in milliseconds - static int const default_wait_timeout = 20; - - class executor { - friend class dialog; - - public: - // High level function to get the result of a command - std::string result(int* exit_code = nullptr); - - // High level function to abort - bool kill(); - -#if _WIN32 - void start_func(std::function<std::string(int*)> const& fun); - static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam); -#elif __EMSCRIPTEN__ - void start(int exit_code); -#else - void start_process(std::vector<std::string> const& command); -#endif - - ~executor(); - - protected: - bool ready(int timeout = default_wait_timeout); - void stop(); - - private: - bool m_running = false; - std::string m_stdout; - int m_exit_code = -1; -#if _WIN32 - std::future<std::string> m_future; - std::set<HWND> m_windows; - std::condition_variable m_cond; - std::mutex m_mutex; - DWORD m_tid; -#elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something -#else - pid_t m_pid = 0; - int m_fd = -1; -#endif - }; - - class platform { - protected: -#if _WIN32 - // Helper class around LoadLibraryA() and GetProcAddress() with some safety - class dll { - public: - dll(std::string const& name); - ~dll(); - - template <typename T> - class proc { - public: - proc(dll const& lib, std::string const& sym) - : m_proc(reinterpret_cast<T*>((void*) ::GetProcAddress(lib.handle, sym.c_str()))) {} - - explicit operator bool() const { return m_proc != nullptr; } - operator T*() const { return m_proc; } - - private: - T* m_proc; - }; - - private: - HMODULE handle; - }; - - // Helper class around CoInitialize() and CoUnInitialize() - class ole32_dll : public dll { - public: - ole32_dll(); - ~ole32_dll(); - bool is_initialized(); - - private: - HRESULT m_state; - }; - - // Helper class around CreateActCtx() and ActivateActCtx() - class new_style_context { - public: - new_style_context(); - ~new_style_context(); - - private: - HANDLE create(); - ULONG_PTR m_cookie = 0; - }; -#endif - }; - - class dialog : protected settings, protected platform { - public: - bool ready(int timeout = default_wait_timeout) const; - bool kill() const; - - protected: - explicit dialog(); - - std::vector<std::string> desktop_helper() const; - static std::string buttons_to_name(choice _choice); - static std::string get_icon_name(icon _icon); - - std::string powershell_quote(std::string const& str) const; - std::string osascript_quote(std::string const& str) const; - std::string shell_quote(std::string const& str) const; - - // Keep handle to executing command - std::shared_ptr<executor> m_async; - }; - - class file_dialog : public dialog { - protected: - enum type { - open, - save, - folder, - }; - - file_dialog(type in_type, std::string const& title, std::string const& default_path = "", - std::vector<std::string> const& filters = {}, opt options = opt::none); - - protected: - std::string string_result(); - std::vector<std::string> vector_result(); - -#if _WIN32 - static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData); -#if PFD_HAS_IFILEDIALOG - std::string select_folder_vista(IFileDialog* ifd, bool force_path); -#endif - - std::wstring m_wtitle; - std::wstring m_wdefault_path; - - std::vector<std::string> m_vector_result; -#endif - }; - -} // namespace internal - -// -// The path class provides some platform-specific path constants -// - -class path : protected internal::platform { - public: - static std::string home(); - static std::string separator(); -}; - -// -// The notify widget -// - -class notify : public internal::dialog { - public: - notify(std::string const& title, std::string const& message, icon _icon = icon::info); -}; - -// -// The message widget -// - -class message : public internal::dialog { - public: - message(std::string const& title, std::string const& text, choice _choice = choice::ok_cancel, - icon _icon = icon::info); - - button result(); - - private: - // Some extra logic to map the exit code to button number - std::map<int, button> m_mappings; -}; - -// -// The open_file, save_file, and open_folder widgets -// - -class open_file : public internal::file_dialog { - public: - open_file(std::string const& title, std::string const& default_path = "", - std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); - -#if defined(__has_cpp_attribute) -#if __has_cpp_attribute(deprecated) - // Backwards compatibility - [[deprecated("Use pfd::opt::multiselect instead of allow_multiselect")]] -#endif -#endif - open_file(std::string const& title, std::string const& default_path, - std::vector<std::string> const& filters, bool allow_multiselect); - - std::vector<std::string> result(); -}; - -class save_file : public internal::file_dialog { - public: - save_file(std::string const& title, std::string const& default_path = "", - std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); - -#if defined(__has_cpp_attribute) -#if __has_cpp_attribute(deprecated) - // Backwards compatibility - [[deprecated("Use pfd::opt::force_overwrite instead of confirm_overwrite")]] -#endif -#endif - save_file(std::string const& title, std::string const& default_path, - std::vector<std::string> const& filters, bool confirm_overwrite); - - std::string result(); -}; - -class select_folder : public internal::file_dialog { - public: - select_folder(std::string const& title, std::string const& default_path = "", - opt options = opt::none); - - std::string result(); -}; - -// -// Below this are all the method implementations. You may choose to define the -// macro PFD_SKIP_IMPLEMENTATION everywhere before including this header except -// in one place. This may reduce compilation times. -// - -#if !defined PFD_SKIP_IMPLEMENTATION - -// internal free functions implementations - -namespace internal { - -#if _WIN32 - static inline std::wstring str2wstr(std::string const& str) { - int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0); - std::wstring ret(len, '\0'); - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPWSTR) ret.data(), - (int) ret.size()); - return ret; - } - - static inline std::string wstr2str(std::wstring const& str) { - int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0, nullptr, - nullptr); - std::string ret(len, '\0'); - WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPSTR) ret.data(), - (int) ret.size(), nullptr, nullptr); - return ret; - } - - static inline bool is_vista() { - OSVERSIONINFOEXW osvi; - memset(&osvi, 0, sizeof(osvi)); - DWORDLONG const mask = VerSetConditionMask( - VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), - VER_MINORVERSION, VER_GREATER_EQUAL), - VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - osvi.dwOSVersionInfoSize = sizeof(osvi); - osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); - osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); - osvi.wServicePackMajor = 0; - - return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, - mask) != FALSE; - } -#endif - - // This is necessary until C++20 which will have std::string::ends_with() etc. - - static inline bool ends_with(std::string const& str, std::string const& suffix) { - return suffix.size() <= str.size() && - str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; - } - - static inline bool starts_with(std::string const& str, std::string const& prefix) { - return prefix.size() <= str.size() && str.compare(0, prefix.size(), prefix) == 0; - } - - // This is necessary until C++17 which will have std::filesystem::is_directory - - static inline bool is_directory(std::string const& path) { -#if _WIN32 - auto attr = GetFileAttributesA(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); -#elif __EMSCRIPTEN__ - // TODO - return false; -#else - struct stat s; - return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); -#endif - } - - // This is necessary because getenv is not thread-safe - - static inline std::string getenv(std::string const& str) { -#if _MSC_VER - char* buf = nullptr; - size_t size = 0; - if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) { - std::string ret(buf); - free(buf); - return ret; - } - return ""; -#else - auto buf = std::getenv(str.c_str()); - return buf ? buf : ""; -#endif - } - -} // namespace internal - -// settings implementation - -inline settings::settings(bool resync) { - flags(flag::is_scanned) &= !resync; - - if (flags(flag::is_scanned)) return; - - auto pfd_verbose = internal::getenv("PFD_VERBOSE"); - auto match_no = std::regex("(|0|no|false)", std::regex_constants::icase); - if (!std::regex_match(pfd_verbose, match_no)) flags(flag::is_verbose) = true; - -#if _WIN32 - flags(flag::is_vista) = internal::is_vista(); -#elif !__APPLE__ - flags(flag::has_zenity) = check_program("zenity"); - flags(flag::has_matedialog) = check_program("matedialog"); - flags(flag::has_qarma) = check_program("qarma"); - flags(flag::has_kdialog) = check_program("kdialog"); - - // If multiple helpers are available, try to default to the best one - if (flags(flag::has_zenity) && flags(flag::has_kdialog)) { - auto desktop_name = internal::getenv("XDG_SESSION_DESKTOP"); - if (desktop_name == std::string("gnome")) - flags(flag::has_kdialog) = false; - else if (desktop_name == std::string("KDE")) - flags(flag::has_zenity) = false; - } -#endif - - flags(flag::is_scanned) = true; -} - -inline bool settings::available() { -#if _WIN32 - return true; -#elif __APPLE__ - return true; -#elif __EMSCRIPTEN__ - // FIXME: Return true after implementation is complete. - return false; -#else - settings tmp; - return tmp.flags(flag::has_zenity) || tmp.flags(flag::has_matedialog) || - tmp.flags(flag::has_qarma) || tmp.flags(flag::has_kdialog); -#endif -} - -inline void settings::verbose(bool value) { - settings().flags(flag::is_verbose) = value; -} - -inline void settings::rescan() { - settings(/* resync = */ true); -} - -// Check whether a program is present using “which”. -inline bool settings::check_program(std::string const& program) { -#if _WIN32 - (void) program; - return false; -#elif __EMSCRIPTEN__ - (void) program; - return false; -#else - int exit_code = -1; - internal::executor async; - async.start_process({"/bin/sh", "-c", "which " + program}); - async.result(&exit_code); - return exit_code == 0; -#endif -} - -inline bool settings::is_osascript() const { -#if __APPLE__ - return true; -#else - return false; -#endif -} - -inline bool settings::is_zenity() const { - return flags(flag::has_zenity) || flags(flag::has_matedialog) || flags(flag::has_qarma); -} - -inline bool settings::is_kdialog() const { - return flags(flag::has_kdialog); -} - -inline bool const& settings::flags(flag in_flag) const { - static bool flags[size_t(flag::max_flag)]; - return flags[size_t(in_flag)]; -} - -inline bool& settings::flags(flag in_flag) { - return const_cast<bool&>(static_cast<settings const*>(this)->flags(in_flag)); -} - -// path implementation -inline std::string path::home() { -#if _WIN32 - // First try the USERPROFILE environment variable - auto user_profile = internal::getenv("USERPROFILE"); - if (user_profile.size() > 0) return user_profile; - // Otherwise, try GetUserProfileDirectory() - HANDLE token = nullptr; - DWORD len = MAX_PATH; - char buf[MAX_PATH] = {'\0'}; - if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { - dll userenv("userenv.dll"); - dll::proc<BOOL WINAPI(HANDLE, LPSTR, LPDWORD)> get_user_profile_directory( - userenv, "GetUserProfileDirectoryA"); - get_user_profile_directory(token, buf, &len); - CloseHandle(token); - if (*buf) return buf; - } -#elif __EMSCRIPTEN__ - return "/"; -#else - // First try the HOME environment variable - auto home = internal::getenv("HOME"); - if (home.size() > 0) return home; - // Otherwise, try getpwuid_r() - size_t len = 4096; -#if defined(_SC_GETPW_R_SIZE_MAX) - auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX); - if (size_max != -1) len = size_t(size_max); -#endif - std::vector<char> buf(len); - struct passwd pwd, *result; - if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) return result->pw_dir; -#endif - return "/"; -} - -inline std::string path::separator() { -#if _WIN32 - return "\\"; -#else - return "/"; -#endif -} - -// executor implementation - -inline std::string internal::executor::result(int* exit_code /* = nullptr */) { - stop(); - if (exit_code) *exit_code = m_exit_code; - return m_stdout; -} - -inline bool internal::executor::kill() { -#if _WIN32 - if (m_future.valid()) { - // Close all windows that weren’t open when we started the future - auto previous_windows = m_windows; - EnumWindows(&enum_windows_callback, (LPARAM) this); - for (auto hwnd : m_windows) - if (previous_windows.find(hwnd) == previous_windows.end()) { - SendMessage(hwnd, WM_CLOSE, 0, 0); - // Also send IDNO in case of a Yes/No or Abort/Retry/Ignore messagebox - SendMessage(hwnd, WM_COMMAND, IDNO, 0); - } - } -#elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something - return false; // cannot kill -#else - ::kill(m_pid, SIGKILL); -#endif - stop(); - return true; -} - -#if _WIN32 -inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) { - auto that = (executor*) lParam; - - DWORD pid; - auto tid = GetWindowThreadProcessId(hwnd, &pid); - if (tid == that->m_tid) that->m_windows.insert(hwnd); - return TRUE; -} -#endif - -#if _WIN32 -inline void internal::executor::start_func(std::function<std::string(int*)> const& fun) { - stop(); - - auto trampoline = [fun, this]() { - // Save our thread id so that the caller can cancel us - m_tid = GetCurrentThreadId(); - EnumWindows(&enum_windows_callback, (LPARAM) this); - m_cond.notify_all(); - return fun(&m_exit_code); - }; - - std::unique_lock<std::mutex> lock(m_mutex); - m_future = std::async(std::launch::async, trampoline); - m_cond.wait(lock); - m_running = true; -} - -#elif __EMSCRIPTEN__ -inline void internal::executor::start(int exit_code) { - m_exit_code = exit_code; -} - -#else -inline void internal::executor::start_process(std::vector<std::string> const& command) { - stop(); - m_stdout.clear(); - m_exit_code = -1; - - int in[2], out[2]; - if (pipe(in) != 0 || pipe(out) != 0) return; - - m_pid = fork(); - if (m_pid < 0) return; - - close(in[m_pid ? 0 : 1]); - close(out[m_pid ? 1 : 0]); - - if (m_pid == 0) { - dup2(in[0], STDIN_FILENO); - dup2(out[1], STDOUT_FILENO); - - // Ignore stderr so that it doesn’t pollute the console (e.g. GTK+ errors from zenity) - int fd = open("/dev/null", O_WRONLY); - dup2(fd, STDERR_FILENO); - close(fd); - - std::vector<char*> args; - std::transform(command.cbegin(), command.cend(), std::back_inserter(args), - [](std::string const& s) { return const_cast<char*>(s.c_str()); }); - args.push_back(nullptr); // null-terminate argv[] - - execvp(args[0], args.data()); - exit(1); - } - - close(in[1]); - m_fd = out[0]; - auto flags = fcntl(m_fd, F_GETFL); - fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); - - m_running = true; -} -#endif - -inline internal::executor::~executor() { - stop(); -} - -inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) { - if (!m_running) return true; - -#if _WIN32 - if (m_future.valid()) { - auto status = m_future.wait_for(std::chrono::milliseconds(timeout)); - if (status != std::future_status::ready) { - // On Windows, we need to run the message pump. If the async - // thread uses a Windows API dialog, it may be attached to the - // main thread and waiting for messages that only we can dispatch. - MSG msg; - while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - return false; - } - - m_stdout = m_future.get(); - } -#elif __EMSCRIPTEN__ || __NX__ - // FIXME: do something - (void) timeout; -#else - char buf[BUFSIZ]; - ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore - if (received > 0) { - m_stdout += std::string(buf, received); - return false; - } - - // Reap child process if it is dead. It is possible that the system has already reaped it - // (this happens when the calling application handles or ignores SIG_CHLD) and results in - // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for - // a little while. - int status; - pid_t child = waitpid(m_pid, &status, WNOHANG); - if (child != m_pid && (child >= 0 || errno != ECHILD)) { - // FIXME: this happens almost always at first iteration - std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); - return false; - } - - close(m_fd); - m_exit_code = WEXITSTATUS(status); -#endif - - m_running = false; - return true; -} - -inline void internal::executor::stop() { - // Loop until the user closes the dialog - while (!ready()) - ; -} - -// dll implementation - -#if _WIN32 -inline internal::platform::dll::dll(std::string const& name) - : handle(::LoadLibraryA(name.c_str())) {} - -inline internal::platform::dll::~dll() { - if (handle) ::FreeLibrary(handle); -} -#endif // _WIN32 - -// ole32_dll implementation - -#if _WIN32 -inline internal::platform::ole32_dll::ole32_dll() : dll("ole32.dll") { - // Use COINIT_MULTITHREADED because COINIT_APARTMENTTHREADED causes crashes. - // See https://github.com/samhocevar/portable-file-dialogs/issues/51 - auto coinit = proc<HRESULT WINAPI(LPVOID, DWORD)>(*this, "CoInitializeEx"); - m_state = coinit(nullptr, COINIT_MULTITHREADED); -} - -inline internal::platform::ole32_dll::~ole32_dll() { - if (is_initialized()) proc<void WINAPI()>(*this, "CoUninitialize")(); -} - -inline bool internal::platform::ole32_dll::is_initialized() { - return m_state == S_OK || m_state == S_FALSE; -} -#endif - -// new_style_context implementation - -#if _WIN32 -inline internal::platform::new_style_context::new_style_context() { - // Only create one activation context for the whole app lifetime. - static HANDLE hctx = create(); - - if (hctx != INVALID_HANDLE_VALUE) ActivateActCtx(hctx, &m_cookie); -} - -inline internal::platform::new_style_context::~new_style_context() { - DeactivateActCtx(0, m_cookie); -} - -inline HANDLE internal::platform::new_style_context::create() { - // This “hack” seems to be necessary for this code to work on windows XP. - // Without it, dialogs do not show and close immediately. GetError() - // returns 0 so I don’t know what causes this. I was not able to reproduce - // this behavior on Windows 7 and 10 but just in case, let it be here for - // those versions too. - // This hack is not required if other dialogs are used (they load comdlg32 - // automatically), only if message boxes are used. - dll comdlg32("comdlg32.dll"); - - // Using approach as shown here: https://stackoverflow.com/a/10444161 - UINT len = ::GetSystemDirectoryA(nullptr, 0); - std::string sys_dir(len, '\0'); - ::GetSystemDirectoryA(&sys_dir[0], len); - - ACTCTXA act_ctx = { - // Do not set flag ACTCTX_FLAG_SET_PROCESS_DEFAULT, since it causes a - // crash with error “default context is already set”. - sizeof(act_ctx), - ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, - "shell32.dll", - 0, - 0, - sys_dir.c_str(), - (LPCSTR) 124, - nullptr, - 0, - }; - - return ::CreateActCtxA(&act_ctx); -} -#endif // _WIN32 - -// dialog implementation - -inline bool internal::dialog::ready(int timeout /* = default_wait_timeout */) const { - return m_async->ready(timeout); -} - -inline bool internal::dialog::kill() const { - return m_async->kill(); -} - -inline internal::dialog::dialog() : m_async(std::make_shared<executor>()) {} - -inline std::vector<std::string> internal::dialog::desktop_helper() const { -#if __APPLE__ - return {"osascript"}; -#else - return {flags(flag::has_zenity) ? "zenity" - : flags(flag::has_matedialog) ? "matedialog" - : flags(flag::has_qarma) ? "qarma" - : flags(flag::has_kdialog) ? "kdialog" - : "echo"}; -#endif -} - -inline std::string internal::dialog::buttons_to_name(choice _choice) { - switch (_choice) { - case choice::ok_cancel: - return "okcancel"; - case choice::yes_no: - return "yesno"; - case choice::yes_no_cancel: - return "yesnocancel"; - case choice::retry_cancel: - return "retrycancel"; - case choice::abort_retry_ignore: - return "abortretryignore"; - /* case choice::ok: */ default: - return "ok"; - } -} - -inline std::string internal::dialog::get_icon_name(icon _icon) { - switch (_icon) { - case icon::warning: - return "warning"; - case icon::error: - return "error"; - case icon::question: - return "question"; - // Zenity wants "information" but WinForms wants "info" - /* case icon::info: */ default: -#if _WIN32 - return "info"; -#else - return "information"; -#endif - } -} - -// This is only used for debugging purposes -inline std::ostream& operator<<(std::ostream& s, std::vector<std::string> const& v) { - int not_first = 0; - for (auto& e : v) s << (not_first++ ? " " : "") << e; - return s; -} - -// Properly quote a string for Powershell: replace ' or " with '' or "" -// FIXME: we should probably get rid of newlines! -// FIXME: the \" sequence seems unsafe, too! -// XXX: this is no longer used but I would like to keep it around just in case -inline std::string internal::dialog::powershell_quote(std::string const& str) const { - return "'" + std::regex_replace(str, std::regex("['\"]"), "$&$&") + "'"; -} - -// Properly quote a string for osascript: replace \ or " with \\ or \" -// XXX: this also used to replace ' with \' when popen was used, but it would be -// smarter to do shell_quote(osascript_quote(...)) if this is needed again. -inline std::string internal::dialog::osascript_quote(std::string const& str) const { - return "\"" + std::regex_replace(str, std::regex("[\\\\\"]"), "\\$&") + "\""; -} - -// Properly quote a string for the shell: just replace ' with '\'' -// XXX: this is no longer used but I would like to keep it around just in case -inline std::string internal::dialog::shell_quote(std::string const& str) const { - return "'" + std::regex_replace(str, std::regex("'"), "'\\''") + "'"; -} - -// file_dialog implementation - -inline internal::file_dialog::file_dialog(type in_type, std::string const& title, - std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = {} */, - opt options /* = opt::none */) { -#if _WIN32 - std::string filter_list; - std::regex whitespace(" *"); - for (size_t i = 0; i + 1 < filters.size(); i += 2) { - filter_list += filters[i] + '\0'; - filter_list += std::regex_replace(filters[i + 1], whitespace, ";") + '\0'; - } - filter_list += '\0'; - - m_async->start_func( - [this, in_type, title, default_path, filter_list, options](int* exit_code) -> std::string { - (void) exit_code; - m_wtitle = internal::str2wstr(title); - m_wdefault_path = internal::str2wstr(default_path); - auto wfilter_list = internal::str2wstr(filter_list); - - // Initialise COM. This is required for the new folder selection window, - // (see https://github.com/samhocevar/portable-file-dialogs/pull/21) - // and to avoid random crashes with GetOpenFileNameW() (see - // https://github.com/samhocevar/portable-file-dialogs/issues/51) - ole32_dll ole32; - - // Folder selection uses a different method - if (in_type == type::folder) { -#if PFD_HAS_IFILEDIALOG - if (flags(flag::is_vista)) { - // On Vista and higher we should be able to use IFileDialog for folder selection - IFileDialog* ifd; - HRESULT hr = dll::proc<HRESULT WINAPI(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>( - ole32, "CoCreateInstance")(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, - IID_PPV_ARGS(&ifd)); - - // In case CoCreateInstance fails (which it should not), try legacy approach - if (SUCCEEDED(hr)) return select_folder_vista(ifd, options & opt::force_path); - } -#endif - - BROWSEINFOW bi; - memset(&bi, 0, sizeof(bi)); - - bi.lpfn = &bffcallback; - bi.lParam = (LPARAM) this; - - if (flags(flag::is_vista)) { - if (ole32.is_initialized()) bi.ulFlags |= BIF_NEWDIALOGSTYLE; - bi.ulFlags |= BIF_EDITBOX; - bi.ulFlags |= BIF_STATUSTEXT; - } - - auto* list = SHBrowseForFolderW(&bi); - std::string ret; - if (list) { - auto buffer = new wchar_t[MAX_PATH]; - SHGetPathFromIDListW(list, buffer); - dll::proc<void WINAPI(LPVOID)>(ole32, "CoTaskMemFree")(list); - ret = internal::wstr2str(buffer); - delete[] buffer; - } - return ret; - } - - OPENFILENAMEW ofn; - memset(&ofn, 0, sizeof(ofn)); - ofn.lStructSize = sizeof(OPENFILENAMEW); - ofn.hwndOwner = GetActiveWindow(); - - ofn.lpstrFilter = wfilter_list.c_str(); - - auto woutput = std::wstring(MAX_PATH * 256, L'\0'); - ofn.lpstrFile = (LPWSTR) woutput.data(); - ofn.nMaxFile = (DWORD) woutput.size(); - if (!m_wdefault_path.empty()) { - // If a directory was provided, use it as the initial directory. If - // a valid path was provided, use it as the initial file. Otherwise, - // let the Windows API decide. - auto path_attr = GetFileAttributesW(m_wdefault_path.c_str()); - if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY)) - ofn.lpstrInitialDir = m_wdefault_path.c_str(); - else if (m_wdefault_path.size() <= woutput.size()) - // second argument is size of buffer, not length of string - StringCchCopyW(ofn.lpstrFile, MAX_PATH * 256 + 1, m_wdefault_path.c_str()); - else { - ofn.lpstrFileTitle = (LPWSTR) m_wdefault_path.data(); - ofn.nMaxFileTitle = (DWORD) m_wdefault_path.size(); - } - } - ofn.lpstrTitle = m_wtitle.c_str(); - ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; - - dll comdlg32("comdlg32.dll"); - - // Apply new visual style (required for windows XP) - new_style_context ctx; - - if (in_type == type::save) { - if (!(options & opt::force_overwrite)) ofn.Flags |= OFN_OVERWRITEPROMPT; - - dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_save_file_name(comdlg32, "GetSaveFileNameW"); - if (get_save_file_name(&ofn) == 0) return ""; - return internal::wstr2str(woutput.c_str()); - } else { - if (options & opt::multiselect) ofn.Flags |= OFN_ALLOWMULTISELECT; - ofn.Flags |= OFN_PATHMUSTEXIST; - - dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_open_file_name(comdlg32, "GetOpenFileNameW"); - if (get_open_file_name(&ofn) == 0) return ""; - } - - std::string prefix; - for (wchar_t const* p = woutput.c_str(); *p;) { - auto filename = internal::wstr2str(p); - p += wcslen(p); - // In multiselect mode, we advance p one wchar further and - // check for another filename. If there is one and the - // prefix is empty, it means we just read the prefix. - if ((options & opt::multiselect) && *++p && prefix.empty()) { - prefix = filename + "/"; - continue; - } - - m_vector_result.push_back(prefix + filename); - } - - return ""; - }); -#elif __EMSCRIPTEN__ - // FIXME: do something - (void) in_type; - (void) title; - (void) default_path; - (void) filters; - (void) options; -#else - auto command = desktop_helper(); - - if (is_osascript()) { - std::string script = "set ret to choose"; - switch (in_type) { - case type::save: - script += " file name"; - break; - case type::open: - default: - script += " file"; - if (options & opt::multiselect) script += " with multiple selections allowed"; - break; - case type::folder: - script += " folder"; - break; - } - - if (default_path.size()) { - if (in_type == type::folder || is_directory(default_path)) - script += " default location "; - else - script += " default name "; - script += osascript_quote(default_path); - } - - script += " with prompt " + osascript_quote(title); - - if (in_type == type::open) { - // Concatenate all user-provided filter patterns - std::string patterns; - for (size_t i = 0; i < filters.size() / 2; ++i) patterns += " " + filters[2 * i + 1]; - - // Split the pattern list to check whether "*" is in there; if it - // is, we have to disable filters because there is no mechanism in - // OS X for the user to override the filter. - std::regex sep("\\s+"); - std::string filter_list; - bool has_filter = true; - std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); - std::sregex_token_iterator end; - for (; iter != end; ++iter) { - auto pat = iter->str(); - if (pat == "*" || pat == "*.*") - has_filter = false; - else if (internal::starts_with(pat, "*.")) - filter_list += "," + osascript_quote(pat.substr(2, pat.size() - 2)); - } - - if (has_filter && filter_list.size() > 0) { - // There is a weird AppleScript bug where file extensions of length != 3 are - // ignored, e.g. type{"txt"} works, but type{"json"} does not. Fortunately if - // the whole list starts with a 3-character extension, everything works again. - // We use "///" for such an extension because we are sure it cannot appear in - // an actual filename. - script += " of type {\"///\"" + filter_list + "}"; - } - } - - if (in_type == type::open && (options & opt::multiselect)) { - script += "\nset s to \"\""; - script += "\nrepeat with i in ret"; - script += "\n set s to s & (POSIX path of i) & \"\\n\""; - script += "\nend repeat"; - script += "\ncopy s to stdout"; - } else { - script += "\nPOSIX path of ret"; - } - - command.push_back("-e"); - command.push_back(script); - } else if (is_zenity()) { - command.push_back("--file-selection"); - - // If the default path is a directory, make sure it ends with "/" otherwise zenity will - // open the file dialog in the parent directory. - auto filename_arg = "--filename=" + default_path; - if (in_type != type::folder && !ends_with(default_path, "/") && - internal::is_directory(default_path)) - filename_arg += "/"; - command.push_back(filename_arg); - - command.push_back("--title"); - command.push_back(title); - command.push_back("--separator=\n"); - - for (size_t i = 0; i < filters.size() / 2; ++i) { - command.push_back("--file-filter"); - command.push_back(filters[2 * i] + "|" + filters[2 * i + 1]); - } - - if (in_type == type::save) command.push_back("--save"); - if (in_type == type::folder) command.push_back("--directory"); - if (!(options & opt::force_overwrite)) command.push_back("--confirm-overwrite"); - if (options & opt::multiselect) command.push_back("--multiple"); - } else if (is_kdialog()) { - switch (in_type) { - case type::save: - command.push_back("--getsavefilename"); - break; - case type::open: - command.push_back("--getopenfilename"); - break; - case type::folder: - command.push_back("--getexistingdirectory"); - break; - } - if (options & opt::multiselect) { - command.push_back("--multiple"); - command.push_back("--separate-output"); - } - - command.push_back(default_path); - - std::string filter; - for (size_t i = 0; i < filters.size() / 2; ++i) - filter += (i == 0 ? "" : " | ") + filters[2 * i] + "(" + filters[2 * i + 1] + ")"; - command.push_back(filter); - - command.push_back("--title"); - command.push_back(title); - } - - if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); -#endif -} - -inline std::string internal::file_dialog::string_result() { -#if _WIN32 - return m_async->result(); -#else - auto ret = m_async->result(); - // Strip potential trailing newline (zenity). Also strip trailing slash - // added by osascript for consistency with other backends. - while (!ret.empty() && (ret.back() == '\n' || ret.back() == '/')) ret.pop_back(); - return ret; -#endif -} - -inline std::vector<std::string> internal::file_dialog::vector_result() { -#if _WIN32 - m_async->result(); - return m_vector_result; -#else - std::vector<std::string> ret; - auto result = m_async->result(); - for (;;) { - // Split result along newline characters - auto i = result.find('\n'); - if (i == 0 || i == std::string::npos) break; - ret.push_back(result.substr(0, i)); - result = result.substr(i + 1, result.size()); - } - return ret; -#endif -} - -#if _WIN32 -// Use a static function to pass as BFFCALLBACK for legacy folder select -inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) { - auto inst = (file_dialog*) pData; - switch (uMsg) { - case BFFM_INITIALIZED: - SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) inst->m_wdefault_path.c_str()); - break; - } - return 0; -} - -#if PFD_HAS_IFILEDIALOG -inline std::string internal::file_dialog::select_folder_vista(IFileDialog* ifd, bool force_path) { - std::string result; - - IShellItem* folder; - - // Load library at runtime so app doesn't link it at load time (which will fail on windows XP) - dll shell32("shell32.dll"); - dll::proc<HRESULT WINAPI(PCWSTR, IBindCtx*, REFIID, void**)> create_item( - shell32, "SHCreateItemFromParsingName"); - - if (!create_item) return ""; - - auto hr = create_item(m_wdefault_path.c_str(), nullptr, IID_PPV_ARGS(&folder)); - - // Set default folder if found. This only sets the default folder. If - // Windows has any info about the most recently selected folder, it - // will display it instead. Generally, calling SetFolder() to set the - // current directory “is not a good or expected user experience and - // should therefore be avoided”: - // https://docs.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfolder - if (SUCCEEDED(hr)) { - if (force_path) - ifd->SetFolder(folder); - else - ifd->SetDefaultFolder(folder); - folder->Release(); - } - - // Set the dialog title and option to select folders - ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM); - ifd->SetTitle(m_wtitle.c_str()); - - hr = ifd->Show(GetActiveWindow()); - if (SUCCEEDED(hr)) { - IShellItem* item; - hr = ifd->GetResult(&item); - if (SUCCEEDED(hr)) { - wchar_t* wname = nullptr; - // This is unlikely to fail because we use FOS_FORCEFILESYSTEM, but try - // to output a debug message just in case. - if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) { - result = internal::wstr2str(std::wstring(wname)); - dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); - } else { - if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) { - auto name = internal::wstr2str(std::wstring(wname)); - dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); - std::cerr << "pfd: failed to get path for " << name << std::endl; - } else - std::cerr << "pfd: item of unknown type selected" << std::endl; - } - - item->Release(); - } - } - - ifd->Release(); - - return result; -} -#endif -#endif - -// notify implementation - -inline notify::notify(std::string const& title, std::string const& message, - icon _icon /* = icon::info */) { - if (_icon == icon::question) // Not supported by notifications - _icon = icon::info; - -#if _WIN32 - // Use a static shared pointer for notify_icon so that we can delete - // it whenever we need to display a new one, and we can also wait - // until the program has finished running. - struct notify_icon_data : public NOTIFYICONDATAW { - ~notify_icon_data() { Shell_NotifyIconW(NIM_DELETE, this); } - }; - - static std::shared_ptr<notify_icon_data> nid; - - // Release the previous notification icon, if any, and allocate a new - // one. Note that std::make_shared() does value initialization, so there - // is no need to memset the structure. - nid = nullptr; - nid = std::make_shared<notify_icon_data>(); - - // For XP support - nid->cbSize = NOTIFYICONDATAW_V2_SIZE; - nid->hWnd = nullptr; - nid->uID = 0; - - // Flag Description: - // - NIF_ICON The hIcon member is valid. - // - NIF_MESSAGE The uCallbackMessage member is valid. - // - NIF_TIP The szTip member is valid. - // - NIF_STATE The dwState and dwStateMask members are valid. - // - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, - // szInfoTitle, and dwInfoFlags members are valid. - // - NIF_GUID Reserved. - nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO; - - // Flag Description - // - NIIF_ERROR An error icon. - // - NIIF_INFO An information icon. - // - NIIF_NONE No icon. - // - NIIF_WARNING A warning icon. - // - NIIF_ICON_MASK Version 6.0. Reserved. - // - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon - // ToolTips - switch (_icon) { - case icon::warning: - nid->dwInfoFlags = NIIF_WARNING; - break; - case icon::error: - nid->dwInfoFlags = NIIF_ERROR; - break; - /* case icon::info: */ default: - nid->dwInfoFlags = NIIF_INFO; - break; - } - - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, - LONG_PTR lParam) -> BOOL { - ((NOTIFYICONDATAW*) lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); - return false; - }; - - nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); - ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR) nid.get()); - - nid->uTimeout = 5000; - - StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str()); - StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(message).c_str()); - - // Display the new icon - Shell_NotifyIconW(NIM_ADD, nid.get()); -#elif __EMSCRIPTEN__ - // FIXME: do something - (void) title; - (void) message; -#else - auto command = desktop_helper(); - - if (is_osascript()) { - command.push_back("-e"); - command.push_back("display notification " + osascript_quote(message) + " with title " + - osascript_quote(title)); - } else if (is_zenity()) { - command.push_back("--notification"); - command.push_back("--window-icon"); - command.push_back(get_icon_name(_icon)); - command.push_back("--text"); - command.push_back(title + "\n" + message); - } else if (is_kdialog()) { - command.push_back("--icon"); - command.push_back(get_icon_name(_icon)); - command.push_back("--title"); - command.push_back(title); - command.push_back("--passivepopup"); - command.push_back(message); - command.push_back("5"); - } - - if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); -#endif -} - -// message implementation - -inline message::message(std::string const& title, std::string const& text, - choice _choice /* = choice::ok_cancel */, icon _icon /* = icon::info */) { -#if _WIN32 - // Use MB_SYSTEMMODAL rather than MB_TOPMOST to ensure the message window is brought - // to front. See https://github.com/samhocevar/portable-file-dialogs/issues/52 - UINT style = MB_SYSTEMMODAL; - switch (_icon) { - case icon::warning: - style |= MB_ICONWARNING; - break; - case icon::error: - style |= MB_ICONERROR; - break; - case icon::question: - style |= MB_ICONQUESTION; - break; - /* case icon::info: */ default: - style |= MB_ICONINFORMATION; - break; - } - - switch (_choice) { - case choice::ok_cancel: - style |= MB_OKCANCEL; - break; - case choice::yes_no: - style |= MB_YESNO; - break; - case choice::yes_no_cancel: - style |= MB_YESNOCANCEL; - break; - case choice::retry_cancel: - style |= MB_RETRYCANCEL; - break; - case choice::abort_retry_ignore: - style |= MB_ABORTRETRYIGNORE; - break; - /* case choice::ok: */ default: - style |= MB_OK; - break; - } - - m_mappings[IDCANCEL] = button::cancel; - m_mappings[IDOK] = button::ok; - m_mappings[IDYES] = button::yes; - m_mappings[IDNO] = button::no; - m_mappings[IDABORT] = button::abort; - m_mappings[IDRETRY] = button::retry; - m_mappings[IDIGNORE] = button::ignore; - - m_async->start_func([text, title, style](int* exit_code) -> std::string { - auto wtext = internal::str2wstr(text); - auto wtitle = internal::str2wstr(title); - // Apply new visual style (required for all Windows versions) - new_style_context ctx; - *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style); - return ""; - }); - -#elif __EMSCRIPTEN__ - std::string full_message; - switch (_icon) { - case icon::warning: - full_message = "⚠️"; - break; - case icon::error: - full_message = "⛔"; - break; - case icon::question: - full_message = "❓"; - break; - /* case icon::info: */ default: - full_message = "ℹ"; - break; - } - - full_message += ' ' + title + "\n\n" + text; - - // This does not really start an async task; it just passes the - // EM_ASM_INT return value to a fake start() function. - m_async->start(EM_ASM_INT( - { - if ($1) return window.confirm(UTF8ToString($0)) ? 0 : -1; - alert(UTF8ToString($0)); - return 0; - }, - full_message.c_str(), _choice == choice::ok_cancel)); -#else - auto command = desktop_helper(); - - if (is_osascript()) { - std::string script = - "display dialog " + osascript_quote(text) + " with title " + osascript_quote(title); - auto if_cancel = button::cancel; - switch (_choice) { - case choice::ok_cancel: - script += - "buttons {\"OK\", \"Cancel\"}" - " default button \"OK\"" - " cancel button \"Cancel\""; - break; - case choice::yes_no: - script += - "buttons {\"Yes\", \"No\"}" - " default button \"Yes\"" - " cancel button \"No\""; - if_cancel = button::no; - break; - case choice::yes_no_cancel: - script += - "buttons {\"Yes\", \"No\", \"Cancel\"}" - " default button \"Yes\"" - " cancel button \"Cancel\""; - break; - case choice::retry_cancel: - script += - "buttons {\"Retry\", \"Cancel\"}" - " default button \"Retry\"" - " cancel button \"Cancel\""; - break; - case choice::abort_retry_ignore: - script += - "buttons {\"Abort\", \"Retry\", \"Ignore\"}" - " default button \"Abort\"" - " cancel button \"Retry\""; - if_cancel = button::retry; - break; - case choice::ok: - default: - script += - "buttons {\"OK\"}" - " default button \"OK\"" - " cancel button \"OK\""; - if_cancel = button::ok; - break; - } - m_mappings[1] = if_cancel; - m_mappings[256] = if_cancel; // XXX: I think this was never correct - script += " with icon "; - switch (_icon) { -#define PFD_OSX_ICON(n) \ - "alias ((path to library folder from system domain) as text " \ - "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")" - case icon::info: - default: - script += PFD_OSX_ICON("ToolBarInfo"); - break; - case icon::warning: - script += "caution"; - break; - case icon::error: - script += "stop"; - break; - case icon::question: - script += PFD_OSX_ICON("GenericQuestionMarkIcon"); - break; -#undef PFD_OSX_ICON - } - - command.push_back("-e"); - command.push_back(script); - } else if (is_zenity()) { - switch (_choice) { - case choice::ok_cancel: - command.insert(command.end(), {"--question", "--cancel-label=Cancel", "--ok-label=OK"}); - break; - case choice::yes_no: - // Do not use standard --question because it causes “No” to return -1, - // which is inconsistent with the “Yes/No/Cancel” mode below. - command.insert(command.end(), - {"--question", "--switch", "--extra-button=No", "--extra-button=Yes"}); - break; - case choice::yes_no_cancel: - command.insert(command.end(), {"--question", "--switch", "--extra-button=Cancel", - "--extra-button=No", "--extra-button=Yes"}); - break; - case choice::retry_cancel: - command.insert(command.end(), - {"--question", "--switch", "--extra-button=Cancel", "--extra-button=Retry"}); - break; - case choice::abort_retry_ignore: - command.insert(command.end(), {"--question", "--switch", "--extra-button=Ignore", - "--extra-button=Abort", "--extra-button=Retry"}); - break; - case choice::ok: - default: - switch (_icon) { - case icon::error: - command.push_back("--error"); - break; - case icon::warning: - command.push_back("--warning"); - break; - default: - command.push_back("--info"); - break; - } - } - - command.insert(command.end(), - {"--title", title, "--width=300", "--height=0", // sensible defaults - "--no-markup", // do not interpret text as Pango markup - "--text", text, "--icon-name=dialog-" + get_icon_name(_icon)}); - } else if (is_kdialog()) { - if (_choice == choice::ok) { - switch (_icon) { - case icon::error: - command.push_back("--error"); - break; - case icon::warning: - command.push_back("--sorry"); - break; - default: - command.push_back("--msgbox"); - break; - } - } else { - std::string flag = "--"; - if (_icon == icon::warning || _icon == icon::error) flag += "warning"; - flag += "yesno"; - if (_choice == choice::yes_no_cancel) flag += "cancel"; - command.push_back(flag); - if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) { - m_mappings[0] = button::yes; - m_mappings[256] = button::no; - } - } - - command.push_back(text); - command.push_back("--title"); - command.push_back(title); - - // Must be after the above part - if (_choice == choice::ok_cancel) - command.insert(command.end(), {"--yes-label", "OK", "--no-label", "Cancel"}); - } - - if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; - - m_async->start_process(command); -#endif -} - -inline button message::result() { - int exit_code; - auto ret = m_async->result(&exit_code); - // osascript will say "button returned:Cancel\n" - // and others will just say "Cancel\n" - if (internal::ends_with(ret, "Cancel\n")) return button::cancel; - if (internal::ends_with(ret, "OK\n")) return button::ok; - if (internal::ends_with(ret, "Yes\n")) return button::yes; - if (internal::ends_with(ret, "No\n")) return button::no; - if (internal::ends_with(ret, "Abort\n")) return button::abort; - if (internal::ends_with(ret, "Retry\n")) return button::retry; - if (internal::ends_with(ret, "Ignore\n")) return button::ignore; - if (m_mappings.count(exit_code) != 0) return m_mappings[exit_code]; - return exit_code == 0 ? button::ok : button::cancel; -} - -// open_file implementation - -inline open_file::open_file(std::string const& title, std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = { "All Files", "*" } */, - opt options /* = opt::none */) - : file_dialog(type::open, title, default_path, filters, options) {} - -inline open_file::open_file(std::string const& title, std::string const& default_path, - std::vector<std::string> const& filters, bool allow_multiselect) - : open_file(title, default_path, filters, (allow_multiselect ? opt::multiselect : opt::none)) {} - -inline std::vector<std::string> open_file::result() { - return vector_result(); -} - -// save_file implementation - -inline save_file::save_file(std::string const& title, std::string const& default_path /* = "" */, - std::vector<std::string> const& filters /* = { "All Files", "*" } */, - opt options /* = opt::none */) - : file_dialog(type::save, title, default_path, filters, options) {} - -inline save_file::save_file(std::string const& title, std::string const& default_path, - std::vector<std::string> const& filters, bool confirm_overwrite) - : save_file(title, default_path, filters, - (confirm_overwrite ? opt::none : opt::force_overwrite)) {} - -inline std::string save_file::result() { - return string_result(); -} - -// select_folder implementation - -inline select_folder::select_folder(std::string const& title, - std::string const& default_path /* = "" */, - opt options /* = opt::none */) - : file_dialog(type::folder, title, default_path, {}, options) {} - -inline std::string select_folder::result() { - return string_result(); -} - -#endif // PFD_SKIP_IMPLEMENTATION - -} // namespace pfd |
