diff options
| author | Amlal <amlal@nekernel.org> | 2025-04-25 13:14:01 +0200 |
|---|---|---|
| committer | Amlal <amlal@nekernel.org> | 2025-04-25 13:14:01 +0200 |
| commit | 20042235d1f53ae428aa154e64afdbae5d8d91ad (patch) | |
| tree | 6ea42d1b30505a57301f8ff2916c78ce94ff6eaf | |
| parent | 0561a8d0a6ae7588309a6e3513bbfeeef5f0aa15 (diff) | |
meta: update .clang-format, format codebase.
Signed-off-by: Amlal <amlal@nekernel.org>
55 files changed, 14079 insertions, 17384 deletions
diff --git a/.clang-format b/.clang-format index fb3cacb..3943f55 100644 --- a/.clang-format +++ b/.clang-format @@ -1,16 +1,29 @@ ---- -BasedOnStyle: Microsoft -AccessModifierOffset: '-4' -AlignAfterOpenBracket: Align -AlignConsecutiveMacros: 'true' -AlignConsecutiveAssignments: 'true' -AlignConsecutiveDeclarations: 'true' -BinPackParameters: 'false' -ColumnLimit: '0' -Language: Cpp -NamespaceIndentation: All +BasedOnStyle: Google +IndentWidth: 2 +TabWidth: 2 +UseTab: Never +ColumnLimit: 100 +DerivePointerAlignment: false PointerAlignment: Left -ReflowComments: 'true' -SortIncludes: 'false' -UseTab: Always -... +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +SortIncludes: true +IncludeBlocks: Preserve +SpaceAfterCStyleCast: true +SpaceBeforeParens: ControlStatements +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false +BreakBeforeBraces: Attach +ConstructorInitializerAllOnOneLineOrOnePerLine: true +Cpp11BracedListStyle: true +NamespaceIndentation: Inner +ReflowComments: true +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignTrailingComments: true +FixNamespaceComments: true +IncludeIsMainRegex: '(Test)?$' +SortUsingDeclarations: true diff --git a/dev/LibC++/base_alloc.h b/dev/LibC++/base_alloc.h index b12fd0a..af5693b 100644 --- a/dev/LibC++/base_alloc.h +++ b/dev/LibC++/base_alloc.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -8,42 +8,36 @@ #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 +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 index 30ec466..314ac12 100644 --- a/dev/LibC++/base_exception.h +++ b/dev/LibC++/base_exception.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -9,22 +9,18 @@ #include <LibC++/defines.h> #include <LibC++/process_base.h> -namespace std::base_exception -{ - inline void __throw_general(void) - { - exit(33); - } +namespace std::base_exception { +inline void __throw_general(void) { + exit(33); +} - inline void __throw_domain_error(const char* error) - { - __throw_general(); - __builtin_unreachable(); // prevent from continuing. - } +inline void __throw_domain_error(const char* error) { + __throw_general(); + __builtin_unreachable(); // prevent from continuing. +} - inline void __throw_bad_array_new_length(void) - { - __throw_general(); - __builtin_unreachable(); // prevent from continuing. - } -} // namespace std::base_exception +inline void __throw_bad_array_new_length(void) { + __throw_general(); + __builtin_unreachable(); // prevent from continuing. +} +} // namespace std::base_exception diff --git a/dev/LibC++/base_math.h b/dev/LibC++/base_math.h index ed1728e..ca6aace 100644 --- a/dev/LibC++/base_math.h +++ b/dev/LibC++/base_math.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -17,46 +17,38 @@ typedef double real_type; typedef float real_type; #endif -namespace std::base_math -{ - /// @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 of function, with Base template argument. - /// @param of Base argument to find sqquare of - template <size_t Base> - inline real_type sqr(real_type in) - { - if (in == 0) - return 0; - - return pow<1 / Base>(in); - } - - /// @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 +namespace std::base_math { +/// @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 of function, with Base template argument. +/// @param of Base argument to find sqquare of +template <size_t Base> +inline real_type sqr(real_type in) { + if (in == 0) return 0; + + return pow<1 / Base>(in); +} + +/// @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 index 7008b86..757e592 100644 --- a/dev/LibC++/base_process.h +++ b/dev/LibC++/base_process.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ @@ -12,11 +12,9 @@ extern "C" int exit(int code); /// @brief Standard C++ namespace -namespace std::base_process -{ - inline int exit(int code) - { - exit(code); - return -1; - } -} // namespace std::base_process +namespace std::base_process { +inline int exit(int code) { + exit(code); + return -1; +} +} // namespace std::base_process diff --git a/dev/LibC++/defines.h b/dev/LibC++/defines.h index 43cefb9..c0459ac 100644 --- a/dev/LibC++/defines.h +++ b/dev/LibC++/defines.h @@ -1,16 +1,15 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ #ifndef __LIBCOMPILER_DEFINES_H__ #define __LIBCOMPILER_DEFINES_H__ -extern "C" -{ -#include <stdint.h> +extern "C" { #include <stddef.h> +#include <stdint.h> } #ifndef __GNUC__ @@ -21,9 +20,9 @@ typedef __SIZE_TYPE__ size_t; typedef long int ssize_t; #else typedef int ssize_t; -#endif // __LP64__ +#endif // __LP64__ -typedef void* ptr_type; +typedef void* ptr_type; typedef __SIZE_TYPE__ size_type; typedef size_t ptrdiff_t; @@ -33,8 +32,8 @@ typedef void* any_t; typedef char* caddr_t; #ifndef NULL -#define NULL ((voidptr_t)0) -#endif // !null +#define NULL ((voidptr_t) 0) +#endif // !null #ifdef __GNUC__ #include <LibC++/alloca.h> @@ -45,12 +44,10 @@ typedef char* caddr_t; #define __deref(ptr) (*(ptr)) #ifdef __cplusplus -#define __init_decl() \ - extern "C" \ - { +#define __init_decl() extern "C" { #define __fini_decl() \ - } \ - ; + } \ + ; #else #define __init_decl() #define __fini_decl() @@ -66,31 +63,29 @@ typedef char* caddr_t; #warning ! alloca not detected ! #endif -typedef long long off_t; +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; + 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; + struct { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; } __attribute__((packed)) double_cast_t; -#endif // ifndef __GNUC__ +#endif // ifndef __GNUC__ #endif /* __LIBCOMPILER_DEFINES_H__ */ diff --git a/dev/LibC++/filesystem.h b/dev/LibC++/filesystem.h index b97bb1f..254bfab 100644 --- a/dev/LibC++/filesystem.h +++ b/dev/LibC++/filesystem.h @@ -1,18 +1,17 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. ------------------------------------------- */ #ifndef __LIBCOMPILER_FS_H__ #define __LIBCOMPILER_FS_H__ -namespace std -{ - class path; - class filesystem_error; - class directory_entry; - class directory_iterator; -} // namespace std +namespace std { +class path; +class filesystem_error; +class directory_entry; +class directory_iterator; +} // namespace std -#endif // __LIBCOMPILER_FS_H__
\ No newline at end of file +#endif // __LIBCOMPILER_FS_H__
\ No newline at end of file diff --git a/dev/LibC++/lc_runtime+unreachable.cc b/dev/LibC++/lc_runtime+unreachable.cc index 125584e..2aaa3c1 100644 --- a/dev/LibC++/lc_runtime+unreachable.cc +++ b/dev/LibC++/lc_runtime+unreachable.cc @@ -1,13 +1,11 @@ /* ------------------------------------------- - \ + \ Copyright (C) 2025 Amlal El Mahrouss, all rights reserved. \ - \ + \ ------------------------------------------- */ #include <LibC++/lc_runtime.h> -extern "C" void __libcompiler_unreachable(void) -{ - while (true) - ; +extern "C" void __libcompiler_unreachable(void) { + while (true); }
\ No newline at end of file diff --git a/dev/LibC++/lc_runtime.h b/dev/LibC++/lc_runtime.h index 0b58a58..d3d331f 100644 --- a/dev/LibC++/lc_runtime.h +++ b/dev/LibC++/lc_runtime.h @@ -1,7 +1,7 @@ /* ------------------------------------------- - \ + \ Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. \ - \ + \ ------------------------------------------- */ #pragma once diff --git a/dev/LibC++/utility.h b/dev/LibC++/utility.h index 1b1b932..4f1d2d7 100644 --- a/dev/LibC++/utility.h +++ b/dev/LibC++/utility.h @@ -1,33 +1,30 @@ /* ------------------------------------------- - \ + \ Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved. \ - \ + \ ------------------------------------------- */ #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 Args&& forward(Args& arg) - { - return static_cast<Args&&>(arg); - } +namespace std { +/// @brief Forward object. +/// @tparam Args the object type. +/// @param arg the object. +/// @return object's rvalue +template <typename Args> +inline Args&& forward(Args& arg) { + return static_cast<Args&&>(arg); +} - /// @brief Move object. - /// @tparam Args the object type. - /// @param arg the object. - /// @return object's rvalue - template <typename Args> - inline Args&& move(Args&& arg) - { - return static_cast<Args&&>(arg); - } -} // namespace std +/// @brief Move object. +/// @tparam Args the object type. +/// @param arg the object. +/// @return object's rvalue +template <typename Args> +inline Args&& move(Args&& arg) { + return static_cast<Args&&>(arg); +} +} // namespace std -#endif // LIBCXX_UTILITY_H +#endif // LIBCXX_UTILITY_H diff --git a/dev/LibCompiler/AE.h b/dev/LibCompiler/AE.h index fdf42a5..6e5f97f 100644 --- a/dev/LibCompiler/AE.h +++ b/dev/LibCompiler/AE.h @@ -15,128 +15,113 @@ #define kAEMag1 'E' #define kAESymbolLen (255) -#define kAEPad (8) -#define kAEMagLen (2) -#define kAENullType (0x00) +#define kAEPad (8) +#define kAEMagLen (2) +#define kAENullType (0x00) // 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 LibCompiler -{ - // @brief Advanced Executable Header - // One thing to keep in mind. - // This object format, is reloctable. - typedef struct AEHeader final - { - CharType fMagic[kAEMagLen]; - CharType fArch; - CharType fSubArch; - SizeType fCount; - CharType fSize; - SizeType fStartCode; - SizeType fCodeSize; - CharType fPad[kAEPad]; - } PACKED AEHeader, *AEHeaderPtr; - - // @brief Advanced Executable Record. - // Could be data, code or bss. - // fKind must be filled with PEF fields. - - typedef struct AERecordHeader final - { - CharType fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - CharType fPad[kAEPad]; - } PACKED AERecordHeader, *AERecordHeaderPtr; - - enum - { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, - }; -} // namespace LibCompiler +namespace LibCompiler { +// @brief Advanced Executable Header +// One thing to keep in mind. +// This object format, is reloctable. +typedef struct AEHeader final { + CharType fMagic[kAEMagLen]; + CharType fArch; + CharType fSubArch; + SizeType fCount; + CharType fSize; + SizeType fStartCode; + SizeType fCodeSize; + CharType fPad[kAEPad]; +} PACKED AEHeader, *AEHeaderPtr; + +// @brief Advanced Executable Record. +// Could be data, code or bss. +// fKind must be filled with PEF fields. + +typedef struct AERecordHeader final { + CharType fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + CharType fPad[kAEPad]; +} PACKED AERecordHeader, *AERecordHeaderPtr; + +enum { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, +}; +} // namespace LibCompiler // provide operator<< for AE -inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::AEHeader& container) -{ - fp.write((char*)&container, sizeof(LibCompiler::AEHeader)); +inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::AEHeader& container) { + fp.write((char*) &container, sizeof(LibCompiler::AEHeader)); - return fp; + return fp; } -inline std::ofstream& operator<<(std::ofstream& fp, - LibCompiler::AERecordHeader& container) -{ - fp.write((char*)&container, sizeof(LibCompiler::AERecordHeader)); +inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::AERecordHeader& container) { + fp.write((char*) &container, sizeof(LibCompiler::AERecordHeader)); - return fp; + return fp; } -inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::AEHeader& container) -{ - fp.read((char*)&container, sizeof(LibCompiler::AEHeader)); - return fp; +inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::AEHeader& container) { + fp.read((char*) &container, sizeof(LibCompiler::AEHeader)); + return fp; } -inline std::ifstream& operator>>(std::ifstream& fp, - LibCompiler::AERecordHeader& container) -{ - fp.read((char*)&container, sizeof(LibCompiler::AERecordHeader)); - return fp; +inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::AERecordHeader& container) { + fp.read((char*) &container, sizeof(LibCompiler::AERecordHeader)); + return fp; } -namespace LibCompiler::Utils -{ - /** - * @brief AE Reader protocol - * - */ - class AEReadableProtocol final - { - public: - std::ifstream FP; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - LIBCOMPILER_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE Record headers. - * - * @param raw the containing buffer - * @param sz it's size (1 = one AERecordHeader, 2 two AERecordHeader(s)) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) - { - if (!raw) - return nullptr; - - return this->_Read<AERecordHeader>(raw, sz * sizeof(AERecordHeader)); - } - - private: - /** - * @brief Implementation of Read for raw classes. - * - * @tparam TypeClass The class to read. - * @param raw the buffer - * @param sz the size - * @return TypeClass* the returning class. - */ - template <typename TypeClass> - TypeClass* _Read(char* raw, std::size_t sz) - { - FP.read(raw, std::streamsize(sz)); - return reinterpret_cast<TypeClass*>(raw); - } - }; -} // namespace LibCompiler::Utils +namespace LibCompiler::Utils { +/** + * @brief AE Reader protocol + * + */ +class AEReadableProtocol final { + public: + std::ifstream FP; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + LIBCOMPILER_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE Record headers. + * + * @param raw the containing buffer + * @param sz it's size (1 = one AERecordHeader, 2 two AERecordHeader(s)) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) { + if (!raw) return nullptr; + + return this->_Read<AERecordHeader>(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template <typename TypeClass> + TypeClass* _Read(char* raw, std::size_t sz) { + FP.read(raw, std::streamsize(sz)); + return reinterpret_cast<TypeClass*>(raw); + } +}; +} // namespace LibCompiler::Utils diff --git a/dev/LibCompiler/AssemblyInterface.h b/dev/LibCompiler/AssemblyInterface.h index 622e2ff..aebd01f 100644 --- a/dev/LibCompiler/AssemblyInterface.h +++ b/dev/LibCompiler/AssemblyInterface.h @@ -1,242 +1,198 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ #pragma once -#include <LibCompiler/Macros.h> #include <LibCompiler/Defines.h> +#include <LibCompiler/Macros.h> #include <LibCompiler/StringView.h> #define ASSEMBLY_INTERFACE : public LibCompiler::AssemblyInterface -namespace LibCompiler -{ - /// @brief Assembly to binary generator class. - /// @note This interface creates according to the CPU target of the child class. - class AssemblyInterface - { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - LIBCOMPILER_COPY_DEFAULT(AssemblyInterface); - - /// @brief compile to object file. - /// @note Example C++ -> MASM -> AE object. - virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; - }; - - /// @brief Simple assembly factory - class AssemblyFactory final - { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - LIBCOMPILER_COPY_DEFAULT(AssemblyFactory); - - public: - enum - { - kArchAMD64, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchAARCH64, - kArchUnknown, - }; - - Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; - }; - - union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; - }; - - union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) - : raw(raw) - { - } - - ~NumberCast64() - { - raw = 0; - } - - CharType number[8]; - UInt64 raw; - }; - - union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) - : raw(raw) - { - } - - ~NumberCast32() - { - raw = 0; - } - - CharType number[4]; - UInt32 raw; - }; - - union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) - : raw(raw) - { - } - - ~NumberCast16() - { - raw = 0; - } - - CharType number[2]; - UInt16 raw; - }; - - union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) - : raw(raw) - { - } - - ~NumberCast8() - { - raw = 0; - } - - CharType number; - UInt8 raw; - }; - - class EncoderInterface - { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - LIBCOMPILER_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string& line, const std::string& file) = 0; - virtual bool WriteLine(std::string& line, const std::string& file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; - }; +namespace LibCompiler { +/// @brief Assembly to binary generator class. +/// @note This interface creates according to the CPU target of the child class. +class AssemblyInterface { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyInterface); + + /// @brief compile to object file. + /// @note Example C++ -> MASM -> AE object. + virtual Int32 CompileToFormat(std::string& src, Int32 arch) = 0; +}; + +/// @brief Simple assembly factory +class AssemblyFactory final { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyFactory); + + public: + enum { + kArchAMD64, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchAARCH64, + kArchUnknown, + }; + + Int32 Compile(std::string& sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; +}; + +union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; +}; + +union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) : raw(raw) {} + + ~NumberCast64() { raw = 0; } + + CharType number[8]; + UInt64 raw; +}; + +union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) : raw(raw) {} + + ~NumberCast32() { raw = 0; } + + CharType number[4]; + UInt32 raw; +}; + +union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) : raw(raw) {} + + ~NumberCast16() { raw = 0; } + + CharType number[2]; + UInt16 raw; +}; + +union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) : raw(raw) {} + + ~NumberCast8() { raw = 0; } + + CharType number; + UInt8 raw; +}; + +class EncoderInterface { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + LIBCOMPILER_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string& line, const std::string& file) = 0; + virtual bool WriteLine(std::string& line, const std::string& file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; +}; #ifdef __ASM_NEED_AMD64__ - class EncoderAMD64 final : public EncoderInterface - { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; +class EncoderAMD64 final : public EncoderInterface { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderAMD64); + LIBCOMPILER_COPY_DEFAULT(EncoderAMD64); - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; + virtual std::string CheckLine(std::string& line, const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); - }; + 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__ +#endif // __ASM_NEED_AMD64__ #ifdef __ASM_NEED_ARM64__ - class EncoderARM64 final : public EncoderInterface - { - public: - explicit EncoderARM64() = default; - ~EncoderARM64() override = default; +class EncoderARM64 final : public EncoderInterface { + public: + explicit EncoderARM64() = default; + ~EncoderARM64() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderARM64); + LIBCOMPILER_COPY_DEFAULT(EncoderARM64); - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; + virtual std::string CheckLine(std::string& line, const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; -#endif // __ASM_NEED_ARM64__ +#endif // __ASM_NEED_ARM64__ #ifdef __ASM_NEED_64x0__ - class Encoder64x0 final : public EncoderInterface - { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; +class Encoder64x0 final : public EncoderInterface { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; - LIBCOMPILER_COPY_DEFAULT(Encoder64x0); + LIBCOMPILER_COPY_DEFAULT(Encoder64x0); - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; + virtual std::string CheckLine(std::string& line, const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; -#endif // __ASM_NEED_64x0__ +#endif // __ASM_NEED_64x0__ #ifdef __ASM_NEED_32x0__ - class Encoder32x0 final : public EncoderInterface - { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; +class Encoder32x0 final : public EncoderInterface { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; - LIBCOMPILER_COPY_DEFAULT(Encoder32x0); + LIBCOMPILER_COPY_DEFAULT(Encoder32x0); - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; + virtual std::string CheckLine(std::string& line, const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; -#endif // __ASM_NEED_32x0__ +#endif // __ASM_NEED_32x0__ #ifdef __ASM_NEED_PPC__ - class EncoderPowerPC final : public EncoderInterface - { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; +class EncoderPowerPC final : public EncoderInterface { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; - LIBCOMPILER_COPY_DEFAULT(EncoderPowerPC); + LIBCOMPILER_COPY_DEFAULT(EncoderPowerPC); - virtual std::string CheckLine(std::string& line, - const std::string& file) override; - virtual bool WriteLine(std::string& line, const std::string& file) override; - virtual bool WriteNumber(const std::size_t& pos, - std::string& from_what) override; - }; + virtual std::string CheckLine(std::string& line, const std::string& file) override; + virtual bool WriteLine(std::string& line, const std::string& file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; -#endif // __ASM_NEED_32x0__ -} // namespace LibCompiler +#endif // __ASM_NEED_32x0__ +} // namespace LibCompiler diff --git a/dev/LibCompiler/Backend/32x0.h b/dev/LibCompiler/Backend/32x0.h index 32f31ff..bb0a5aa 100644 --- a/dev/LibCompiler/Backend/32x0.h +++ b/dev/LibCompiler/Backend/32x0.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -12,47 +12,43 @@ // @file Backend/32x0.hpp #define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, + {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, #define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 -#define kAsmByte 0 +#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 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 kAsmWordStr ".word" /* 32-bit */ #define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ inline std::vector<CpuCode32x0> kOpcodes32x0 = { - kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) - kAsmOpcodeDecl("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) - kAsmOpcodeDecl("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) - kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) - kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) - kAsmOpcodeDecl("lea", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR (1C). - kAsmOpcodeDecl("ret", 0b0111011, 0b110, - kAsmImmediate) // return from procedure (2C). - kAsmOpcodeDecl("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) - kAsmOpcodeDecl("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) - kAsmOpcodeDecl("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) + kAsmOpcodeDecl("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) + kAsmOpcodeDecl("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) + kAsmOpcodeDecl("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) + kAsmOpcodeDecl("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) + kAsmOpcodeDecl("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) + kAsmOpcodeDecl("lea", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR (1C). + kAsmOpcodeDecl("ret", 0b0111011, 0b110, + kAsmImmediate) // return from procedure (2C). + kAsmOpcodeDecl("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) + kAsmOpcodeDecl("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) + kAsmOpcodeDecl("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) }; // \brief 64x0 register prefix @@ -61,10 +57,10 @@ inline std::vector<CpuCode32x0> kOpcodes32x0 = { // r0 -> hw zero #define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 /* return address register */ #define kAsmRetRegister 19 diff --git a/dev/LibCompiler/Backend/64x0.h b/dev/LibCompiler/Backend/64x0.h index a0084b1..745dff0 100644 --- a/dev/LibCompiler/Backend/64x0.h +++ b/dev/LibCompiler/Backend/64x0.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -13,53 +13,48 @@ // @file Backend/64x0.hpp #define kAsmOpcodeDecl(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, \ - .fOpcode = __OPCODE, \ - .fFunct3 = __FUNCT3, \ - .fFunct7 = __FUNCT7}, + {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, #define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 -typedef char e64k_character_t; +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; +struct CpuOpcode64x0 { + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; }; inline std::vector<CpuOpcode64x0> kOpcodes64x0 = { - kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) - kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) - kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) - kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) - kAsmOpcodeDecl("subc", 0b0101011, 0b111, kAsmImmediate) - kAsmOpcodeDecl("sc", 0b1110011, 0b00, kAsmSyscall)}; + kAsmOpcodeDecl("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + kAsmOpcodeDecl("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) kAsmOpcodeDecl( + "bg", 0b1100111, 0b111, kAsmRegToReg) kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) + kAsmOpcodeDecl("subc", 0b0101011, 0b111, kAsmImmediate) + kAsmOpcodeDecl("sc", 0b1110011, 0b00, kAsmSyscall)}; // \brief 64x0 register prefix // example: r32, r0 @@ -67,13 +62,13 @@ inline std::vector<CpuOpcode64x0> kOpcodes64x0 = { // r0 -> hw zero #define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 +#define kAsmZeroRegister 0 #define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 /* return address register */ #define kAsmRetRegister 19 diff --git a/dev/LibCompiler/Backend/amd64.h b/dev/LibCompiler/Backend/amd64.h index 8486b01..f42b131 100644 --- a/dev/LibCompiler/Backend/amd64.h +++ b/dev/LibCompiler/Backend/amd64.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -13,46 +13,36 @@ #define kAsmOpcodeDecl(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, -typedef char i64_character_t; -typedef uint8_t i64_byte_t; +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; +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 kAsmIntOpcode 0xCC #define kasmIntOpcodeAlt 0xCD -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 #define kJumpLimitStandardLimit 0xEB inline std::vector<CpuOpcodeAMD64> kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) - kAsmOpcodeDecl("into", 0xCE) - kAsmOpcodeDecl("intd", 0xF1) - kAsmOpcodeDecl("int3", 0xC3) - kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) - kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) - kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) - kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) - kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF)}; + kAsmOpcodeDecl("int", 0xCD) kAsmOpcodeDecl("into", 0xCE) kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) kAsmOpcodeDecl("iret", 0xCF) kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) kAsmOpcodeDecl("ret", 0xC3) kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) kAsmOpcodeDecl("hlt", 0xf4) kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) kAsmOpcodeDecl("call", 0xFF)}; #define kAsmRegisterLimit 16 diff --git a/dev/LibCompiler/Backend/arm64.h b/dev/LibCompiler/Backend/arm64.h index 08096ee..fb91a1c 100644 --- a/dev/LibCompiler/Backend/arm64.h +++ b/dev/LibCompiler/Backend/arm64.h @@ -6,8 +6,8 @@ Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved #pragma once -#include <stdint.h> #include <LibCompiler/Defines.h> +#include <stdint.h> /// @brief ARM64 encoding support. /// @file Backend/arm64.hpp @@ -15,30 +15,27 @@ Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved 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 +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) +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 +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 kAsmRegisterLimit (30) #define kAsmRegisterPrefix "x" -#define kOpcodeARM64Count (1000) +#define kOpcodeARM64Count (1000) diff --git a/dev/LibCompiler/Backend/power64.h b/dev/LibCompiler/Backend/power64.h index 0f797a5..03aea49 100644 --- a/dev/LibCompiler/Backend/power64.h +++ b/dev/LibCompiler/Backend/power64.h @@ -1,10 +1,10 @@ /* ------------------------------------------- - Some modifications are copyrighted under: - Amlal El Mahrouss + Some modifications are copyrighted under: + Amlal El Mahrouss - Original author: - Apple Inc + Original author: + Apple Inc ------------------------------------------- */ @@ -22,1908 +22,1536 @@ * 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 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 */ +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; +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}}}, + {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}}}, + {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}, + {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}}}, + {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 */ + {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 kAsmZeroRegister 0 #define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 31 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 +#define kAsmRegisterLimit 31 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 /* return address register */ #define kAsmRetRegister 19 diff --git a/dev/LibCompiler/Defines.h b/dev/LibCompiler/Defines.h index 07f3b33..eacf9c0 100644 --- a/dev/LibCompiler/Defines.h +++ b/dev/LibCompiler/Defines.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -9,23 +9,23 @@ #ifndef Yes #define Yes true -#endif // ifndef Yes +#endif // ifndef Yes #ifndef No #define No false -#endif // ifndef No +#endif // ifndef No #ifndef YES #define YES true -#endif // ifndef YES +#endif // ifndef YES #ifndef NO #define NO false -#endif // ifndef NO +#endif // ifndef NO #ifndef BOOL #define BOOL bool -#endif // ifndef BOOL +#endif // ifndef BOOL #define SizeType size_t @@ -34,37 +34,36 @@ #define UIntPtr uintptr_t -#define Int64 int64_t +#define Int64 int64_t #define UInt64 uint64_t -#define Int32 int +#define Int32 int #define UInt32 unsigned #define Bool bool -#define Int16 int16_t +#define Int16 int16_t #define UInt16 uint16_t -#define Int8 int8_t +#define Int8 int8_t #define UInt8 uint8_t #define CharType char -#define Boolean bool +#define Boolean bool -#include <filesystem> -#include <cstdint> #include <cassert> -#include <cstring> -#include <iostream> -#include <utility> #include <cctype> +#include <cstdint> #include <cstdio> +#include <cstring> +#include <filesystem> #include <fstream> +#include <iostream> #include <memory> +#include <new> #include <string> +#include <utility> #include <vector> -#include <vector> -#include <new> #define nullPtr std::nullptr_t @@ -82,76 +81,71 @@ #define rt_copy_memory(dst, src, len) memcpy(dst, src, len) #endif -#define LIBCOMPILER_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; +#define LIBCOMPILER_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; -#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; +#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; -#define LIBCOMPILER_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; +#define LIBCOMPILER_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; -#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; +#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; #define LC_IMPORT_C extern "C" -#define LC_IMPORT extern +#define LC_IMPORT extern #include <ctime> #include <fstream> #include <string> #include <vector> -namespace LibCompiler -{ - inline constexpr int kBaseYear = 1900; +namespace LibCompiler { +inline constexpr int kBaseYear = 1900; - typedef std::string String; +typedef std::string String; - inline String current_date() noexcept - { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); +inline String current_date() noexcept { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); - String fmt = std::to_string(kBaseYear + time_struct->tm_year); + String fmt = std::to_string(kBaseYear + time_struct->tm_year); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); - return fmt; - } + return fmt; +} - inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept - { - if (limit == 0) - return false; +inline bool to_str(CharType* str, Int32 limit, Int32 base) noexcept { + if (limit == 0) return false; - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; - while (limit != 1) - { - ret = ret % 10; - str[cnt] = ret; + while (limit != 1) { + ret = ret % 10; + str[cnt] = ret; - ++cnt; - --limit; - --ret; - } + ++cnt; + --limit; + --ret; + } - str[copy_limit] = '\0'; - return true; - } + str[copy_limit] = '\0'; + return true; +} - using String = std::basic_string<CharType>; -} // namespace LibCompiler +using String = std::basic_string<CharType>; +} // namespace LibCompiler #define PACKED __attribute__((packed)) @@ -160,10 +154,8 @@ typedef char char_type; #define kObjectFileExt ".obj" #define kBinaryFileExt ".bin" -#define kAsmFileExts \ - { \ - ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" \ - } +#define kAsmFileExts \ + { ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" } #define kAsmFileExtsMax 7 @@ -171,6 +163,6 @@ typedef char char_type; #ifdef MSVC #pragma scalar_storage_order big - endian -#endif // ifdef MSVC +#endif // ifdef MSVC #endif /* ifndef __LIBCOMPILER_DEFINES_H__ */ diff --git a/dev/LibCompiler/ErrorID.h b/dev/LibCompiler/ErrorID.h index b105f9b..1f58313 100644 --- a/dev/LibCompiler/ErrorID.h +++ b/dev/LibCompiler/ErrorID.h @@ -12,12 +12,12 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/ErrorOr.h> -#define LIBCOMPILER_SUCCESSS 0 -#define LIBCOMPILER_EXEC_ERROR -30 +#define LIBCOMPILER_SUCCESSS 0 +#define LIBCOMPILER_EXEC_ERROR -30 #define LIBCOMPILER_FILE_NOT_FOUND -31 -#define LIBCOMPILER_DIR_NOT_FOUND -32 -#define LIBCOMPILER_FILE_EXISTS -33 -#define LIBCOMPILER_TOO_LONG -34 -#define LIBCOMPILER_INVALID_DATA -35 -#define LIBCOMPILER_UNIMPLEMENTED -36 -#define LIBCOMPILER_FAT_ERROR -37 +#define LIBCOMPILER_DIR_NOT_FOUND -32 +#define LIBCOMPILER_FILE_EXISTS -33 +#define LIBCOMPILER_TOO_LONG -34 +#define LIBCOMPILER_INVALID_DATA -35 +#define LIBCOMPILER_UNIMPLEMENTED -36 +#define LIBCOMPILER_FAT_ERROR -37 diff --git a/dev/LibCompiler/ErrorOr.h b/dev/LibCompiler/ErrorOr.h index 2a6d590..ca93dd2 100644 --- a/dev/LibCompiler/ErrorOr.h +++ b/dev/LibCompiler/ErrorOr.h @@ -12,50 +12,34 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/Ref.h> -namespace LibCompiler -{ - using ErrorT = UInt32; - - template <typename T> - class ErrorOr final - { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(Int32 err) - : mId(err) - { - } - - explicit ErrorOr(nullPtr Null) - { - } - - explicit ErrorOr(T Class) - : mRef(Class) - { - } - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref<T> Leak() - { - return mRef; - } - - operator bool() - { - return mRef; - } - - private: - Ref<T> mRef; - Int32 mId{0}; - }; - - using ErrorOrAny = ErrorOr<voidPtr>; - -} // namespace LibCompiler +namespace LibCompiler { +using ErrorT = UInt32; + +template <typename T> +class ErrorOr final { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(Int32 err) : mId(err) {} + + explicit ErrorOr(nullPtr Null) {} + + explicit ErrorOr(T Class) : mRef(Class) {} + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref<T> Leak() { return mRef; } + + operator bool() { return mRef; } + + private: + Ref<T> mRef; + Int32 mId{0}; +}; + +using ErrorOrAny = ErrorOr<voidPtr>; + +} // namespace LibCompiler diff --git a/dev/LibCompiler/Macros.h b/dev/LibCompiler/Macros.h index f2f5f6b..cce89d6 100644 --- a/dev/LibCompiler/Macros.h +++ b/dev/LibCompiler/Macros.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -9,25 +9,25 @@ #ifndef _MACROS_H_ #define _MACROS_H_ -#define LIBCOMPILER_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; +#define LIBCOMPILER_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; -#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; +#define LIBCOMPILER_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; -#define LIBCOMPILER_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; +#define LIBCOMPILER_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; -#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; +#define LIBCOMPILER_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; /// @note xxxx is the error placeholder, in hexadecimal. #define LIBCOMPILER_ERROR_PREFIX_CXX "CXXxxxx" -#define LIBCOMPILER_ERROR_PREFIX_CL "CLxxxx" +#define LIBCOMPILER_ERROR_PREFIX_CL "CLxxxx" #define LIBCOMPILER_ERROR_PREFIX_ASM "ASMxxxx" #endif /* ifndef _MACROS_H_ */ diff --git a/dev/LibCompiler/PEF.h b/dev/LibCompiler/PEF.h index 1148dea..f32d830 100644 --- a/dev/LibCompiler/PEF.h +++ b/dev/LibCompiler/PEF.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -11,14 +11,14 @@ // @file PEF.hpp // @brief Preferred Executable Format -#define kPefMagic "Joy!" +#define kPefMagic "Joy!" #define kPefMagicFat "yoJ!" -#define kPefExt ".exec" -#define kPefDylibExt ".dylib" -#define kPefLibExt ".lib" +#define kPefExt ".exec" +#define kPefDylibExt ".dylib" +#define kPefLibExt ".lib" #define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" +#define kPefDebugExt ".dbg" #define kPefDriverExt ".sys" #define kPefZero128 ".zero128" @@ -38,107 +38,92 @@ #define kPefStart "__ImageStart" -namespace LibCompiler -{ - enum - { - kPefArchStart = 99, - kPefArchIntel86S = 100, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* 64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchARM64, - kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, - }; - - enum - { - kPefSubArchAMD, - kPefSubArchIntel, - kPefSubArchARM, - kPefSubArchGeneric, - kPefSubArchIBM, - }; - - enum - { - kPefKindExec = 1, /* .o */ - kPefKindDylib = 2, /* .dylib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, - }; - - /* PEF container */ - typedef struct PEFContainer final - { - CharType Magic[kPefMagicLen]; - UInt32 Linker; - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - } PACKED PEFContainer, *PEFContainerPtr; - - /* First PEFCommandHeader starts after PEFContainer */ - /* Last container is __exec_end */ - - /* PEF executable section and commands. */ - - typedef struct PEFCommandHeader final - { - CharType Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* file offset */ - SizeType Size; /* file size */ - } PACKED PEFCommandHeader, *PEFCommandHeaderPtr; - - enum - { - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, - kPefInvalid = 0xFF, - }; -} // namespace LibCompiler - -inline std::ofstream& operator<<(std::ofstream& fp, - LibCompiler::PEFContainer& container) -{ - fp.write((char*)&container, sizeof(LibCompiler::PEFContainer)); - return fp; +namespace LibCompiler { +enum { + kPefArchStart = 99, + kPefArchIntel86S = 100, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* 64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, + kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, +}; + +enum { + kPefSubArchAMD, + kPefSubArchIntel, + kPefSubArchARM, + kPefSubArchGeneric, + kPefSubArchIBM, +}; + +enum { + kPefKindExec = 1, /* .o */ + kPefKindDylib = 2, /* .dylib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, +}; + +/* PEF container */ +typedef struct PEFContainer final { + CharType Magic[kPefMagicLen]; + UInt32 Linker; + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ +} PACKED PEFContainer, *PEFContainerPtr; + +/* First PEFCommandHeader starts after PEFContainer */ +/* Last container is __exec_end */ + +/* PEF executable section and commands. */ + +typedef struct PEFCommandHeader final { + CharType Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* file offset */ + SizeType Size; /* file size */ +} PACKED PEFCommandHeader, *PEFCommandHeaderPtr; + +enum { + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, + kPefInvalid = 0xFF, +}; +} // namespace LibCompiler + +inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::PEFContainer& container) { + fp.write((char*) &container, sizeof(LibCompiler::PEFContainer)); + return fp; } -inline std::ofstream& operator<<(std::ofstream& fp, - LibCompiler::PEFCommandHeader& container) -{ - fp.write((char*)&container, sizeof(LibCompiler::PEFCommandHeader)); - return fp; +inline std::ofstream& operator<<(std::ofstream& fp, LibCompiler::PEFCommandHeader& container) { + fp.write((char*) &container, sizeof(LibCompiler::PEFCommandHeader)); + return fp; } -inline std::ifstream& operator>>(std::ifstream& fp, - LibCompiler::PEFContainer& container) -{ - fp.read((char*)&container, sizeof(LibCompiler::PEFContainer)); - return fp; +inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::PEFContainer& container) { + fp.read((char*) &container, sizeof(LibCompiler::PEFContainer)); + return fp; } -inline std::ifstream& operator>>(std::ifstream& fp, - LibCompiler::PEFCommandHeader& container) -{ - fp.read((char*)&container, sizeof(LibCompiler::PEFCommandHeader)); - return fp; +inline std::ifstream& operator>>(std::ifstream& fp, LibCompiler::PEFCommandHeader& container) { + fp.read((char*) &container, sizeof(LibCompiler::PEFCommandHeader)); + return fp; } diff --git a/dev/LibCompiler/Parser.h b/dev/LibCompiler/Parser.h index cb0e470..04a7fab 100644 --- a/dev/LibCompiler/Parser.h +++ b/dev/LibCompiler/Parser.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -8,172 +8,143 @@ #include <LibCompiler/AssemblyInterface.h> -namespace LibCompiler -{ - inline auto kInvalidFrontend = "NA"; - - /// @brief Compiler backend, implements a frontend, such as C, C++... - /// See Toolchain, for some examples. - class ICompilerFrontend - { - public: - explicit ICompilerFrontend() = default; - virtual ~ICompilerFrontend() = default; - - LIBCOMPILER_COPY_DEFAULT(ICompilerFrontend); - - // NOTE: cast this to your user defined ast. - typedef void* AstType; - - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - - virtual bool Compile(std::string text, const std::string file) = 0; - - //! @brief What language are we dealing with? - virtual const char* Language() - { - return kInvalidFrontend; - } - - virtual bool IsValid() - { - return strcmp(this->Language(), kInvalidFrontend) > 0; - } - }; - - struct SyntaxLeafList; - struct SyntaxLeafList; - struct CompilerKeyword; - - /// we want to do that because 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 - { - std::string keyword_name; - KeywordKind keyword_kind = kKeywordKindInvalid; - }; - struct SyntaxLeafList final - { - struct SyntaxLeaf final - { - Int32 fUserType; +namespace LibCompiler { +inline auto kInvalidFrontend = "NA"; + +/// @brief Compiler backend, implements a frontend, such as C, C++... +/// See Toolchain, for some examples. +class ICompilerFrontend { + public: + explicit ICompilerFrontend() = default; + virtual ~ICompilerFrontend() = default; + + LIBCOMPILER_COPY_DEFAULT(ICompilerFrontend); + + // NOTE: cast this to your user defined ast. + typedef void* AstType; + + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + + virtual bool Compile(std::string text, const std::string file) = 0; + + //! @brief What language are we dealing with? + virtual const char* Language() { return kInvalidFrontend; } + + virtual bool IsValid() { return strcmp(this->Language(), kInvalidFrontend) > 0; } +}; + +struct SyntaxLeafList; +struct SyntaxLeafList; +struct CompilerKeyword; + +/// we want to do that because 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 { + std::string keyword_name; + KeywordKind keyword_kind = kKeywordKindInvalid; +}; +struct SyntaxLeafList final { + struct SyntaxLeaf final { + Int32 fUserType; #ifdef LC_USE_STRUCTS - CompilerKeyword fUserData; + CompilerKeyword fUserData; #else - std::string fUserData; + std::string fUserData; #endif - SyntaxLeaf() = default; - - std::string fUserValue; - struct SyntaxLeaf* fNext; - }; - - std::vector<SyntaxLeaf> fLeafList; - SizeType fNumLeafs; - - size_t SizeOf() - { - return fNumLeafs; - } - std::vector<SyntaxLeaf>& Get() - { - return fLeafList; - } - SyntaxLeaf& At(size_t index) - { - return fLeafList[index]; - } - }; - - /// find the perfect matching word in a haystack. - /// \param haystack base string - /// \param needle the string we search for. - /// \return if we found it or not. - inline bool find_word(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) - return true; - - if (index <= 0 || index >= haystack.size()) - return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); - } - - /// find a word within strict conditions and returns a range of it. - /// \param haystack - /// \param needle - /// \return position of needle. - inline std::size_t find_word_range(const std::string& haystack, - const std::string& needle) noexcept - { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == std::string::npos) - return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) - { - return index; - } - - return false; - } -} // namespace LibCompiler + SyntaxLeaf() = default; + + std::string fUserValue; + struct SyntaxLeaf* fNext; + }; + + std::vector<SyntaxLeaf> fLeafList; + SizeType fNumLeafs; + + size_t SizeOf() { return fNumLeafs; } + std::vector<SyntaxLeaf>& Get() { return fLeafList; } + SyntaxLeaf& At(size_t index) { return fLeafList[index]; } +}; + +/// find the perfect matching word in a haystack. +/// \param haystack base string +/// \param needle the string we search for. +/// \return if we found it or not. +inline bool find_word(const std::string& haystack, const std::string& needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) return true; + + if (index <= 0 || index >= haystack.size()) return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); +} + +/// find a word within strict conditions and returns a range of it. +/// \param haystack +/// \param needle +/// \return position of needle. +inline std::size_t find_word_range(const std::string& haystack, + const std::string& needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == std::string::npos) return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) { + return index; + } + + return false; +} +} // namespace LibCompiler diff --git a/dev/LibCompiler/Ref.h b/dev/LibCompiler/Ref.h index 117083c..c5188b5 100644 --- a/dev/LibCompiler/Ref.h +++ b/dev/LibCompiler/Ref.h @@ -12,92 +12,64 @@ #include <LibCompiler/Defines.h> -namespace LibCompiler -{ - // @author EL Mahrouss Amlal - // @brief Reference holder class, refers to a pointer of data in static memory. - template <typename T> - class Ref final - { - public: - explicit Ref() = default; - - ~Ref() - { - if (m_Strong) - { - (*m_Class).~T(); - } - } - - LIBCOMPILER_COPY_DEFAULT(Ref); - - public: - explicit Ref(T cls, const Bool& strong = false) - : m_Class(&cls), m_Strong(strong) - { - } - - Ref& operator=(T ref) - { - *m_Class = ref; - return *this; - } - - public: - T* operator->() const - { - return m_Class; - } - - T& Leak() - { - return *m_Class; - } - - T operator*() - { - return *m_Class; - } - - Bool IsStrong() const - { - return m_Strong; - } - - operator bool() - { - return *m_Class; - } - - private: - T* m_Class{nullptr}; - Bool m_Strong{false}; - }; - - // @author EL Mahrouss Amlal - // @brief Non null Reference holder class, refers to a pointer of data in static memory. - template <typename T> - class NonNullRef final - { - public: - explicit NonNullRef() = delete; - - explicit NonNullRef(T* ref) - : m_Ref(ref, true) - { - } - - Ref<T>& operator->() - { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef<T>& ref) = delete; - NonNullRef(const NonNullRef<T>& ref) = default; - - private: - Ref<T> m_Ref{nullptr}; - }; -} // namespace LibCompiler +namespace LibCompiler { +// @author EL Mahrouss Amlal +// @brief Reference holder class, refers to a pointer of data in static memory. +template <typename T> +class Ref final { + public: + explicit Ref() = default; + + ~Ref() { + if (m_Strong) { + (*m_Class).~T(); + } + } + + LIBCOMPILER_COPY_DEFAULT(Ref); + + public: + explicit Ref(T cls, const Bool& strong = false) : m_Class(&cls), m_Strong(strong) {} + + Ref& operator=(T ref) { + *m_Class = ref; + return *this; + } + + public: + T* operator->() const { return m_Class; } + + T& Leak() { return *m_Class; } + + T operator*() { return *m_Class; } + + Bool IsStrong() const { return m_Strong; } + + operator bool() { return *m_Class; } + + private: + T* m_Class{nullptr}; + Bool m_Strong{false}; +}; + +// @author EL Mahrouss Amlal +// @brief Non null Reference holder class, refers to a pointer of data in static memory. +template <typename T> +class NonNullRef final { + public: + explicit NonNullRef() = delete; + + explicit NonNullRef(T* ref) : m_Ref(ref, true) {} + + Ref<T>& operator->() { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef<T>& ref) = delete; + NonNullRef(const NonNullRef<T>& ref) = default; + + private: + Ref<T> m_Ref{nullptr}; +}; +} // namespace LibCompiler diff --git a/dev/LibCompiler/StringView.h b/dev/LibCompiler/StringView.h index b65121e..18003a3 100644 --- a/dev/LibCompiler/StringView.h +++ b/dev/LibCompiler/StringView.h @@ -12,79 +12,66 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/ErrorOr.h> -namespace LibCompiler -{ - /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - - class StringView final - { - public: - explicit StringView() = delete; - - explicit StringView(SizeType Sz) noexcept - : m_Sz(Sz) - { - m_Data = new CharType[Sz]; - assert(m_Data); - } - - ~StringView() noexcept - { - if (m_Data) - { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - LIBCOMPILER_COPY_DEFAULT(StringView); - - CharType* Data(); - const CharType* CData() const; - SizeType Length() const; - - bool operator==(const CharType* rhs) const; - bool operator!=(const CharType* rhs) const; - - bool operator==(const StringView& rhs) const; - bool operator!=(const StringView& rhs) const; - - StringView& operator+=(const CharType* rhs); - StringView& operator+=(const StringView& rhs); - - operator bool() - { - return m_Data && m_Data[0] != 0; - } - - bool operator!() - { - return !m_Data || m_Data[0] == 0; - } - - private: - CharType* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; - }; - - /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ - struct StringBuilder final - { - static StringView Construct(const CharType* data); - static const char* FromInt(const char* fmt, int n); - static const char* FromBool(const char* fmt, bool n); - static const char* Format(const char* fmt, const char* from); - static bool Equals(const char* lhs, const char* rhs); - }; -} // namespace LibCompiler +namespace LibCompiler { +/** + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ + +class StringView final { + public: + explicit StringView() = delete; + + explicit StringView(SizeType Sz) noexcept : m_Sz(Sz) { + m_Data = new CharType[Sz]; + assert(m_Data); + } + + ~StringView() noexcept { + if (m_Data) { + memset(m_Data, 0, m_Sz); + delete[] m_Data; + + m_Data = nullptr; + } + } + + LIBCOMPILER_COPY_DEFAULT(StringView); + + CharType* Data(); + const CharType* CData() const; + SizeType Length() const; + + bool operator==(const CharType* rhs) const; + bool operator!=(const CharType* rhs) const; + + bool operator==(const StringView& rhs) const; + bool operator!=(const StringView& rhs) const; + + StringView& operator+=(const CharType* rhs); + StringView& operator+=(const StringView& rhs); + + operator bool() { return m_Data && m_Data[0] != 0; } + + bool operator!() { return !m_Data || m_Data[0] == 0; } + + private: + CharType* m_Data{nullptr}; + SizeType m_Sz{0}; + SizeType m_Cur{0}; + + friend class StringBuilder; +}; + +/** + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ +struct StringBuilder final { + static StringView Construct(const CharType* data); + static const char* FromInt(const char* fmt, int n); + static const char* FromBool(const char* fmt, bool n); + static const char* Format(const char* fmt, const char* from); + static bool Equals(const char* lhs, const char* rhs); +}; +} // namespace LibCompiler diff --git a/dev/LibCompiler/UUID.h b/dev/LibCompiler/UUID.h index 84ffd43..d54eec7 100644 --- a/dev/LibCompiler/UUID.h +++ b/dev/LibCompiler/UUID.h @@ -63,921 +63,773 @@ #endif -namespace uuids -{ +namespace uuids { #ifdef __cpp_lib_span - template <class ElementType, std::size_t Extent> - using span = std::span<ElementType, Extent>; +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>; +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 inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) || - (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) || - (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')); - } - - template <typename TChar> - [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template <typename StringType> - [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type, - typename StringType::traits_type> - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast<const uint8_t*>(start); - const uint8_t* finish = static_cast<const uint8_t*>(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast<const uint8_t*>(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast<uint8_t>(d32[0] >> 24); - digest[di++] = static_cast<uint8_t>(d32[0] >> 16); - digest[di++] = static_cast<uint8_t>(d32[0] >> 8); - digest[di++] = static_cast<uint8_t>(d32[0] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[1] >> 24); - digest[di++] = static_cast<uint8_t>(d32[1] >> 16); - digest[di++] = static_cast<uint8_t>(d32[1] >> 8); - digest[di++] = static_cast<uint8_t>(d32[1] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[2] >> 24); - digest[di++] = static_cast<uint8_t>(d32[2] >> 16); - digest[di++] = static_cast<uint8_t>(d32[2] >> 8); - digest[di++] = static_cast<uint8_t>(d32[2] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[3] >> 24); - digest[di++] = static_cast<uint8_t>(d32[3] >> 16); - digest[di++] = static_cast<uint8_t>(d32[3] >> 8); - digest[di++] = static_cast<uint8_t>(d32[3] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[4] >> 24); - digest[di++] = static_cast<uint8_t>(d32[4] >> 16); - digest[di++] = static_cast<uint8_t>(d32[4] >> 8); - digest[di++] = static_cast<uint8_t>(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template <typename CharT> - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid<wchar_t>[37] = - L"00000000-0000-0000-0000-000000000000"; - - template <typename CharT> - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef"; - } // namespace 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 || !Detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template <typename StringType> - [[nodiscard]] constexpr static std::optional<uuid> from_string( - StringType const& in_str) noexcept - { - auto str = 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 || !Detail::is_hex(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 - // -------------------------------------------------------------------------------------------------------------------------- +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 inline bool is_hex(TChar const ch) noexcept { + return (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) || + (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) || + (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')); + } + + template <typename TChar> + [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const* str) noexcept { + if (str) return str; + return {}; + } + + template <typename StringType> + [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type, + typename StringType::traits_type> + to_string_view(StringType const& str) noexcept { + return str; + } + + class sha1 { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() { reset(); } + + void reset() noexcept { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) { + const uint8_t* begin = static_cast<const uint8_t*>(start); + const uint8_t* finish = static_cast<const uint8_t*>(end); + while (begin != finish) { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) { + const uint8_t* block = static_cast<const uint8_t*>(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + process_byte(0); + } + while (m_blockByteIndex < 56) { + process_byte(0); + } + } else { + while (m_blockByteIndex < 56) { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast<uint8_t>(d32[0] >> 24); + digest[di++] = static_cast<uint8_t>(d32[0] >> 16); + digest[di++] = static_cast<uint8_t>(d32[0] >> 8); + digest[di++] = static_cast<uint8_t>(d32[0] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[1] >> 24); + digest[di++] = static_cast<uint8_t>(d32[1] >> 16); + digest[di++] = static_cast<uint8_t>(d32[1] >> 8); + digest[di++] = static_cast<uint8_t>(d32[1] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[2] >> 24); + digest[di++] = static_cast<uint8_t>(d32[2] >> 16); + digest[di++] = static_cast<uint8_t>(d32[2] >> 8); + digest[di++] = static_cast<uint8_t>(d32[2] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[3] >> 24); + digest[di++] = static_cast<uint8_t>(d32[3] >> 16); + digest[di++] = static_cast<uint8_t>(d32[3] >> 8); + digest[di++] = static_cast<uint8_t>(d32[3] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[4] >> 24); + digest[di++] = static_cast<uint8_t>(d32[4] >> 16); + digest[di++] = static_cast<uint8_t>(d32[4] >> 8); + digest[di++] = static_cast<uint8_t>(d32[4] >> 0); + + return digest; + } + + private: + void process_block() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template <typename CharT> + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000"; + + template <typename CharT> + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef"; +} // namespace 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 || !Detail::is_hex(str[i])) { + return false; + } + + if (firstDigit) { + firstDigit = false; + } else { + index++; + firstDigit = true; + } + } + + if (index < 16) { + return false; + } + + return true; + } + + template <typename StringType> + [[nodiscard]] constexpr static std::optional<uuid> from_string( + StringType const& in_str) noexcept { + auto str = 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 || !Detail::is_hex(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; +class uuid_system_generator { + public: + using result_type = uuid; - uuid operator()() - { + uuid operator()() { #ifdef _WIN32 - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } + 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), + std::array<uint8_t, 16> bytes = { + {static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF), + static_cast<unsigned char>((newId.Data1) & 0xFF), - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), + (unsigned char) ((newId.Data2 >> 8) & 0xFF), (unsigned char) ((newId.Data2) & 0xFF), - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), + (unsigned char) ((newId.Data3 >> 8) & 0xFF), (unsigned char) ((newId.Data3) & 0xFF), - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + 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)}; + return uuid{std::begin(bytes), std::end(bytes)}; #elif defined(__linux__) || defined(__unix__) - uuid_t id; - uuid_generate(id); + 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]}}; + 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)}; + 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)}; + 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{}; + 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; - }; +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>; +// !!! 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; + std::optional<mac_address> device_address; - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } + [[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; + 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(); - } + 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]] 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++; - } + [[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; + public: + [[nodiscard]] uuid operator()() { + if (get_mac_address()) { + std::array<uuids::uuid::value_type, 16> data; - auto tm = get_time_intervals(); + auto tm = get_time_intervals(); - auto clock_seq = get_clock_sequence(); + auto clock_seq = get_clock_sequence(); - auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm); + 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[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); - memcpy(&data[8], &clock_seq, 2); + memcpy(&data[8], &clock_seq, 2); - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; - memcpy(&data[10], &device_address.value()[0], 6); + memcpy(&data[10], &device_address.value()[0], 6); - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } - return {}; - } - }; + 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 - { +} // 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))); + 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)); - } + 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 + } +}; +} // namespace std #endif /* STDUUID_H */
\ No newline at end of file diff --git a/dev/LibCompiler/Version.h b/dev/LibCompiler/Version.h index c10a16e..a623312 100644 --- a/dev/LibCompiler/Version.h +++ b/dev/LibCompiler/Version.h @@ -1,15 +1,15 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ #pragma once -#define kDistVersion "v1.1.0" +#define kDistVersion "v1.1.0" #define kDistVersionBCD 0x0110 -#define ToString(X) Stringify(X) +#define ToString(X) Stringify(X) #define Stringify(X) #X #define kDistRelease ToString(kDistReleaseBranch) diff --git a/dev/LibCompiler/XCOFF.h b/dev/LibCompiler/XCOFF.h index 862c363..047a20f 100644 --- a/dev/LibCompiler/XCOFF.h +++ b/dev/LibCompiler/XCOFF.h @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved - File: XCOFF.hpp - Purpose: XCOFF for NeKernel. + File: XCOFF.hpp + Purpose: XCOFF for NeKernel. - Revision History: + Revision History: - 04/07/24: Added file (amlel) + 04/07/24: Added file (amlel) ------------------------------------------- */ @@ -18,24 +18,22 @@ #define kXCOFF64Magic 0x01F7 -#define kXCOFFRelFlg 0x0001 +#define kXCOFFRelFlg 0x0001 #define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace LibCompiler -{ - /// @brief XCoff identification header. - typedef struct XCoffFileHeader - { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header - } XCoffFileHeader; -} // namespace LibCompiler - -#endif // ifndef __XCOFF__ +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace LibCompiler { +/// @brief XCoff identification header. +typedef struct XCoffFileHeader { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header +} XCoffFileHeader; +} // namespace LibCompiler + +#endif // ifndef __XCOFF__ diff --git a/dev/LibCompiler/src/Assembler32x0.cc b/dev/LibCompiler/src/Assembler32x0.cc index 1790b8b..ac24946 100644 --- a/dev/LibCompiler/src/Assembler32x0.cc +++ b/dev/LibCompiler/src/Assembler32x0.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -19,10 +19,10 @@ #define __ASM_NEED_32x0__ 1 -#include <LibCompiler/Backend/32x0.h> -#include <LibCompiler/Parser.h> #include <LibCompiler/AE.h> +#include <LibCompiler/Backend/32x0.h> #include <LibCompiler/PEF.h> +#include <LibCompiler/Parser.h> ///////////////////// @@ -30,9 +30,9 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) @@ -44,7 +44,6 @@ ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(NEAssemblerMain32000) -{ - return 0; +LIBCOMPILER_MODULE(NEAssemblerMain32000) { + return 0; } diff --git a/dev/LibCompiler/src/Assembler64x0.cc b/dev/LibCompiler/src/Assembler64x0.cc index 7630adf..7701982 100644 --- a/dev/LibCompiler/src/Assembler64x0.cc +++ b/dev/LibCompiler/src/Assembler64x0.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -19,10 +19,10 @@ #define __ASM_NEED_64x0__ 1 -#include <LibCompiler/Backend/64x0.h> -#include <LibCompiler/Parser.h> #include <LibCompiler/AE.h> +#include <LibCompiler/Backend/64x0.h> #include <LibCompiler/PEF.h> +#include <LibCompiler/Parser.h> #include <algorithm> #include <filesystem> #include <fstream> @@ -35,25 +35,25 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) -static char kOutputArch = LibCompiler::kPefArch64000; +static char kOutputArch = LibCompiler::kPefArch64000; static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; constexpr auto c64x0IPAlignment = 0x4U; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; static bool kVerbose = false; @@ -61,49 +61,42 @@ static bool kVerbose = false; static std::vector<e64k_num_t> kBytes; static LibCompiler::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector<LibCompiler::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; +static std::vector<std::string> kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; // \brief forward decl. static bool asm_read_attributes(std::string& line); -namespace Detail -{ - void print_error(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); +namespace Detail { +void print_error(std::string reason, std::string file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); - kStdErr << kRed << "[ asm ] " << kWhite - << ((file == "LibCompiler") ? "InternalErrorException: " - : ("FileException{ " + file + " }: ")) - << kBlank << std::endl; - kStdErr << kRed << "[ asm ] " << kWhite << reason << kBlank << std::endl; + kStdErr << kRed << "[ asm ] " << kWhite + << ((file == "LibCompiler") ? "InternalErrorException: " + : ("FileException{ " + file + " }: ")) + << kBlank << std::endl; + kStdErr << kRed << "[ asm ] " << kWhite << reason << kBlank << std::endl; - if (kAcceptableErrors > kErrorLimit) - std::exit(3); + if (kAcceptableErrors > kErrorLimit) std::exit(3); - ++kAcceptableErrors; - } + ++kAcceptableErrors; +} - void print_warning(std::string reason, std::string file) noexcept - { - if (reason[0] == '\n') - reason.erase(0, 1); +void print_warning(std::string reason, std::string file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); - if (!file.empty()) - { - kStdOut << kYellow << "[ asm ] " << kWhite << file << kBlank << std::endl; - } + if (!file.empty()) { + kStdOut << kYellow << "[ asm ] " << kWhite << file << kBlank << std::endl; + } - kStdOut << kYellow << "[ asm ] " << kWhite << reason << kBlank << std::endl; - } -} // namespace Detail + kStdOut << kYellow << "[ asm ] " << kWhite << reason << kBlank << std::endl; +} +} // namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -111,225 +104,191 @@ namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMain64x0) -{ - for (size_t i = 1; i < argc; ++i) - { - if (argv[i][0] == '-') - { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) - { - kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } - else if (strcmp(argv[i], "--h") == 0) - { - kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss " - "Logic.\n"; - kStdOut << "--version: Print program version.\n"; - kStdOut << "--verbose: Print verbose output.\n"; - kStdOut << "--binary: Output as flat binary.\n"; - kStdOut << "--64xxx: Compile for a subset of the X64000.\n"; - - return 0; - } - else if (strcmp(argv[i], "--binary") == 0) - { - kOutputAsBinary = true; - continue; - } - else if (strcmp(argv[i], "--verbose") == 0) - { - kVerbose = true; - continue; - } - - kStdOut << "Assembler64x0: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) - { - kStdOut << "Assembler64x0: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) - { - if (object_output.find(ext) != std::string::npos) - { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) - { - if (kVerbose) - { - kStdOut << "Assembler64x0: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - LibCompiler::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(LibCompiler::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - LibCompiler::Encoder64x0 asm64; - - while (std::getline(file_ptr, line)) - { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) - { - 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, "LibCompiler"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "Assembler64x0: Writing object file...\n"; - } +LIBCOMPILER_MODULE(AssemblerMain64x0) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { + kStdOut + << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) " + "Amlal El Mahrouss\n"; + return 0; + } else if (strcmp(argv[i], "--h") == 0) { + kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss " + "Logic.\n"; + kStdOut << "--version: Print program version.\n"; + kStdOut << "--verbose: Print verbose output.\n"; + kStdOut << "--binary: Output as flat binary.\n"; + kStdOut << "--64xxx: Compile for a subset of the X64000.\n"; + + return 0; + } else if (strcmp(argv[i], "--binary") == 0) { + kOutputAsBinary = true; + continue; + } else if (strcmp(argv[i], "--verbose") == 0) { + kVerbose = true; + continue; + } + + kStdOut << "Assembler64x0: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) { + kStdOut << "Assembler64x0: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) { + if (object_output.find(ext) != std::string::npos) { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) { + if (kVerbose) { + kStdOut << "Assembler64x0: error: " << strerror(errno) << "\n"; + } + } - // this is the final step, write everything to the file. + std::string line; - auto pos = file_ptr_out.tellp(); + LibCompiler::AEHeader hdr{0}; - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + memset(hdr.fPad, kAENullType, kAEPad); - file_ptr_out << hdr; + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(LibCompiler::AEHeader); + hdr.fArch = kOutputArch; - 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; - } + // COMPILATION LOOP - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + ///////////////////////////////////////////////////////////////////////////////////////// - std::size_t record_count = 0UL; + LibCompiler::Encoder64x0 asm64; - for (auto& rec : kRecords) - { - if (kVerbose) - kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n"; + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + Detail::print_error(ln, argv[i]); + continue; + } - rec.fFlags |= LibCompiler::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; + 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, "LibCompiler"); + } - file_ptr_out << rec; - } + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "Assembler64x0: Writing object file...\n"; + } - for (auto& sym : kUndefinedSymbols) - { - LibCompiler::AERecordHeader _record_hdr{0}; + // this is the final step, write everything to the file. - if (kVerbose) - kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n"; + auto pos = file_ptr_out.tellp(); - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - ++record_count; + file_ptr_out << hdr; - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + 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"; - file_ptr_out << _record_hdr; + std::filesystem::remove(object_output); + return 1; + } - ++kCounter; - } + kRecords[kRecords.size() - 1].fSize = kBytes.size(); - auto pos_end = file_ptr_out.tellp(); + std::size_t record_count = 0UL; - file_ptr_out.seekp(pos); + for (auto& rec : kRecords) { + if (kVerbose) kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n"; - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); + rec.fFlags |= LibCompiler::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; - file_ptr_out << hdr; + file_ptr_out << rec; + } - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "Assembler64x0: Write raw binary...\n"; - } - } + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - // byte from byte, we write this. - for (auto& byte : kBytes) - { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } + for (auto& sym : kUndefinedSymbols) { + LibCompiler::AERecordHeader _record_hdr{0}; - if (kVerbose) - kStdOut << "Assembler64x0: Wrote file with program in it.\n"; + if (kVerbose) kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n"; - file_ptr_out.flush(); - file_ptr_out.close(); + _record_hdr.fKind = kAENullType; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; - if (kVerbose) - kStdOut << "Assembler64x0: Exit succeeded.\n"; + ++record_count; - return 0; - } + 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"; + if (kVerbose) kStdOut << "Assembler64x0: Exit failed.\n"; - return 1; + return 1; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -339,176 +298,145 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string& line) -{ - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (LibCompiler::find_word(line, "extern_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment")); - - /// sanity check to avoid stupid linker errors. - if (name.size() == 0) - { - 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 = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (LibCompiler::find_word(line, "public_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid public_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. +static bool asm_read_attributes(std::string& line) { + // extern_segment is the opposite of public_segment, it signals to the ld + // that we need this symbol. + if (LibCompiler::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment")); - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); + /// 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"); + } - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; - // now we can tell the code size of the previous kCurrentRecord. + // mangle this + for (char& j : name) { + if (j == ' ' || j == ',') j = '$'; + } - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + result += name; - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = LibCompiler::kPefZero; + } - ++kCounter; + // this is a special case for the start stub. + // we want this so that ld can find it. - memset(kCurrentRecord.fPad, kAENullType, kAEPad); + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } - kRecords.emplace_back(kCurrentRecord); + // now we can tell the code size of the previous kCurrentRecord. - return true; - } + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - return false; + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (LibCompiler::find_word(line, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_public_segment_bin"); + } + + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); + + std::string name_copy = name; + + for (char& j : name) { + if (j == ' ') j = '$'; + } + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = LibCompiler::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; } // \brief algorithms and helpers. -namespace 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(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); - } -} // namespace Detail::algorithm +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(const std::string& str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -516,258 +444,199 @@ namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// -std::string LibCompiler::Encoder64x0::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || LibCompiler::find_word(line, "extern_segment") || - LibCompiler::find_word(line, "public_segment") || - line.find('#') != std::string::npos || LibCompiler::find_word(line, ";")) - { - if (line.find('#') != std::string::npos) - { - line.erase(line.find('#')); - } - else if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - // now check the line for validity - if (!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 (LibCompiler::find_word(line, opcode64x0.fName)) - { - if (!isspace(line[line.find(opcode64x0.fName) + - strlen(opcode64x0.fName)])) - { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; +std::string LibCompiler::Encoder64x0::CheckLine(std::string& line, const std::string& file) { + std::string err_str; + + if (line.empty() || LibCompiler::find_word(line, "extern_segment") || + LibCompiler::find_word(line, "public_segment") || line.find('#') != std::string::npos || + LibCompiler::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + // now check the line for validity + if (!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 (LibCompiler::find_word(line, opcode64x0.fName)) { + if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) { + err_str += "\nMissing space between "; + err_str += opcode64x0.fName; + err_str += " and operands.\nhere -> "; + err_str += line; + } + } + } + + return err_str; + } + } + + err_str += "Unrecognized instruction: " + line; + + return err_str; } -bool LibCompiler::Encoder64x0::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_hex_number"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "Assembler64x0: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "Assembler64x0: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "Assembler64x0: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::Encoder64x0::WriteNumber(const std::size_t& pos, std::string& jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { + if (errno != 0) { + Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_hex_number"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "Assembler64x0: found a base 16 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "Assembler64x0: found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "Assembler64x0: found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -776,342 +645,265 @@ bool LibCompiler::Encoder64x0::WriteNumber(const std::size_t& pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool LibCompiler::Encoder64x0::WriteLine(std::string& line, - const std::string& file) -{ - if (LibCompiler::find_word(line, "public_segment ")) - return true; - - for (auto& opcode64x0 : kOpcodes64x0) - { - // strict check here - if (LibCompiler::find_word(line, opcode64x0.fName) && - 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 == LibCompiler::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; - } - - LibCompiler::NumberCast64 num(label.second); - - for (auto& num : num.number) - { - kBytes.push_back(num); - } - - goto asm_end_label_cpy; - } - } - - if (cpy_jump_label[0] == '0') - { - switch (cpy_jump_label[1]) - { - case 'x': - case 'o': - case 'b': - if (this->WriteNumber(0, cpy_jump_label)) - goto asm_end_label_cpy; - - break; - default: - break; - } - - if (isdigit(cpy_jump_label[0])) - { - if (this->WriteNumber(0, cpy_jump_label)) - goto asm_end_label_cpy; - - break; - } - } - } - - if (cpy_jump_label.size() < 1) - { - Detail::print_error("label is empty, can't jump on it.", file); - throw std::runtime_error("label_empty"); - } - - /// don't go any further if: - /// load word (ldw) or store word. (stw) - - if (name == "ldw" || name == "stw") - break; - - auto mld_reloc_str = std::to_string(cpy_jump_label.size()); - mld_reloc_str += kUndefinedSymbol; - mld_reloc_str += cpy_jump_label; - - bool ignore_back_slash = false; - - for (auto& reloc_chr : mld_reloc_str) - { - if (reloc_chr == '\\') - { - ignore_back_slash = true; - continue; - } - - if (ignore_back_slash) - { - ignore_back_slash = false; - continue; - } - - kBytes.push_back(reloc_chr); - } - - kBytes.push_back('\0'); - goto asm_end_label_cpy; - } - - asm_end_label_cpy: - kOrigin += c64x0IPAlignment; - - break; - } - } - - return true; +bool LibCompiler::Encoder64x0::WriteLine(std::string& line, const std::string& file) { + if (LibCompiler::find_word(line, "public_segment ")) return true; + + for (auto& opcode64x0 : kOpcodes64x0) { + // strict check here + if (LibCompiler::find_word(line, opcode64x0.fName) && 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 == LibCompiler::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; + } + + LibCompiler::NumberCast64 num(label.second); + + for (auto& num : num.number) { + kBytes.push_back(num); + } + + goto asm_end_label_cpy; + } + } + + if (cpy_jump_label[0] == '0') { + switch (cpy_jump_label[1]) { + case 'x': + case 'o': + case 'b': + if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; + + break; + default: + break; + } + + if (isdigit(cpy_jump_label[0])) { + if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; + + break; + } + } + } + + if (cpy_jump_label.size() < 1) { + Detail::print_error("label is empty, can't jump on it.", file); + throw std::runtime_error("label_empty"); + } + + /// don't go any further if: + /// load word (ldw) or store word. (stw) + + if (name == "ldw" || name == "stw") break; + + auto mld_reloc_str = std::to_string(cpy_jump_label.size()); + mld_reloc_str += kUndefinedSymbol; + mld_reloc_str += cpy_jump_label; + + bool ignore_back_slash = false; + + for (auto& reloc_chr : mld_reloc_str) { + if (reloc_chr == '\\') { + ignore_back_slash = true; + continue; + } + + if (ignore_back_slash) { + ignore_back_slash = false; + continue; + } + + kBytes.push_back(reloc_chr); + } + + kBytes.push_back('\0'); + goto asm_end_label_cpy; + } + + asm_end_label_cpy: + kOrigin += c64x0IPAlignment; + + break; + } + } + + return true; } // Last rev 13-1-24 diff --git a/dev/LibCompiler/src/AssemblerAMD64.cc b/dev/LibCompiler/src/AssemblerAMD64.cc index be77ce9..a5a7ee5 100644 --- a/dev/LibCompiler/src/AssemblerAMD64.cc +++ b/dev/LibCompiler/src/AssemblerAMD64.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -24,12 +24,12 @@ #define __ASM_NEED_AMD64__ 1 #define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' +#define kAssemblerPragmaSym '#' -#include <LibCompiler/Backend/amd64.h> -#include <LibCompiler/Parser.h> #include <LibCompiler/AE.h> +#include <LibCompiler/Backend/amd64.h> #include <LibCompiler/PEF.h> +#include <LibCompiler/Parser.h> #include <algorithm> #include <cstdlib> #include <filesystem> @@ -43,25 +43,25 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) -static char kOutputArch = LibCompiler::kPefArchAMD64; +static char kOutputArch = LibCompiler::kPefArchAMD64; static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; constexpr auto kIPAlignement = 0x4U; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; /// @brief keep it simple by default. @@ -72,11 +72,11 @@ static bool kVerbose = false; static std::vector<i64_byte_t> kAppBytes; static LibCompiler::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector<LibCompiler::AERecordHeader> kRecords; -static std::vector<std::string> kDefinedSymbols; -static std::vector<std::string> kUndefinedSymbols; +static std::vector<std::string> kDefinedSymbols; +static std::vector<std::string> kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; @@ -91,289 +91,246 @@ static bool asm_read_attributes(std::string& line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainAMD64) -{ - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) - { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast<i64_hword_t>(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) - { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) - { - if (argv[i][0] == '-') - { - if (strcmp(argv[i], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) - { - kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: v1.10\nAssemblerAMD64: Copyright " - "(c) 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; - - LibCompiler::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(LibCompiler::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - LibCompiler::EncoderAMD64 asm64; - - if (kVerbose) - { - kStdOut << "Compiling: " + asm_input << "\n"; - kStdOut << "From: " + line << "\n"; - } - - while (std::getline(file_ptr, line)) - { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) - { - 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, "LibCompiler"); - } - - try - { - std::filesystem::remove(object_output); - } - catch (...) - { - } +LIBCOMPILER_MODULE(AssemblerMainAMD64) { + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = {"ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", + "jl", "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", + "jng", "jnge", "jnl", "jnle", "jno", "jnp", "jns", "jnz", + "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) { + CpuOpcodeAMD64 code{.fName = opcodes_jump[i], + .fOpcode = static_cast<i64_hword_t>(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) { + kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: " + "v1.10\nAssemblerAMD64: Copyright " + "(c) 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; - goto asm_fail_exit; - } - } + LibCompiler::AEHeader hdr{0}; - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Writing object file...\n"; - } + memset(hdr.fPad, kAENullType, kAEPad); - // this is the final step, write everything to the file. + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(LibCompiler::AEHeader); + hdr.fArch = kOutputArch; - auto pos = file_ptr_out.tellp(); + ///////////////////////////////////////////////////////////////////////////////////////// - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + // COMPILATION LOOP - 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"; + LibCompiler::EncoderAMD64 asm64; - std::filesystem::remove(object_output); - return 1; - } + if (kVerbose) { + kStdOut << "Compiling: " + asm_input << "\n"; + kStdOut << "From: " + line << "\n"; + } - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + Detail::print_error(ln, argv[i]); + continue; + } - std::size_t record_count = 0UL; + 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, "LibCompiler"); + } - for (auto& rec : kRecords) - { - if (kVerbose) - kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n"; + try { + std::filesystem::remove(object_output); + } catch (...) { + } - rec.fFlags |= LibCompiler::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; + goto asm_fail_exit; + } + } - file_ptr_out << rec; - } + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerAMD64: Writing object file...\n"; + } - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + // this is the final step, write everything to the file. - for (auto& sym : kUndefinedSymbols) - { - LibCompiler::AERecordHeader _record_hdr{0}; + auto pos = file_ptr_out.tellp(); - if (kVerbose) - kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n"; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + file_ptr_out << hdr; - ++record_count; + 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"; - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + std::filesystem::remove(object_output); + return 1; + } - file_ptr_out << _record_hdr; + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - ++kCounter; - } + std::size_t record_count = 0UL; - auto pos_end = file_ptr_out.tellp(); + for (auto& rec : kRecords) { + if (kVerbose) kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n"; - file_ptr_out.seekp(pos); + rec.fFlags |= LibCompiler::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); + file_ptr_out << rec; + } - file_ptr_out << hdr; + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Write raw binary...\n"; - } - } + for (auto& sym : kUndefinedSymbols) { + LibCompiler::AERecordHeader _record_hdr{0}; - // byte from byte, we write this. - for (auto& byte : kAppBytes) - { - if (byte == 0) - continue; + if (kVerbose) kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n"; - if (byte == 0xFF) - { - byte = 0; - } + _record_hdr.fKind = kAENullType; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; - file_ptr_out << reinterpret_cast<const char*>(&byte)[0]; - } + ++record_count; - if (kVerbose) - kStdOut << "AssemblerAMD64: Wrote file with program in it.\n"; + memset(_record_hdr.fPad, kAENullType, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - file_ptr_out.flush(); - file_ptr_out.close(); + file_ptr_out << _record_hdr; - if (kVerbose) - kStdOut << "AssemblerAMD64: Exit succeeded.\n"; + ++kCounter; + } - return 0; - } + 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"; + if (kVerbose) kStdOut << "AssemblerAMD64: Exit failed.\n"; - return 1; + return 1; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -383,185 +340,155 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string& line) -{ - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (LibCompiler::find_word(line, "extern_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid directive in flat binary mode.", "LibCompiler"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) - { - 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 = LibCompiler::kPefCode; - } - else if (name.find(kPefData64) != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(kPefZero64) != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (LibCompiler::find_word(line, "public_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid directive in flat binary mode.", "LibCompiler"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 1); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) - { - Detail::print_error("Symbol already defined.", "LibCompiler"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. +static bool asm_read_attributes(std::string& line) { + // extern_segment is the opposite of public_segment, it signals to the ld + // that we need this symbol. + if (LibCompiler::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + 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 = LibCompiler::kPefCode; + } else if (name.find(kPefData64) != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(kPefZero64) != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = LibCompiler::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. + ++kCounter; - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } + memset(kCurrentRecord.fPad, kAENullType, kAEPad); - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); + kRecords.emplace_back(kCurrentRecord); - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; + return true; + } + // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (LibCompiler::find_word(line, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_public_segment_bin"); + } - // now we can tell the code size of the previous kCurrentRecord. + auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 1); - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + std::string name_copy = name; - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + for (char& j : name) { + if (j == ' ') j = '$'; + } - ++kCounter; + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != kDefinedSymbols.end()) { + Detail::print_error("Symbol already defined.", "LibCompiler"); + throw std::runtime_error("invalid_public_segment_bin"); + } - memset(kCurrentRecord.fPad, kAENullType, kAEPad); + kDefinedSymbols.push_back(name); - kRecords.emplace_back(kCurrentRecord); + if (name.find(".code64") != std::string::npos) { + // data is treated as code. - return true; - } + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. - return false; + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = LibCompiler::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; } // \brief algorithms and helpers. -namespace 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(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_valid) == str.end(); - } -} // namespace Detail::algorithm +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(const std::string& str) { + return std::find_if(str.begin(), str.end(), is_not_valid) == str.end(); +} +} // namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -569,580 +496,458 @@ namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// -std::string LibCompiler::EncoderAMD64::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || LibCompiler::find_word(line, "extern_segment") || - LibCompiler::find_word(line, "public_segment") || - LibCompiler::find_word(line, kAssemblerPragmaSymStr) || - LibCompiler::find_word(line, ";") || line[0] == kAssemblerPragmaSym) - { - if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - // now check the line for validity - if (!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 (LibCompiler::find_word(line, opcodeAMD64.fName)) - { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; +std::string LibCompiler::EncoderAMD64::CheckLine(std::string& line, const std::string& file) { + std::string err_str; + + if (line.empty() || LibCompiler::find_word(line, "extern_segment") || + LibCompiler::find_word(line, "public_segment") || + LibCompiler::find_word(line, kAssemblerPragmaSymStr) || LibCompiler::find_word(line, ";") || + line[0] == kAssemblerPragmaSym) { + if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + // now check the line for validity + if (!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 (LibCompiler::find_word(line, opcodeAMD64.fName)) { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; } -bool LibCompiler::EncoderAMD64::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - LibCompiler::NumberCast64 num = LibCompiler::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::NumberCast64 num = LibCompiler::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::NumberCast64 num = LibCompiler::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - LibCompiler::NumberCast64 num = LibCompiler::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::EncoderAMD64::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, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + LibCompiler::NumberCast64 num = + LibCompiler::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::NumberCast64 num = + LibCompiler::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::NumberCast64 num = + LibCompiler::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + LibCompiler::NumberCast64 num = + LibCompiler::NumberCast64(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } -bool LibCompiler::EncoderAMD64::WriteNumber32(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) - { - return false; - } - - LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::EncoderAMD64::WriteNumber32(const std::size_t& pos, std::string& jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) { + return false; + } + + LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) { + return false; + } + + LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) { + return false; + } + + LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) { + return false; + } + + LibCompiler::NumberCast32 num = LibCompiler::NumberCast32(res); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } -bool LibCompiler::EncoderAMD64::WriteNumber16(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - LibCompiler::NumberCast16 num = LibCompiler::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::NumberCast16 num = LibCompiler::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::NumberCast16 num = LibCompiler::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - LibCompiler::NumberCast16 num = LibCompiler::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - if (i == 0) - i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::EncoderAMD64::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, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + LibCompiler::NumberCast16 num = + LibCompiler::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::NumberCast16 num = + LibCompiler::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::NumberCast16 num = + LibCompiler::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + LibCompiler::NumberCast16 num = + LibCompiler::NumberCast16(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) { + if (i == 0) i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } -bool LibCompiler::EncoderAMD64::WriteNumber8(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - LibCompiler::NumberCast8 num = LibCompiler::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::NumberCast8 num = LibCompiler::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::NumberCast8 num = LibCompiler::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - LibCompiler::NumberCast8 num = LibCompiler::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) - { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::EncoderAMD64::WriteNumber8(const std::size_t& pos, std::string& jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { + if (errno != 0) { + Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + LibCompiler::NumberCast8 num = + LibCompiler::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::NumberCast8 num = + LibCompiler::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::NumberCast8 num = + LibCompiler::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + LibCompiler::NumberCast8 num = + LibCompiler::NumberCast8(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) { + kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1151,331 +956,237 @@ bool LibCompiler::EncoderAMD64::WriteNumber8(const std::size_t& pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool LibCompiler::EncoderAMD64::WriteLine(std::string& line, - const std::string& file) -{ - if (LibCompiler::find_word(line, "public_segment ")) - return true; - - struct RegMapAMD64 - { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector<RegMapAMD64> kRegisterList{ - {.fName = "ax", .fModRM = 0x0}, - {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, - {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, - {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, - {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, - {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, - {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, - {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto& opcodeAMD64 : kOpcodesAMD64) - { - // strict check here - if (LibCompiler::find_word(line, opcodeAMD64.fName) && - Detail::algorithm::is_valid_amd64(line)) - { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (line.find(name) != std::string::npos && - name == "mov") - { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) - { - Detail::print_error("Syntax error: missing right operand.", "LibCompiler"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector<RegMapAMD64> currentRegList; - - for (auto& reg : kRegisterList) - { - std::vector<char> regExt = {'e', 'r'}; - - for (auto& ext : regExt) - { - std::string registerName; - - if (bits > 16) - registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) - { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) - { - if (registerName[0] == 'r') - { - Detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) - onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) - { - /// very tricky to understand. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') - { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } - else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) - { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) - { - if (!hasRBasedRegs && bits >= 32) - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - if (!onlyOneReg) - kAppBytes.emplace_back(0x89); - } - else if (bits == 16) - { - if (hasRBasedRegs) - { - Detail::print_error( - "Invalid combination of operands and registers.", "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - else - { - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - } - - if (onlyOneReg) - { - auto num = GetNumber32(line, ","); - - for (auto& num_idx : num.number) - { - if (num_idx == 0) - num_idx = 0xFF; - } - - auto modrm = (0x3 << 6 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number. - kAppBytes.emplace_back(modrm); - kAppBytes.emplace_back(num.number[0]); - kAppBytes.emplace_back(num.number[1]); - kAppBytes.emplace_back(num.number[2]); - kAppBytes.emplace_back(num.number[3]); - - break; - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) - { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - } - else - { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') - { - Detail::print_error("Invalid combination of operands and registers.", - "LibCompiler"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } - else if (name == "int" || name == "into" || name == "intd") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } - else if (name == "jmp" || name == "call") - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) - { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } - else - { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) - { - if (foundInstruction) - { - Detail::print_error("Syntax error: " + line, "LibCompiler"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) - { - kRegisterBitWidth = 64U; - } - else if (line.find("bits 32") != std::string::npos) - { - kRegisterBitWidth = 32U; - } - else if (line.find("bits 16") != std::string::npos) - { - kRegisterBitWidth = 16U; - } - else if (line.find("org") != std::string::npos) - { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) - { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) - { - if (errno != 0) - { - continue; - } - else - { - if (kVerbose) - { - kStdOut << "AssemblerAMD64: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) - { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) - { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) - { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += kIPAlignement; - - return true; +bool LibCompiler::EncoderAMD64::WriteLine(std::string& line, const std::string& file) { + if (LibCompiler::find_word(line, "public_segment ")) return true; + + struct RegMapAMD64 { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector<RegMapAMD64> kRegisterList{ + {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) { + // strict check here + if (LibCompiler::find_word(line, opcodeAMD64.fName) && + Detail::algorithm::is_valid_amd64(line)) { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (line.find(name) != std::string::npos && name == "mov") { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) { + Detail::print_error("Syntax error: missing right operand.", "LibCompiler"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector<RegMapAMD64> currentRegList; + + for (auto& reg : kRegisterList) { + std::vector<char> regExt = {'e', 'r'}; + + for (auto& ext : regExt) { + std::string registerName; + + if (bits > 16) registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) { + if (registerName[0] == 'r') { + Detail::print_error("invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back({.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || currentRegList[1].fName[0] == 'r') { + if (isdigit(currentRegList[0].fName[1]) && isdigit(currentRegList[1].fName[1])) { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } else if (isdigit(currentRegList[0].fName[1]) || isdigit(currentRegList[1].fName[1])) { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) { + if (!hasRBasedRegs && bits >= 32) { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + if (!onlyOneReg) kAppBytes.emplace_back(0x89); + } else if (bits == 16) { + if (hasRBasedRegs) { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } else { + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + } + + if (onlyOneReg) { + auto num = GetNumber32(line, ","); + + for (auto& num_idx : num.number) { + if (num_idx == 0) num_idx = 0xFF; + } + + auto modrm = (0x3 << 6 | currentRegList[0].fModRM); + + kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number. + kAppBytes.emplace_back(modrm); + kAppBytes.emplace_back(num.number[0]); + kAppBytes.emplace_back(num.number[1]); + kAppBytes.emplace_back(num.number[2]); + kAppBytes.emplace_back(num.number[3]); + + break; + } + + if (currentRegList[1].fName[0] == 'r' && currentRegList[0].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && currentRegList[1].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) { + if (currentRegList[0].fName[0] == 'r' || currentRegList[0].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || currentRegList[1].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + } else { + if (currentRegList[0].fName[0] != 'r' || currentRegList[0].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || currentRegList[1].fName[0] == 'e') { + Detail::print_error("Invalid combination of operands and registers.", "LibCompiler"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } else if (name == "int" || name == "into" || name == "intd") { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } else if (name == "jmp" || name == "call") { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } else { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) { + if (foundInstruction) { + Detail::print_error("Syntax error: " + line, "LibCompiler"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) { + kRegisterBitWidth = 64U; + } else if (line.find("bits 32") != std::string::npos) { + kRegisterBitWidth = 32U; + } else if (line.find("bits 16") != std::string::npos) { + kRegisterBitWidth = 16U; + } else if (line.find("org") != std::string::npos) { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) { + if (kOrigin = strtol((line.substr(line.find("org") + strlen("org") + 1)).c_str(), nullptr, + base[i]); + kOrigin) { + if (errno != 0) { + continue; + } else { + if (kVerbose) { + kStdOut << "AssemblerAMD64: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += kIPAlignement; + + return true; } // Last rev 13-1-24 diff --git a/dev/LibCompiler/src/AssemblerARM64.cc b/dev/LibCompiler/src/AssemblerARM64.cc index 52b78d6..d984845 100644 --- a/dev/LibCompiler/src/AssemblerARM64.cc +++ b/dev/LibCompiler/src/AssemblerARM64.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -17,16 +17,16 @@ #define __ASM_NEED_ARM64__ 1 -#include <LibCompiler/ErrorID.h> +#include <LibCompiler/AE.h> #include <LibCompiler/Backend/arm64.h> +#include <LibCompiler/ErrorID.h> #include <LibCompiler/PEF.h> #include <LibCompiler/Parser.h> -#include <LibCompiler/AE.h> #include <LibCompiler/Version.h> -#include <filesystem> #include <algorithm> -#include <iostream> +#include <filesystem> #include <fstream> +#include <iostream> #include <vector> ///////////////////// @@ -35,9 +35,9 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) @@ -45,15 +45,15 @@ constexpr auto cPowerIPAlignment = 0x4U; -static CharType kOutputArch = LibCompiler::kPefArchARM64; -static Boolean kOutputAsBinary = false; +static CharType kOutputArch = LibCompiler::kPefArchARM64; +static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; static bool kVerbose = false; @@ -61,13 +61,13 @@ static bool kVerbose = false; static std::vector<uint8_t> kBytes; static LibCompiler::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector<LibCompiler::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; +static std::vector<std::string> kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; // \brief forward decl. static bool asm_read_attributes(std::string& line); @@ -81,225 +81,191 @@ static bool asm_read_attributes(std::string& line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainARM64) -{ - 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; - - LibCompiler::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(LibCompiler::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - LibCompiler::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, "LibCompiler"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "AssemblerARM64: Writing object file...\n"; - } +LIBCOMPILER_MODULE(AssemblerMainARM64) { + 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; + + LibCompiler::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(LibCompiler::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + LibCompiler::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, "LibCompiler"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } - // this is the final step, write everything to the file. + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerARM64: Writing object file...\n"; + } - auto pos = file_ptr_out.tellp(); + // this is the final step, write everything to the file. - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + auto pos = file_ptr_out.tellp(); - file_ptr_out << hdr; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - 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"; + file_ptr_out << hdr; - std::filesystem::remove(object_output); - return 1; - } + 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"; - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + std::filesystem::remove(object_output); + return 1; + } - std::size_t record_count = 0UL; + kRecords[kRecords.size() - 1].fSize = kBytes.size(); - for (auto& record_hdr : kRecords) - { - record_hdr.fFlags |= LibCompiler::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; + std::size_t record_count = 0UL; - file_ptr_out << record_hdr; + for (auto& record_hdr : kRecords) { + record_hdr.fFlags |= LibCompiler::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; + ++record_count; - if (kVerbose) - kStdOut << "AssemblerARM64: Wrote record " << record_hdr.fName << "...\n"; - } + file_ptr_out << record_hdr; - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + if (kVerbose) kStdOut << "AssemblerARM64: Wrote record " << record_hdr.fName << "...\n"; + } - for (auto& sym : kUndefinedSymbols) - { - LibCompiler::AERecordHeader undefined_sym{0}; + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - if (kVerbose) - kStdOut << "AssemblerARM64: Wrote symbol " << sym << " to file...\n"; + for (auto& sym : kUndefinedSymbols) { + LibCompiler::AERecordHeader undefined_sym{0}; - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; + if (kVerbose) kStdOut << "AssemblerARM64: Wrote symbol " << sym << " to file...\n"; - ++record_count; + undefined_sym.fKind = kAENullType; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); + ++record_count; - file_ptr_out << undefined_sym; + memset(undefined_sym.fPad, kAENullType, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - ++kCounter; - } + file_ptr_out << undefined_sym; - auto pos_end = file_ptr_out.tellp(); + ++kCounter; + } - file_ptr_out.seekp(pos); + auto pos_end = file_ptr_out.tellp(); - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); + file_ptr_out.seekp(pos); - file_ptr_out << hdr; + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "AssemblerARM64: Write raw binary...\n"; - } - } + file_ptr_out << hdr; - // byte from byte, we write this. - for (auto& byte : kBytes) - { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "AssemblerARM64: Write raw binary...\n"; + } + } - if (kVerbose) - kStdOut << "AssemblerARM64: Wrote file with program in it.\n"; + // byte from byte, we write this. + for (auto& byte : kBytes) { + file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); + } - file_ptr_out.flush(); - file_ptr_out.close(); + if (kVerbose) kStdOut << "AssemblerARM64: Wrote file with program in it.\n"; - if (kVerbose) - kStdOut << "AssemblerARM64: Exit succeeded.\n"; + file_ptr_out.flush(); + file_ptr_out.close(); - return 0; - } + if (kVerbose) kStdOut << "AssemblerARM64: Exit succeeded.\n"; + + return 0; + } asm_fail_exit: - if (kVerbose) - kStdOut << "AssemblerARM64: Exit failed.\n"; + if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n"; - return LIBCOMPILER_EXEC_ERROR; + return LIBCOMPILER_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -309,175 +275,144 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string& line) -{ - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (LibCompiler::find_word(line, "extern_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) - { - Detail::print_error("Invalid extern_segment", "LibCompiler"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) - { - if (j == ' ' || j == ',') - j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (LibCompiler::find_word(line, "public_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid public_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. +static bool asm_read_attributes(std::string& line) { + // extern_segment is the opposite of public_segment, it signals to the li + // that we need this symbol. + if (LibCompiler::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = LibCompiler::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. + kRecords.emplace_back(kCurrentRecord); - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); + 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 (LibCompiler::find_word(line, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_public_segment_bin"); + } - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - // now we can tell the code size of the previous kCurrentRecord. + std::string name_copy = name; - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + for (char& j : name) { + if (j == ' ') j = '$'; + } - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + if (name.find(".code64") != std::string::npos) { + // data is treated as code. - ++kCounter; + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. - memset(kCurrentRecord.fPad, kAENullType, kAEPad); + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. - kRecords.emplace_back(kCurrentRecord); + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = LibCompiler::kPefZero; + } - return true; - } + // this is a special case for the start stub. + // we want this so that li can find it. - return false; + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; } // \brief algorithms and helpers. -namespace 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(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); - } -} // namespace Detail::algorithm +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(const std::string& str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -485,209 +420,161 @@ namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// -std::string LibCompiler::EncoderARM64::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || LibCompiler::find_word(line, "extern_segment") || - LibCompiler::find_word(line, "public_segment") || - line.find('#') != std::string::npos || LibCompiler::find_word(line, ";")) - { - if (line.find('#') != std::string::npos) - { - line.erase(line.find('#')); - } - else if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - /// does the line contains valid input? - if (!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; +std::string LibCompiler::EncoderARM64::CheckLine(std::string& line, const std::string& file) { + std::string err_str; + + if (line.empty() || LibCompiler::find_word(line, "extern_segment") || + LibCompiler::find_word(line, "public_segment") || line.find('#') != std::string::npos || + LibCompiler::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + /// does the line contains valid input? + if (!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 LibCompiler::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, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "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, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::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, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::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; - } - } - - LibCompiler::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; +bool LibCompiler::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, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "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, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::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, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::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; + } + } + + LibCompiler::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; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -696,16 +583,12 @@ bool LibCompiler::EncoderARM64::WriteNumber(const std::size_t& pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool LibCompiler::EncoderARM64::WriteLine(std::string& line, - const std::string& file) -{ - if (LibCompiler::find_word(line, "public_segment")) - return false; +bool LibCompiler::EncoderARM64::WriteLine(std::string& line, const std::string& file) { + if (LibCompiler::find_word(line, "public_segment")) return false; - if (!Detail::algorithm::is_valid_arm64(line)) - return false; + if (!Detail::algorithm::is_valid_arm64(line)) return false; - return true; + return true; } // Last rev 13-1-24 diff --git a/dev/LibCompiler/src/AssemblerPower.cc b/dev/LibCompiler/src/AssemblerPower.cc index 59f7ed6..30b6d68 100644 --- a/dev/LibCompiler/src/AssemblerPower.cc +++ b/dev/LibCompiler/src/AssemblerPower.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -17,16 +17,16 @@ #define __ASM_NEED_PPC__ 1 -#include <LibCompiler/ErrorID.h> +#include <LibCompiler/AE.h> #include <LibCompiler/Backend/power64.h> +#include <LibCompiler/ErrorID.h> #include <LibCompiler/PEF.h> #include <LibCompiler/Parser.h> -#include <LibCompiler/AE.h> #include <LibCompiler/Version.h> -#include <filesystem> #include <algorithm> -#include <iostream> +#include <filesystem> #include <fstream> +#include <iostream> #include <vector> ///////////////////// @@ -35,9 +35,9 @@ ///////////////////// -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" #define kYellow "\e[0;33m" #define kStdOut (std::cout << kWhite) @@ -45,15 +45,15 @@ constexpr auto cPowerIPAlignment = 0x4U; -static CharType kOutputArch = LibCompiler::kPefArchPowerPC; -static Boolean kOutputAsBinary = false; +static CharType kOutputArch = LibCompiler::kPefArchPowerPC; +static Boolean kOutputAsBinary = false; -static UInt32 kErrorLimit = 10; +static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; static std::size_t kCounter = 1UL; -static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::uintptr_t kOrigin = kPefBaseOrigin; static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; static bool kVerbose = false; @@ -61,13 +61,13 @@ static bool kVerbose = false; static std::vector<uint8_t> kBytes; static LibCompiler::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; + .fName = "", .fKind = LibCompiler::kPefCode, .fSize = 0, .fOffset = 0}; static std::vector<LibCompiler::AERecordHeader> kRecords; -static std::vector<std::string> kUndefinedSymbols; +static std::vector<std::string> kUndefinedSymbols; static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; // \brief forward decl. static bool asm_read_attributes(std::string& line); @@ -81,225 +81,191 @@ static bool asm_read_attributes(std::string& line); ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(AssemblerMainPower64) -{ - for (size_t i = 1; i < argc; ++i) - { - if (argv[i][0] == '-') - { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) - { - kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion << "\nAssemblerPower: " - "Copyright (c) " - "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; - - LibCompiler::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(LibCompiler::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - LibCompiler::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) - { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) - { - 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, "LibCompiler"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) - { - if (kVerbose) - { - kStdOut << "AssemblerPower: Writing object file...\n"; - } +LIBCOMPILER_MODULE(AssemblerMainPower64) { + for (size_t i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { + kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion + << "\nAssemblerPower: " + "Copyright (c) " + "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; + + LibCompiler::AEHeader hdr{0}; + + memset(hdr.fPad, kAENullType, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(LibCompiler::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + LibCompiler::EncoderPowerPC asm64; + + while (std::getline(file_ptr, line)) { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { + 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, "LibCompiler"); + } + + std::filesystem::remove(object_output); + goto asm_fail_exit; + } + } - // this is the final step, write everything to the file. + if (!kOutputAsBinary) { + if (kVerbose) { + kStdOut << "AssemblerPower: Writing object file...\n"; + } - auto pos = file_ptr_out.tellp(); + // this is the final step, write everything to the file. - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + auto pos = file_ptr_out.tellp(); - file_ptr_out << hdr; + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - 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"; + file_ptr_out << hdr; - std::filesystem::remove(object_output); - return 1; - } + 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"; - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + std::filesystem::remove(object_output); + return 1; + } - std::size_t record_count = 0UL; + kRecords[kRecords.size() - 1].fSize = kBytes.size(); - for (auto& record_hdr : kRecords) - { - record_hdr.fFlags |= LibCompiler::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; + std::size_t record_count = 0UL; - file_ptr_out << record_hdr; + for (auto& record_hdr : kRecords) { + record_hdr.fFlags |= LibCompiler::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; + ++record_count; - if (kVerbose) - kStdOut << "AssemblerPower: Wrote record " << record_hdr.fName << "...\n"; - } + file_ptr_out << record_hdr; - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; + if (kVerbose) kStdOut << "AssemblerPower: Wrote record " << record_hdr.fName << "...\n"; + } - for (auto& sym : kUndefinedSymbols) - { - LibCompiler::AERecordHeader undefined_sym{0}; + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; - if (kVerbose) - kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n"; + for (auto& sym : kUndefinedSymbols) { + LibCompiler::AERecordHeader undefined_sym{0}; - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; + if (kVerbose) kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n"; - ++record_count; + undefined_sym.fKind = kAENullType; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); + ++record_count; - file_ptr_out << undefined_sym; + memset(undefined_sym.fPad, kAENullType, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - ++kCounter; - } + file_ptr_out << undefined_sym; - auto pos_end = file_ptr_out.tellp(); + ++kCounter; + } - file_ptr_out.seekp(pos); + auto pos_end = file_ptr_out.tellp(); - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); + file_ptr_out.seekp(pos); - file_ptr_out << hdr; + hdr.fStartCode = pos_end; + hdr.fCodeSize = kBytes.size(); - file_ptr_out.seekp(pos_end); - } - else - { - if (kVerbose) - { - kStdOut << "AssemblerPower: Write raw binary...\n"; - } - } + file_ptr_out << hdr; - // byte from byte, we write this. - for (auto& byte : kBytes) - { - file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); - } + file_ptr_out.seekp(pos_end); + } else { + if (kVerbose) { + kStdOut << "AssemblerPower: Write raw binary...\n"; + } + } - if (kVerbose) - kStdOut << "AssemblerPower: Wrote file with program in it.\n"; + // byte from byte, we write this. + for (auto& byte : kBytes) { + file_ptr_out.write(reinterpret_cast<const char*>(&byte), sizeof(byte)); + } - file_ptr_out.flush(); - file_ptr_out.close(); + if (kVerbose) kStdOut << "AssemblerPower: Wrote file with program in it.\n"; - if (kVerbose) - kStdOut << "AssemblerPower: Exit succeeded.\n"; + file_ptr_out.flush(); + file_ptr_out.close(); - return 0; - } + if (kVerbose) kStdOut << "AssemblerPower: Exit succeeded.\n"; + + return 0; + } asm_fail_exit: - if (kVerbose) - kStdOut << "AssemblerPower: Exit failed.\n"; + if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n"; - return LIBCOMPILER_EXEC_ERROR; + return LIBCOMPILER_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -309,175 +275,144 @@ asm_fail_exit: ///////////////////////////////////////////////////////////////////////////////////////// -static bool asm_read_attributes(std::string& line) -{ - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (LibCompiler::find_word(line, "extern_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) - { - Detail::print_error("Invalid extern_segment", "LibCompiler"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) - { - if (j == ' ' || j == ',') - j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (LibCompiler::find_word(line, "public_segment")) - { - if (kOutputAsBinary) - { - Detail::print_error("Invalid public_segment directive in flat binary mode.", - "LibCompiler"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) - { - if (j == ' ') - j = '$'; - } - - if (name.find(".code64") != std::string::npos) - { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - else if (name.find(".data64") != std::string::npos) - { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = LibCompiler::kPefData; - } - else if (name.find(".zero64") != std::string::npos) - { - // this is a bss section. +static bool asm_read_attributes(std::string& line) { + // extern_segment is the opposite of public_segment, it signals to the li + // that we need this symbol. + if (LibCompiler::find_word(line, "extern_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid extern_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment_bin"); + } + + auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); + + if (name.size() == 0) { + Detail::print_error("Invalid extern_segment", "LibCompiler"); + throw std::runtime_error("invalid_extern_segment"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) { + if (j == ' ' || j == ',') j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) { + // data is treated as code. + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. + kCurrentRecord.fKind = LibCompiler::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that li can find it. + + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = LibCompiler::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. + kRecords.emplace_back(kCurrentRecord); - if (name == kPefStart) - { - kCurrentRecord.fKind = LibCompiler::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); + return true; + } + // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64., + // .zero64 + else if (LibCompiler::find_word(line, "public_segment")) { + if (kOutputAsBinary) { + Detail::print_error("Invalid public_segment directive in flat binary mode.", "LibCompiler"); + throw std::runtime_error("invalid_public_segment_bin"); + } - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; + auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - // now we can tell the code size of the previous kCurrentRecord. + std::string name_copy = name; - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kBytes.size(); + for (char& j : name) { + if (j == ' ') j = '$'; + } - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + if (name.find(".code64") != std::string::npos) { + // data is treated as code. - ++kCounter; + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = LibCompiler::kPefCode; + } else if (name.find(".data64") != std::string::npos) { + // no code will be executed from here. - memset(kCurrentRecord.fPad, kAENullType, kAEPad); + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = LibCompiler::kPefData; + } else if (name.find(".zero64") != std::string::npos) { + // this is a bss section. - kRecords.emplace_back(kCurrentRecord); + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = LibCompiler::kPefZero; + } - return true; - } + // this is a special case for the start stub. + // we want this so that li can find it. - return false; + if (name == kPefStart) { + kCurrentRecord.fKind = LibCompiler::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAENullType, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; } // \brief algorithms and helpers. -namespace 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(const std::string& str) - { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); - } -} // namespace Detail::algorithm +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(const std::string& str) { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); +} +} // namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// @@ -485,255 +420,198 @@ namespace Detail::algorithm ///////////////////////////////////////////////////////////////////////////////////////// -std::string LibCompiler::EncoderPowerPC::CheckLine(std::string& line, - const std::string& file) -{ - std::string err_str; - - if (line.empty() || LibCompiler::find_word(line, "extern_segment") || - LibCompiler::find_word(line, "public_segment") || - line.find('#') != std::string::npos || LibCompiler::find_word(line, ";")) - { - if (line.find('#') != std::string::npos) - { - line.erase(line.find('#')); - } - else if (line.find(';') != std::string::npos) - { - line.erase(line.find(';')); - } - else - { - /// does the line contains valid input? - if (!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 (LibCompiler::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 (LibCompiler::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; +std::string LibCompiler::EncoderPowerPC::CheckLine(std::string& line, const std::string& file) { + std::string err_str; + + if (line.empty() || LibCompiler::find_word(line, "extern_segment") || + LibCompiler::find_word(line, "public_segment") || line.find('#') != std::string::npos || + LibCompiler::find_word(line, ";")) { + if (line.find('#') != std::string::npos) { + line.erase(line.find('#')); + } else if (line.find(';') != std::string::npos) { + line.erase(line.find(';')); + } else { + /// does the line contains valid input? + if (!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 (LibCompiler::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 (LibCompiler::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 LibCompiler::EncoderPowerPC::WriteNumber(const std::size_t& pos, - std::string& jump_label) -{ - if (!isdigit(jump_label[pos])) - return false; - - switch (jump_label[pos + 1]) - { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerPower: found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "AssemblerPower: found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "AssemblerPower: found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - return false; - } - } - - LibCompiler::NumberCast64 num( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) - { - kBytes.push_back(i); - } - - if (kVerbose) - { - kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; +bool LibCompiler::EncoderPowerPC::WriteNumber(const std::size_t& pos, std::string& jump_label) { + if (!isdigit(jump_label[pos])) return false; + + switch (jump_label[pos + 1]) { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { + if (errno != 0) { + Detail::print_error("invalid hex number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerPower: found a base 16 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "AssemblerPower: found a base 2 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + kBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + jump_label, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "AssemblerPower: found a base 8 number here: " << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) { + kBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + return false; + } + } + + LibCompiler::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) { + kBytes.push_back(i); + } + + if (kVerbose) { + kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos) << "\n"; + } + + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -742,355 +620,299 @@ bool LibCompiler::EncoderPowerPC::WriteNumber(const std::size_t& pos, ///////////////////////////////////////////////////////////////////////////////////////// -bool LibCompiler::EncoderPowerPC::WriteLine(std::string& line, - const std::string& file) -{ - if (LibCompiler::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 (LibCompiler::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; +bool LibCompiler::EncoderPowerPC::WriteLine(std::string& line, const std::string& file) { + if (LibCompiler::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 (LibCompiler::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/LibCompiler/src/AssemblyFactory.cc b/dev/LibCompiler/src/AssemblyFactory.cc index e70f279..4695c63 100644 --- a/dev/LibCompiler/src/AssemblyFactory.cc +++ b/dev/LibCompiler/src/AssemblyFactory.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -23,37 +23,29 @@ //! @file Asm.cpp //! @brief AssemblyKit source implementation. -namespace LibCompiler -{ - ///! @brief Compile for specific format (ELF, PEF, ZBIN) - Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept - { - if (sourceFile.length() < 1 || !fMounted) - return LIBCOMPILER_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); - } - - ///! @brief mount assembly backend. - void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept - { - if (mountPtr) - { - fMounted = mountPtr; - } - } - - ///! @brief Unmount assembler. - AssemblyInterface* AssemblyFactory::Unmount() noexcept - { - auto mount_prev = fMounted; - - if (mount_prev) - { - fMounted = nullptr; - } - - return mount_prev; - } -} // namespace LibCompiler +namespace LibCompiler { +///! @brief Compile for specific format (ELF, PEF, ZBIN) +Int32 AssemblyFactory::Compile(std::string& sourceFile, const Int32& arch) noexcept { + if (sourceFile.length() < 1 || !fMounted) return LIBCOMPILER_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); +} + +///! @brief mount assembly backend. +void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { + if (mountPtr) { + fMounted = mountPtr; + } +} + +///! @brief Unmount assembler. +AssemblyInterface* AssemblyFactory::Unmount() noexcept { + auto mount_prev = fMounted; + + if (mount_prev) { + fMounted = nullptr; + } + + return mount_prev; +} +} // namespace LibCompiler diff --git a/dev/LibCompiler/src/CCompiler64x0.cc b/dev/LibCompiler/src/CCompiler64x0.cc index 89fc682..dea3ebd 100644 --- a/dev/LibCompiler/src/CCompiler64x0.cc +++ b/dev/LibCompiler/src/CCompiler64x0.cc @@ -41,7 +41,7 @@ #define kExitOK (0) #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -50,63 +50,57 @@ ///////////////////////////////////// -namespace Detail -{ - // \brief Register map structure, used to keep track of each variable's registers. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; - }; - - struct CompilerState final - { - std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace Detail +namespace Detail { +// \brief Register map structure, used to keep track of each variable's registers. +struct CompilerRegisterMap final { + std::string fName; + std::string fReg; +}; + +// \brief Map for C structs +// \author amlel +struct CompilerStructMap final { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector<std::pair<Int32, std::string>> fOffsets; +}; + +struct CompilerState final { + std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; +}; +} // namespace Detail static Detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace Detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept; - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace Detail +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace Detail { +/// @brief prints an error into stdout. +/// @param reason the reason of the error. +/// @param file where does it originate from? +void print_error(std::string reason, std::string file) noexcept; + +struct CompilerType final { + std::string fName; + std::string fValue; +}; +} // namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -119,11 +113,11 @@ static int kMachine = 0; ///////////////////////////////////////// -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; +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; ///////////////////////////////////////// @@ -131,67 +125,56 @@ static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// -static std::vector<std::string> kFileList; +static std::vector<std::string> kFileList; static LibCompiler::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerFrontend64x0 final : public LibCompiler::ICompilerFrontend -{ -public: - explicit CompilerFrontend64x0() = default; - ~CompilerFrontend64x0() override = default; +class CompilerFrontend64x0 final : public LibCompiler::ICompilerFrontend { + public: + explicit CompilerFrontend64x0() = default; + ~CompilerFrontend64x0() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontend64x0); + LIBCOMPILER_COPY_DEFAULT(CompilerFrontend64x0); - std::string Check(const char* text, const char* file); - bool Compile(std::string text, const std::string file) override; + std::string Check(const char* text, const char* file); + bool Compile(std::string text, const std::string file) override; - const char* Language() override - { - return "64k C"; - } + const char* Language() override { return "64k C"; } }; -static CompilerFrontend64x0* kCompilerFrontend = nullptr; +static CompilerFrontend64x0* kCompilerFrontend = nullptr; static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; +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 +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 ///////////////////////////////////////////////////////////////////////////////////////// @@ -200,1090 +183,858 @@ namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerFrontend64x0::Compile(std::string text_, const 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 = LibCompiler::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 += ' '; +bool CompilerFrontend64x0::Compile(std::string text_, const 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + Detail::number_cast time_off = (UInt64) out.as_bytes().data(); + + if (!typeFound) { + auto substr = text.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) { + if (substr[y] == ' ') { + while (match_type.find(' ') != std::string::npos) { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) { + if (clType.fName == match_type) { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) { + break; + } + + if (text.find('(') != std::string::npos) { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (text[text_index] == 'r') { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) { + if (!value.empty()) { + if (value.find('(') != std::string::npos) { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " extern_segment"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); + + kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; + syntaxLeaf.fUserValue += kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword public_segment .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value in struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + if (ch == ' ') { + space_found_ = true; + } + + if (ch == ';') break; + + if (space_found_) sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } else { + substr += "\tldw "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; + + if (text[text_index_2] == ';') { + break; + } + + if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { + if (first_encountered != 2) { + if (text[text_index] != '=' && + substr.find("public_segment .data64") == std::string::npos && !kInStruct) + substr += "public_segment .data64 "; + } + + ++first_encountered; + + continue; + } - if (substr.find('=') != std::string::npos) - { - break; - } + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } - if (text.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; + substr += ","; + continue; + } - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } + substr += text[text_index_2]; + } - typeFound = true; - break; - } - } + for (auto& clType : kCompilerTypes) { + if (substr.find(clType.fName) != std::string::npos) { + if (substr.find(clType.fName) > substr.find('"')) continue; - break; - } + 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; - match_type += substr[y]; - } - } + if (clType.fName == "const") continue; - if (text[text_index] == '{') - { - if (kInStruct) - { - continue; - } + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } - kInBraces = true; - ++kBracesCount; + if (substr.find("extern") != std::string::npos) { + substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); - ++return_index) - { - if (text[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < text.size(); ++value_index) - { - if (text[value_index] == ';') - break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') - { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__LIBCOMPILER_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (text[text_index] == ';' && kInStruct) - continue; - - if (text.find("typedef ") != std::string::npos) - continue; - - if (text[text_index] == '=' && kInStruct) - { - Detail::print_error("assignement of value in struct " + text, - file); - continue; - } - - if (text[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) - { - continue; - } - - if (text[text_index + 1] == '=' || - text[text_index - 1] == '!' || - text[text_index - 1] == '<' || - text[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (text.find("*") != std::string::npos) - { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } - else - { - substr += "\tldw "; - } - } - else if (text.find('=') != std::string::npos && !kInBraces) - { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); - ++text_index_2) - { - if (text[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) - { - if (text[text_index_2] == '\"') - break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') - continue; - - if (text[text_index_2] == ';') - { - break; - } - - if (text[text_index_2] == ' ' || - text[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && - !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("public_segment .data64"), - strlen("public_segment .data64"), "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) - { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') - break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); - ++idx) - { - if (text[idx] == ',') - continue; - - if (text[idx] == ' ') - continue; - - if (text[idx] == ')') - break; - } - - for (char substr_first_index : text) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); + if (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); + } - if (!args_buffer.empty()) - args += "\tldw r6, "; + auto var_to_find = std::find_if( + kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - std::string register_type; - std::size_t index = 7UL; + if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); - ++index; + if (var_to_find == kCompilerVariables.cend()) { + ++kRegisterCounter; - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } - args += args_buffer; - args += "\n\tlda r19, "; - } - } + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - for (char _text_i : text) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } + if (text[text_index] == '=') break; + } - continue; - } + // function handler. - if (_text_i == '(') - break; + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; - substr += _text_i; - } + bool type_crossed = false; - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + if (text[idx] == ' ') continue; - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); + if (text[idx] == ')') break; + } - syntaxLeaf.fUserValue += "public_segment .code64 "; + for (char substr_first_index : text) { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; + 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); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + if (!args_buffer.empty()) args += "\tldw r6, "; - fnFound = true; - } + std::string register_type; + std::size_t index = 7UL; - kCompilerFunctions.push_back(text); - } + while (args_buffer.find("$") != std::string::npos) { + register_type = kRegisterPrefix; + register_type += std::to_string(index); - if (text[text_index] == '-' && text[text_index + 1] == '-') - { - text = text.replace(text.find("--"), strlen("--"), ""); + ++index; - for (int _text_i = 0; _text_i < text.size(); ++_text_i) - { - if (text[_text_i] == '\t' || text[_text_i] == ' ') - text.erase(_text_i, 1); - } + args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); + } - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; + args += args_buffer; + args += "\n\tlda r19, "; + } + } - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } + for (char _text_i : text) { + if (_text_i == '\t' || _text_i == ' ') { + if (!type_crossed) { + substr.clear(); + type_crossed = true; + } - if (text[text_index] == '}') - { - kRegisterCounter = kStartUsable; + continue; + } - --kBracesCount; + if (_text_i == '(') break; - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } + substr += _text_i; + } - if (kIfFound) - kIfFound = false; + if (kInBraces) { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; - if (kInStruct) - kInStruct = false; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } + fnFound = true; + } else { + syntaxLeaf.fUserValue.clear(); - syntaxLeaf.fUserValue.clear(); - } + syntaxLeaf.fUserValue += "public_segment .code64 "; - auto syntaxLeaf = LibCompiler::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; - return true; + 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; } -static bool kShouldHaveBraces = false; +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; - } +std::string CompilerFrontend64x0::Check(const char* text, const char* file) { + std::string err_str; + std::string ln = text; + + if (ln.empty()) { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) { + if (isalnum(ln[i])) { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == '\'') { + if (ln[string_index + 1] != ';') { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } else if (ln.find('"') != std::string::npos) { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == '"') { + if (ln[string_index + 1] != ';') { + ln.erase(string_index, 1); + } else { + break; + } + } + } + } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { + std::vector<std::string> forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("--*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) { + if (ln.find(forbidden) != std::string::npos) { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final { + std::string fBegin; + std::string fEnd; + }; + + const std::vector<CompilerVariableRange> variables_list = { + {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) { + if (ln.find(variable.fBegin) != std::string::npos) { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == variable.fEnd[0]) { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; + ++index_keyword) { + if (ln[index_keyword] == ' ') { + continue; + } + + if (isdigit(ln[index_keyword])) { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) { + if (var.fValue.find(keyword) != std::string::npos) { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) { + if (fn.find(keyword[0]) != std::string::npos) { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; + + if (fn[where_begin] != keyword[keyword_begin]) { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) { + err_str.clear(); + goto cc_next; + } else { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) return err_str; + + if (keyword.find(".") != std::string::npos) return err_str; + + if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } cc_next: - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (LibCompiler::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } + // extern does not declare anything, it extern_segments a variable. + // so that's why it's not declare upper. + if (LibCompiler::find_word(ln, "extern")) { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) { + if (ln[i] == '\"') { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { + if (ln.find('{') == std::string::npos) { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } else if (ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + } + } skip_braces_check: - for (auto& key : kCompilerTypes) - { - if (LibCompiler::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && - !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && - !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; + for (auto& key : kCompilerTypes) { + if (LibCompiler::find_word(ln, key.fName)) { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; + + goto next; + } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find('=') == std::string::npos) continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } else { + continue; + } + + if (ln.find('=') != std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) { + if (ln.find(';') == std::string::npos) { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { + if (ln.find(';') + 1 != ln.size()) { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) { + if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && + !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && + !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) { + bool found_func = false; + size_t i = ln.find('('); + std::vector<char> opens; + std::vector<char> closes; + + for (; i < ln.size(); ++i) { + if (ln[i] == ')') { + closes.push_back(1); + } + + if (ln[i] == '(') { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) { + if (ln[i] == ')' && !space_found) { + space_found = true; + continue; + } + + if (space_found) { + if (ln[i] == ' ' && isalnum(ln[i + 1])) { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } else { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } else { + if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) { + if (!kInStruct && ln.find(';') == std::string::npos) { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) { + if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { + if (ln.size() <= 2) return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1294,186 +1045,144 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCCInterface final ASSEMBLY_INTERFACE -{ -public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return LibCompiler::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCCInterface::Arch()) - return 1; - - if (kCompilerFrontend == nullptr) - return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = LibCompiler::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - LibCompiler::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerFrontend->Compile(line_src, src.data()); - } - else - { - 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (LibCompiler::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (LibCompiler::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("extern_segment " + needle) != - std::string::npos) - { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("extern_segment " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "sub") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } +class AssemblyCCInterface final ASSEMBLY_INTERFACE { + public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + + [[maybe_unused]] static Int32 Arch() noexcept { return LibCompiler::AssemblyFactory::kArch64x0; } + + Int32 CompileToFormat(std::string& src, Int32 arch) override { + if (arch != AssemblyCCInterface::Arch()) return 1; + + if (kCompilerFrontend == nullptr) return 1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) { + if (ch == '.') { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector<const char*> exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = LibCompiler::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + LibCompiler::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) { + if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->Compile(line_src, src.data()); + } else { + 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) { + for (auto& struc : kState.kStructMap) { + /// TODO: + } + } + } + + for (auto& keyword : keywords) { + if (LibCompiler::find_word(leaf.fUserValue, keyword)) { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) { + if (reg.fName[i] == ' ') { + ++i; + + for (; i < reg.fName.size(); i++) { + if (reg.fName[i] == ',') { + break; + } + + if (reg.fName[i] == ' ') continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (LibCompiler::find_word(leaf.fUserValue, needle)) { + if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { + std::string range = "extern_segment " + needle; + leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), + range.size(), needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) { + std::string::difference_type countComma = + std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kExitOK; + } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -1481,116 +1190,98 @@ public: #include <LibCompiler/Version.h> #define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) +#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) -static void cc_print_help() -{ - kSplashCxx(); +static void cc_print_help() { + kSplashCxx(); } ///////////////////////////////////////////////////////////////////////////////////////// #define kExt ".c" -LIBCOMPILER_MODULE(NeOSCompilerCLang64x0) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = LibCompiler::AssemblyFactory::kArch64x0; - kCompilerFrontend = new CompilerFrontend64x0(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "--v") == 0 || - strcmp(argv[index], "--version") == 0) - { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "--verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) - { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "--dialect") == 0) - { - if (kCompilerFrontend) - std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "--fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - 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; +LIBCOMPILER_MODULE(NeOSCompilerCLang64x0) { + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyCCInterface()); + kMachine = LibCompiler::AssemblyFactory::kArch64x0; + kCompilerFrontend = new CompilerFrontend64x0(); + + for (auto index = 1UL; index < argc; ++index) { + if (skip) { + skip = false; + continue; + } + + if (argv[index][0] == '-') { + if (strcmp(argv[index], "--v") == 0 || strcmp(argv[index], "--version") == 0) { + kSplashCxx(); + return kExitOK; + } + + if (strcmp(argv[index], "--verbose") == 0) { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) { + cc_print_help(); + + return kExitOK; + } + + if (strcmp(argv[index], "--dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + if (strcmp(argv[index], "--fmax-exceptions") == 0) { + try { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + 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/LibCompiler/src/CCompilerARM64.cc b/dev/LibCompiler/src/CCompilerARM64.cc index 5d3e892..accd9f9 100644 --- a/dev/LibCompiler/src/CCompilerARM64.cc +++ b/dev/LibCompiler/src/CCompilerARM64.cc @@ -41,7 +41,7 @@ #define kExitOK (0) #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -50,63 +50,57 @@ ///////////////////////////////////// -namespace Detail -{ - // \brief Register map structure, used to keep track of each variable's registers. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; - }; - - struct CompilerState final - { - std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace Detail +namespace Detail { +// \brief Register map structure, used to keep track of each variable's registers. +struct CompilerRegisterMap final { + std::string fName; + std::string fReg; +}; + +// \brief Map for C structs +// \author amlel +struct CompilerStructMap final { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector<std::pair<Int32, std::string>> fOffsets; +}; + +struct CompilerState final { + std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; +}; +} // namespace Detail static Detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace Detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept; - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace Detail +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace Detail { +/// @brief prints an error into stdout. +/// @param reason the reason of the error. +/// @param file where does it originate from? +void print_error(std::string reason, std::string file) noexcept; + +struct CompilerType final { + std::string fName; + std::string fValue; +}; +} // namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -119,11 +113,11 @@ static int kMachine = 0; ///////////////////////////////////////// -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; +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; ///////////////////////////////////////// @@ -131,67 +125,56 @@ static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// -static std::vector<std::string> kFileList; +static std::vector<std::string> kFileList; static LibCompiler::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; +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 LibCompiler::ICompilerFrontend -{ -public: - explicit CompilerFrontendARM64() = default; - ~CompilerFrontendARM64() override = default; +class CompilerFrontendARM64 final : public LibCompiler::ICompilerFrontend { + public: + explicit CompilerFrontendARM64() = default; + ~CompilerFrontendARM64() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendARM64); + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendARM64); - std::string Check(const char* text, const char* file); - bool Compile(std::string text, const std::string file) override; + std::string Check(const char* text, const char* file); + bool Compile(std::string text, const std::string file) override; - const char* Language() override - { - return "64k C"; - } + const char* Language() override { return "64k C"; } }; -static CompilerFrontendARM64* kCompilerFrontend = nullptr; +static CompilerFrontendARM64* kCompilerFrontend = nullptr; static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; +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 +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 ///////////////////////////////////////////////////////////////////////////////////////// @@ -200,1088 +183,856 @@ namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerFrontendARM64::Compile(std::string text, const 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 = LibCompiler::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 += ' '; +bool CompilerFrontendARM64::Compile(std::string text, const 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + Detail::number_cast time_off = (UInt64) out.as_bytes().data(); + + if (!typeFound) { + auto substr = text.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) { + if (substr[y] == ' ') { + while (match_type.find(' ') != std::string::npos) { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) { + if (clType.fName == match_type) { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) { + break; + } + + if (text.find('(') != std::string::npos) { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (text[text_index] == 'r') { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) { + if (!value.empty()) { + if (value.find('(') != std::string::npos) { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " extern_segment"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); + + kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; + syntaxLeaf.fUserValue += kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword public_segment .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value in struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + if (ch == ' ') { + space_found_ = true; + } + + if (ch == ';') break; + + if (space_found_) sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } else { + substr += "\tldw "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; + + if (text[text_index_2] == ';') { + break; + } + + if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { + if (first_encountered != 2) { + if (text[text_index] != '=' && + substr.find("public_segment .data64") == std::string::npos && !kInStruct) + substr += "public_segment .data64 "; + } + + ++first_encountered; + + continue; + } + + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } - if (substr.find('=') != std::string::npos) - { - break; - } + substr += ","; + continue; + } - if (text.find('(') != std::string::npos) - { - syntaxLeaf.fUserValue = buf; + substr += text[text_index_2]; + } - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } + for (auto& clType : kCompilerTypes) { + if (substr.find(clType.fName) != std::string::npos) { + if (substr.find(clType.fName) > substr.find('"')) continue; - break; - } + 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; - match_type += substr[y]; - } - } + if (clType.fName == "const") continue; - if (text[text_index] == '{') - { - if (kInStruct) - { - continue; - } - - kInBraces = true; - ++kBracesCount; + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') - { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); - ++return_index) - { - if (text[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < text.size(); ++value_index) - { - if (text[value_index] == ';') - break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') - { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__LIBCOMPILER_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (text[text_index] == ';' && kInStruct) - continue; - - if (text.find("typedef ") != std::string::npos) - continue; - - if (text[text_index] == '=' && kInStruct) - { - Detail::print_error("assignement of value in struct " + text, - file); - continue; - } - - if (text[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) - { - continue; - } - - if (text[text_index + 1] == '=' || - text[text_index - 1] == '!' || - text[text_index - 1] == '<' || - text[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (text.find("*") != std::string::npos) - { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } - else - { - substr += "\tldw "; - } - } - else if (text.find('=') != std::string::npos && !kInBraces) - { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); - ++text_index_2) - { - if (text[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) - { - if (text[text_index_2] == '\"') - break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') - continue; - - if (text[text_index_2] == ';') - { - break; - } - - if (text[text_index_2] == ' ' || - text[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && - !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("public_segment .data64"), - strlen("public_segment .data64"), "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) - { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') - break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); - ++idx) - { - if (text[idx] == ',') - continue; - - if (text[idx] == ' ') - continue; - - if (text[idx] == ')') - break; - } - - for (char substr_first_index : text) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') - { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); + if (substr.find("extern") != std::string::npos) { + substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - if (!args_buffer.empty()) - args += "\tldw r6, "; + if (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); + } - std::string register_type; - std::size_t index = 7UL; + auto var_to_find = std::find_if( + kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); + if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - ++index; + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } + if (var_to_find == kCompilerVariables.cend()) { + ++kRegisterCounter; - args += args_buffer; - args += "\n\tlda r19, "; - } - } + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } - for (char _text_i : text) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - continue; - } + if (text[text_index] == '=') break; + } - if (_text_i == '(') - break; + // function handler. - substr += _text_i; - } + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; - if (kInBraces) - { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; + bool type_crossed = false; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; - fnFound = true; - } - else - { - syntaxLeaf.fUserValue.clear(); + if (text[idx] == ' ') continue; - syntaxLeaf.fUserValue += "public_segment .code64 "; + if (text[idx] == ')') break; + } - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; + for (char substr_first_index : text) { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + 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); - fnFound = true; - } + if (!args_buffer.empty()) args += "\tldw r6, "; - kCompilerFunctions.push_back(text); - } + std::string register_type; + std::size_t index = 7UL; - if (text[text_index] == '-' && text[text_index + 1] == '-') - { - text = text.replace(text.find("--"), strlen("--"), ""); + while (args_buffer.find("$") != std::string::npos) { + register_type = kRegisterPrefix; + register_type += std::to_string(index); - for (int _text_i = 0; _text_i < text.size(); ++_text_i) - { - if (text[_text_i] == '\t' || text[_text_i] == ' ') - text.erase(_text_i, 1); - } + ++index; - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; + args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); + } - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } + args += args_buffer; + args += "\n\tlda r19, "; + } + } - if (text[text_index] == '}') - { - kRegisterCounter = kStartUsable; + for (char _text_i : text) { + if (_text_i == '\t' || _text_i == ' ') { + if (!type_crossed) { + substr.clear(); + type_crossed = true; + } - --kBracesCount; + continue; + } - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } + if (_text_i == '(') break; - if (kIfFound) - kIfFound = false; + substr += _text_i; + } - if (kInStruct) - kInStruct = false; + if (kInBraces) { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - syntaxLeaf.fUserValue.clear(); - } + fnFound = true; + } else { + syntaxLeaf.fUserValue.clear(); - auto syntaxLeaf = LibCompiler::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + syntaxLeaf.fUserValue += "public_segment .code64 "; - return true; + 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; } -static bool kShouldHaveBraces = false; +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; - } +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 (LibCompiler::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } + // extern does not declare anything, it extern_segments a variable. + // so that's why it's not declare upper. + if (LibCompiler::find_word(ln, "extern")) { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) { + if (ln[i] == '\"') { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { + if (ln.find('{') == std::string::npos) { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } else if (ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + } + } skip_braces_check: - for (auto& key : kCompilerTypes) - { - if (LibCompiler::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && - !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && - !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; + for (auto& key : kCompilerTypes) { + if (LibCompiler::find_word(ln, key.fName)) { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; + + goto next; + } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find('=') == std::string::npos) continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } else { + continue; + } + + if (ln.find('=') != std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) { + if (ln.find(';') == std::string::npos) { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { + if (ln.find(';') + 1 != ln.size()) { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) { + if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && + !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && + !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) { + bool found_func = false; + size_t i = ln.find('('); + std::vector<char> opens; + std::vector<char> closes; + + for (; i < ln.size(); ++i) { + if (ln[i] == ')') { + closes.push_back(1); + } + + if (ln[i] == '(') { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) { + if (ln[i] == ')' && !space_found) { + space_found = true; + continue; + } + + if (space_found) { + if (ln[i] == ' ' && isalnum(ln[i + 1])) { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } else { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } else { + if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) { + if (!kInStruct && ln.find(';') == std::string::npos) { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) { + if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { + if (ln.size() <= 2) return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1292,186 +1043,146 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCCInterface final ASSEMBLY_INTERFACE -{ -public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return LibCompiler::AssemblyFactory::kArchAARCH64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCCInterface::Arch()) - return 1; - - if (kCompilerFrontend == nullptr) - return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = LibCompiler::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: ARM64 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - LibCompiler::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerFrontend->Compile(line_src, src.data()); - } - else - { - 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (LibCompiler::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (LibCompiler::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("extern_segment " + needle) != - std::string::npos) - { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("extern_segment " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "sub") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } +class AssemblyCCInterface final ASSEMBLY_INTERFACE { + public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyCCInterface); + + [[maybe_unused]] static Int32 Arch() noexcept { + return LibCompiler::AssemblyFactory::kArchAARCH64; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override { + if (arch != AssemblyCCInterface::Arch()) return 1; + + if (kCompilerFrontend == nullptr) return 1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) { + if (ch == '.') { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector<const char*> exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = LibCompiler::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) << "# Language: ARM64 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + LibCompiler::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) { + if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->Compile(line_src, src.data()); + } else { + 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) { + for (auto& struc : kState.kStructMap) { + /// TODO: + } + } + } + + for (auto& keyword : keywords) { + if (LibCompiler::find_word(leaf.fUserValue, keyword)) { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) { + if (reg.fName[i] == ' ') { + ++i; + + for (; i < reg.fName.size(); i++) { + if (reg.fName[i] == ',') { + break; + } + + if (reg.fName[i] == ' ') continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (LibCompiler::find_word(leaf.fUserValue, needle)) { + if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { + std::string range = "extern_segment " + needle; + leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), + range.size(), needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) { + std::string::difference_type countComma = + std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kExitOK; + } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -1479,116 +1190,98 @@ public: #include <LibCompiler/Version.h> #define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) +#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) -static void cc_print_help() -{ - kSplashCxx(); +static void cc_print_help() { + kSplashCxx(); } ///////////////////////////////////////////////////////////////////////////////////////// #define kCExtension ".c" -LIBCOMPILER_MODULE(NeOSCompilerCLangARM64) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = LibCompiler::AssemblyFactory::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; +LIBCOMPILER_MODULE(NeOSCompilerCLangARM64) { + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyCCInterface()); + kMachine = LibCompiler::AssemblyFactory::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/LibCompiler/src/CCompilerPower64.cc b/dev/LibCompiler/src/CCompilerPower64.cc index ac35c4a..90031a0 100644 --- a/dev/LibCompiler/src/CCompilerPower64.cc +++ b/dev/LibCompiler/src/CCompilerPower64.cc @@ -10,6 +10,7 @@ #include <LibCompiler/Backend/power64.h> #include <LibCompiler/Parser.h> #include <LibCompiler/UUID.h> +#include <cstdio> #include <fstream> #include <iostream> #include <memory> @@ -17,7 +18,6 @@ #include <string> #include <utility> #include <vector> -#include <cstdio> #define kExitOK 0 @@ -32,7 +32,7 @@ ///////////////////// #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -41,63 +41,57 @@ ///////////////////////////////////// -namespace Detail -{ - // \brief name to register struct. - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Map for C structs - // \author amlel - struct CompilerStructMap final - { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; - }; - - struct CompilerState final - { - std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; - }; -} // namespace Detail +namespace Detail { +// \brief name to register struct. +struct CompilerRegisterMap final { + std::string fName; + std::string fReg; +}; + +// \brief Map for C structs +// \author amlel +struct CompilerStructMap final { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector<std::pair<Int32, std::string>> fOffsets; +}; + +struct CompilerState final { + std::vector<LibCompiler::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; +}; +} // namespace Detail static Detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace Detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept; - - struct CompilerType final - { - std::string fName; - std::string fValue; - }; -} // namespace Detail +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace Detail { +/// @brief prints an error into stdout. +/// @param reason the reason of the error. +/// @param file where does it originate from? +void print_error(std::string reason, std::string file) noexcept; + +struct CompilerType final { + std::string fName; + std::string fValue; +}; +} // namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -110,11 +104,11 @@ static int kMachine = 0; ///////////////////////////////////////// -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; +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; ///////////////////////////////////////// @@ -122,67 +116,56 @@ static std::string kRegisterPrefix = kAsmRegisterPrefix; ///////////////////////////////////////// -static std::vector<std::string> kFileList; +static std::vector<std::string> kFileList; static LibCompiler::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; /* @brief C compiler backend for C */ -class CompilerFrontendPower64 final : public LibCompiler::ICompilerFrontend -{ -public: - explicit CompilerFrontendPower64() = default; - ~CompilerFrontendPower64() override = default; +class CompilerFrontendPower64 final : public LibCompiler::ICompilerFrontend { + public: + explicit CompilerFrontendPower64() = default; + ~CompilerFrontendPower64() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendPower64); + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendPower64); - std::string Check(const char* text, const char* file); - bool Compile(std::string text, const std::string file) override; + std::string Check(const char* text, const char* file); + bool Compile(std::string text, const std::string file) override; - const char* Language() override - { - return "POWER C"; - } + const char* Language() override { return "POWER C"; } }; -static CompilerFrontendPower64* kCompilerFrontend = nullptr; +static CompilerFrontendPower64* kCompilerFrontend = nullptr; static std::vector<Detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; +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 +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 ///////////////////////////////////////////////////////////////////////////////////////// @@ -191,1122 +174,885 @@ namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// -bool CompilerFrontendPower64::Compile(std::string text_, const 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 = LibCompiler::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 += ' '; +bool CompilerFrontendPower64::Compile(std::string text_, const 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + Detail::number_cast time_off = (UInt64) out.as_bytes().data(); + + if (!typeFound) { + auto substr = text.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) { + if (substr[y] == ' ') { + while (match_type.find(' ') != std::string::npos) { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) { + if (clType.fName == match_type) { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) { + break; + } + + if (text.find('(') != std::string::npos) { + syntax_leaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (text[text_index] == '{') { + if (kInStruct) { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } + + // return keyword handler + if (text[text_index] == 'r') { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < text.size(); ++return_index) { + if (text[return_index] != return_keyword[index]) { + for (size_t value_index = return_index; value_index < text.size(); ++value_index) { + if (text[value_index] == ';') break; + + value += text[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) { + if (!value.empty()) { + if (value.find('(') != std::string::npos) { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " extern_segment"; + value += tmp; + } + + syntax_leaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) value.erase(value.find(' '), 1); + + while (value.find("extern_segment") != std::string::npos) + value.erase(value.find("extern_segment"), strlen("extern_segment")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) { + if (value.find(reg.fName) != std::string::npos) { + found = true; + syntax_leaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) syntax_leaf.fUserValue += "r0"; + } + + syntax_leaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + break; + } + } + + if (text[text_index] == 'i' && text[text_index + 1] == 'f') { + auto expr = text.substr(text_index + 2); + text.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); + + kIfFunction = "__LIBCOMPILER_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntax_leaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntax_leaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction + + " \ndword public_segment .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (text[text_index] == '=' || text[text_index] == ';') { + if (fnFound) continue; + if (kIfFound) continue; + + if (text[text_index] == ';' && kInStruct) continue; + + if (text.find("typedef ") != std::string::npos) continue; + + if (text[text_index] == '=' && kInStruct) { + Detail::print_error("assignement of value inside a struct " + text, file); + continue; + } + + if (text[text_index] == ';' && kInStruct) { + bool space_found_ = false; + std::string sym; + + for (auto& ch : text) { + if (ch == ' ') { + space_found_ = true; + } + + if (ch == ';') break; + + if (space_found_) sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (text[text_index] == '=' && kInStruct) { + continue; + } + + if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || + text[text_index - 1] == '<' || text[text_index - 1] == '>') { + continue; + } + + std::string substr; + + if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { + if (text.find("*") != std::string::npos) { + if (text.find("=") > text.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } else { + substr += "\tli "; + } + } else if (text.find('=') != std::string::npos && !kInBraces) { + substr += "stw public_segment .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < text.size(); ++text_index_2) { + if (text[text_index_2] == '\"') break; + + substr += text[text_index_2]; + } + } + + if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - if (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; - } + if (text[text_index_2] == ';') { + break; + } - match_type += substr[y]; - } - } + 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 "; + } - 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"; + ++first_encountered; - std::size_t index = 0UL; - - std::string value; + continue; + } - for (size_t return_index = text_index; return_index < text.size(); - ++return_index) - { - if (text[return_index] != return_keyword[index]) - { - for (size_t value_index = return_index; - value_index < text.size(); ++value_index) - { - if (text[value_index] == ';') - break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) - { - if (!value.empty()) - { - if (value.find('(') != std::string::npos) - { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) - { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntax_leaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("extern_segment") != std::string::npos) - value.erase(value.find("extern_segment"), strlen("extern_segment")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) - { - if (value.find(reg.fName) != std::string::npos) - { - found = true; - syntax_leaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) - syntax_leaf.fUserValue += "r0"; - } - - syntax_leaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') - { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) - { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) - expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) - expr.erase(expr.find(")")); - - kIfFunction = "__LIBCOMPILER_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntax_leaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntax_leaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction + - " \ndword public_segment .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') - { - if (fnFound) - continue; - if (kIfFound) - continue; - - if (text[text_index] == ';' && kInStruct) - continue; - - if (text.find("typedef ") != std::string::npos) - continue; - - if (text[text_index] == '=' && kInStruct) - { - Detail::print_error( - "assignement of value inside a struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) - { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) - { - if (ch == ' ') - { - space_found_ = true; - } - - if (ch == ';') - break; - - if (space_found_) - sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) - { - continue; - } - - if (text[text_index + 1] == '=' || - text[text_index - 1] == '!' || - text[text_index - 1] == '<' || - text[text_index - 1] == '>') - { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) - { - if (text.find("*") != std::string::npos) - { - if (text.find("=") > text.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } - else - { - substr += "\tli "; - } - } - else if (text.find('=') != std::string::npos && !kInBraces) - { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); - ++text_index_2) - { - if (text[text_index_2] == '\"') - { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) - { - if (text[text_index_2] == '\"') - break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') - continue; - - if (text[text_index_2] == ';') - { - break; - } - - if (text[text_index_2] == ' ' || - text[text_index_2] == '\t') - { - if (first_encountered != 2) - { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && - !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') - { - if (!kInBraces) - { - substr.replace(substr.find("public_segment .data64"), - strlen("public_segment .data64"), "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) - { - if (substr.find(clType.fName) != std::string::npos) - { - if (substr.find(clType.fName) > substr.find('"')) - continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } - else if (substr.find(clType.fValue) != std::string::npos) - { - if (substr.find(clType.fValue) > substr.find('"')) - continue; - - if (clType.fName == "const") - continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) - { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - kCompilerVariables.push_back({.fName = substr}); - - if (text[text_index] == ';') - break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) - { - if (newSubstr[start] == ',') - break; - - if (newSubstr[start] == ' ') - continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntax_leaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } + if (text[text_index_2] == '=') { + if (!kInBraces) { + substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), + "public_segment .zero64 "); + } - // function handler. + substr += ","; + continue; + } - if (text[text_index] == '(' && !fnFound && !kIfFound) - { - std::string substr; - std::string args_buffer; - std::string args; + substr += text[text_index_2]; + } - bool type_crossed = false; + for (auto& clType : kCompilerTypes) { + if (substr.find(clType.fName) != std::string::npos) { + if (substr.find(clType.fName) > substr.find('"')) continue; - for (size_t idx = text.find('(') + 1; idx < text.size(); - ++idx) - { - if (text[idx] == ',') - 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 (text[idx] == ' ') - continue; + if (clType.fName == "const") continue; - if (text[idx] == ')') - break; - } + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } - for (char substr_first_index : text) - { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; + if (substr.find("extern") != std::string::npos) { + substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - 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 (substr.find("public_segment .data64") != std::string::npos) + substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); + } - if (!args_buffer.empty()) - args += "\tldw r6, "; + auto var_to_find = std::find_if( + kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - std::string register_type; - std::size_t index = 7UL; + kCompilerVariables.push_back({.fName = substr}); - while (args_buffer.find("$") != std::string::npos) - { - register_type = kRegisterPrefix; - register_type += std::to_string(index); + if (text[text_index] == ';') break; - ++index; + std::string reg = kAsmRegisterPrefix; - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); - args += args_buffer; - args += "\n\tli r31, "; - } - } + auto newSubstr = substr.substr(substr.find(" ")); - for (char _text_i : text) - { - if (_text_i == '\t' || _text_i == ' ') - { - if (!type_crossed) - { - substr.clear(); - type_crossed = true; - } + std::string symbol; - continue; - } + for (size_t start = 0; start < newSubstr.size(); ++start) { + if (newSubstr[start] == ',') break; - if (_text_i == '(') - break; + if (newSubstr[start] == ' ') continue; - substr += _text_i; - } + symbol += (newSubstr[start]); + } - if (kInBraces) - { - syntax_leaf.fUserValue = args; - syntax_leaf.fUserValue += substr; + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - syntax_leaf.fUserValue += "\n\tblr\n"; + syntax_leaf.fUserValue += "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + } - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + // function handler. - fnFound = true; - } - else - { - syntax_leaf.fUserValue.clear(); + if (text[text_index] == '(' && !fnFound && !kIfFound) { + std::string substr; + std::string args_buffer; + std::string args; - syntax_leaf.fUserValue += "public_segment .code64 "; + bool type_crossed = false; - syntax_leaf.fUserValue += substr; - syntax_leaf.fUserValue += "\n"; + for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { + if (text[idx] == ',') continue; - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + if (text[idx] == ' ') continue; - fnFound = true; - } + if (text[idx] == ')') break; + } - kCompilerFunctions.push_back(text); - } + for (char substr_first_index : text) { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; - if (text[text_index] == '-' && text[text_index + 1] == '-') - { - text = text.replace(text.find("--"), strlen("--"), ""); + 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); - for (int _text_i = 0; _text_i < text.size(); ++_text_i) - { - if (text[_text_i] == '\t' || text[_text_i] == ' ') - text.erase(_text_i, 1); - } + if (!args_buffer.empty()) args += "\tldw r6, "; - syntax_leaf.fUserValue += "dec "; - syntax_leaf.fUserValue += text; + std::string register_type; + std::size_t index = 7UL; - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - break; - } + while (args_buffer.find("$") != std::string::npos) { + register_type = kRegisterPrefix; + register_type += std::to_string(index); - if (text[text_index] == '}') - { - kRegisterCounter = kStartUsable; + ++index; - --kBracesCount; + args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); + } - if (kBracesCount < 1) - { - kInBraces = false; - kBracesCount = 0; - } + args += args_buffer; + args += "\n\tli r31, "; + } + } - if (kIfFound) - kIfFound = false; + for (char _text_i : text) { + if (_text_i == '\t' || _text_i == ' ') { + if (!type_crossed) { + substr.clear(); + type_crossed = true; + } - if (kInStruct) - kInStruct = false; + continue; + } - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } + if (_text_i == '(') break; - syntax_leaf.fUserValue.clear(); - } + substr += _text_i; + } - auto syntax_leaf = LibCompiler::SyntaxLeafList::SyntaxLeaf(); - syntax_leaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + if (kInBraces) { + syntax_leaf.fUserValue = args; + syntax_leaf.fUserValue += substr; - return true; + 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 = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + syntax_leaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); + + return true; } -static bool kShouldHaveBraces = false; +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; - } +std::string CompilerFrontendPower64::Check(const char* text, const char* file) { + std::string err_str; + std::string ln = text; + + if (ln.empty()) { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) { + if (isalnum(ln[i])) { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == '\'') { + if (ln[string_index + 1] != ';') { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } else if (ln.find('"') != std::string::npos) { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == '"') { + if (ln[string_index + 1] != ';') { + ln.erase(string_index, 1); + } else { + break; + } + } + } + } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { + std::vector<std::string> forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("--*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) { + if (ln.find(forbidden) != std::string::npos) { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final { + std::string fBegin; + std::string fEnd; + }; + + const std::vector<CompilerVariableRange> variables_list = { + {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) { + if (ln.find(variable.fBegin) != std::string::npos) { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) { + if (ln[string_index] == variable.fEnd[0]) { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; + ++index_keyword) { + if (ln[index_keyword] == ' ') { + continue; + } + + if (isdigit(ln[index_keyword])) { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) { + if (var.fValue.find(keyword) != std::string::npos) { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) { + if (fn.find(keyword[0]) != std::string::npos) { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; + + if (fn[where_begin] != keyword[keyword_begin]) { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) { + err_str.clear(); + goto cc_next; + } else { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) return err_str; + + if (keyword.find(".") != std::string::npos) return err_str; + + if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } cc_next: - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (LibCompiler::find_word(ln, "extern")) - { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) - { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } - else if (kShouldHaveBraces && ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) - { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) - { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) - { - if (ln[i] == '\"') - { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) - { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) - { - if (ln.find('{') == std::string::npos) - { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } - else if (ln.find('{') != std::string::npos) - { - kShouldHaveBraces = false; - } - } + // extern does not declare anything, it extern_segments a variable. + // so that's why it's not declare upper. + if (LibCompiler::find_word(ln, "extern")) { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) { + if (ln[i] == '\"') { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { + if (ln.find('{') == std::string::npos) { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } else if (ln.find('{') != std::string::npos) { + kShouldHaveBraces = false; + } + } skip_braces_check: - for (auto& key : kCompilerTypes) - { - if (LibCompiler::find_word(ln, key.fName)) - { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) - { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') - { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') - type_not_found = false; - - goto next; - } - else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') - { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') - type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find('=') == std::string::npos) - continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - else - { - continue; - } - - if (ln.find('=') != std::string::npos) - { - if (ln.find('(') != std::string::npos) - { - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && - ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) - { - if (ln.find(';') == std::string::npos) - { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && - ln.find("for") == std::string::npos) - { - if (ln.find(';') + 1 != ln.size()) - { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) - { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || - (ln.substr(ln.find(';') + 1)[i] != '\t')) - { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); - !err.empty()) - { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) - { - if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && - !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && - !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) - { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) - { - if (ln[i] == ')') - { - closes.push_back(1); - } - - if (ln[i] == '(') - { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) - { - if (ln[i] == ')' && !space_found) - { - space_found = true; - continue; - } - - if (space_found) - { - if (ln[i] == ' ' && isalnum(ln[i + 1])) - { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) - { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } - else - { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) - { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) - { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - else - { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) - { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) - { - if (!kInStruct && ln.find(';') == std::string::npos) - { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) - { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) - { - if (ln.size() <= 2) - return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; + for (auto& key : kCompilerTypes) { + if (LibCompiler::find_word(ln, key.fName)) { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; + + goto next; + } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find('=') == std::string::npos) continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } else { + continue; + } + + if (ln.find('=') != std::string::npos) { + if (ln.find('(') != std::string::npos) { + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) { + if (ln.find(';') == std::string::npos) { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { + if (ln.find(';') + 1 != ln.size()) { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) { + if (ln.find(';') == std::string::npos && !LibCompiler::find_word(ln, "|") && + !LibCompiler::find_word(ln, "||") && !LibCompiler::find_word(ln, "&") && + !LibCompiler::find_word(ln, "&&") && !LibCompiler::find_word(ln, "~")) { + bool found_func = false; + size_t i = ln.find('('); + std::vector<char> opens; + std::vector<char> closes; + + for (; i < ln.size(); ++i) { + if (ln[i] == ')') { + closes.push_back(1); + } + + if (ln[i] == '(') { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) { + if (ln[i] == ')' && !space_found) { + space_found = true; + continue; + } + + if (space_found) { + if (ln[i] == ' ' && isalnum(ln[i + 1])) { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } else { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } else { + if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) { + if (!kInStruct && ln.find(';') == std::string::npos) { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) { + if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { + if (ln.size() <= 2) return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -1317,183 +1063,145 @@ skip_braces_check: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyMountpointCLang final ASSEMBLY_INTERFACE -{ -public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - LIBCOMPILER_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept - { - return LibCompiler::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyMountpointCLang::Arch()) - return 1; - - if (kCompilerFrontend == nullptr) - return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) - { - if (ch == '.') - { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char*> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = LibCompiler::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - LibCompiler::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) - { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); - err.empty()) - { - kCompilerFrontend->Compile(line_src, src.data()); - } - else - { - 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) - { - for (auto& struc : kState.kStructMap) - { - /// TODO: - } - } - } - - for (auto& keyword : keywords) - { - if (LibCompiler::find_word(leaf.fUserValue, keyword)) - { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) - { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ' ') - { - ++i; - - for (; i < reg.fName.size(); i++) - { - if (reg.fName[i] == ',') - { - break; - } - - if (reg.fName[i] == ' ') - continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (LibCompiler::find_word(leaf.fUserValue, needle)) - { - if (leaf.fUserValue.find("extern_segment ") != std::string::npos) - { - std::string range = "extern_segment "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) - { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) - { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") - { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } +class AssemblyMountpointCLang final ASSEMBLY_INTERFACE { + public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + LIBCOMPILER_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept { + return LibCompiler::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override { + if (arch != AssemblyMountpointCLang::Arch()) return 1; + + if (kCompilerFrontend == nullptr) return 1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) { + if (ch == '.') { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector<const char*> exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = LibCompiler::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + LibCompiler::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) { + if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { + kCompilerFrontend->Compile(line_src, src.data()); + } else { + 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 (LibCompiler::find_word(leaf.fUserValue, access_ident)) { + for (auto& struc : kState.kStructMap) { + /// TODO: + } + } + } + + for (auto& keyword : keywords) { + if (LibCompiler::find_word(leaf.fUserValue, keyword)) { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) { + if (reg.fName[i] == ' ') { + ++i; + + for (; i < reg.fName.size(); i++) { + if (reg.fName[i] == ',') { + break; + } + + if (reg.fName[i] == ' ') continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (LibCompiler::find_word(leaf.fUserValue, needle)) { + if (leaf.fUserValue.find("extern_segment ") != std::string::npos) { + std::string range = "extern_segment "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) { + std::string::difference_type countComma = + std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && keyword != "dec") { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kExitOK; + } }; ///////////////////////////////////////////////////////////////////////////////////////// @@ -1501,116 +1209,98 @@ public: #include <LibCompiler/Version.h> #define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) +#define kSplashCxx() kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) -static void cc_print_help() -{ - kSplashCxx(); +static void cc_print_help() { + kSplashCxx(); } ///////////////////////////////////////////////////////////////////////////////////////// #define kExt ".c" -LIBCOMPILER_MODULE(NeOSCompilerCLangPowerPC) -{ - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = LibCompiler::AssemblyFactory::kArchPowerPC; - kCompilerFrontend = new CompilerFrontendPower64(); - - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } - - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) - { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "-verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) - { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "-dialect") == 0) - { - if (kCompilerFrontend) - std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - 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; +LIBCOMPILER_MODULE(NeOSCompilerCLangPowerPC) { + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = LibCompiler::AssemblyFactory::kArchPowerPC; + kCompilerFrontend = new CompilerFrontendPower64(); + + for (auto index = 1UL; index < argc; ++index) { + if (skip) { + skip = false; + continue; + } + + if (argv[index][0] == '-') { + if (strcmp(argv[index], "-v") == 0 || strcmp(argv[index], "-version") == 0) { + kSplashCxx(); + return kExitOK; + } + + if (strcmp(argv[index], "-verbose") == 0) { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { + cc_print_help(); + + return kExitOK; + } + + if (strcmp(argv[index], "-dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) { + try { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + 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/LibCompiler/src/CPlusPlusCompilerAMD64.cc b/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc index c053920..66cf859 100644 --- a/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc +++ b/dev/LibCompiler/src/CPlusPlusCompilerAMD64.cc @@ -14,8 +14,10 @@ #define kExitOK (EXIT_SUCCESS) #define kExitNO (EXIT_FAILURE) -#define kSplashCxx() \ - kPrintF(kWhite "%s\n", "NeKernel Optimized C++ Compiler Driver, (c) 2024-2025 Amlal El Mahrouss, All rights reserved.") +#define kSplashCxx() \ + kPrintF(kWhite "%s\n", \ + "NeKernel Optimized C++ Compiler Driver, (c) 2024-2025 Amlal El Mahrouss, All rights " \ + "reserved.") // extern_segment, @autodelete { ... }, fn foo() -> auto { ... } @@ -42,7 +44,7 @@ /////////////////////// #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" ///////////////////////////////////// @@ -52,80 +54,68 @@ ///////////////////////////////////// /// @internal -namespace Detail -{ - std::filesystem::path expand_home(const std::filesystem::path& p) - { - if (!p.empty() && p.string()[0] == '~') - { - const char* home = std::getenv("HOME"); // For Unix-like systems - if (!home) - { - home = std::getenv("USERPROFILE"); // For Windows - } - if (home) - { - return std::filesystem::path(home) / p.relative_path().string().substr(1); - } - else - { - throw std::runtime_error("Home directory not found in environment variables"); - } - } - return p; - } - - struct CompilerRegisterMap final - { - std::string fName; - std::string fReg; - }; - - // \brief Offset based struct/class - struct CompilerStructMap final - { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector<std::pair<Int32, std::string>> fOffsets; - }; - - struct CompilerState final - { - std::vector<CompilerRegisterMap> fStackMapVector; - std::vector<CompilerStructMap> fStructMapVector; - LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - Boolean fVerbose; - }; -} // namespace Detail +namespace Detail { +std::filesystem::path expand_home(const std::filesystem::path& p) { + if (!p.empty() && p.string()[0] == '~') { + const char* home = std::getenv("HOME"); // For Unix-like systems + if (!home) { + home = std::getenv("USERPROFILE"); // For Windows + } + if (home) { + return std::filesystem::path(home) / p.relative_path().string().substr(1); + } else { + throw std::runtime_error("Home directory not found in environment variables"); + } + } + return p; +} + +struct CompilerRegisterMap final { + std::string fName; + std::string fReg; +}; + +// \brief Offset based struct/class +struct CompilerStructMap final { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector<std::pair<Int32, std::string>> fOffsets; +}; + +struct CompilerState final { + std::vector<CompilerRegisterMap> fStackMapVector; + std::vector<CompilerStructMap> fStructMapVector; + LibCompiler::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + Boolean fVerbose; +}; +} // namespace Detail static Detail::CompilerState kState; -static SizeType kErrorLimit = 100; +static SizeType kErrorLimit = 100; static Int32 kOnClassScope = 0; static Int32 kAcceptableErrors = 0; -namespace Detail -{ - /// @brief prints an error into stdout. - /// @param reason the reason of the error. - /// @param file where does it originate from? - void print_error(std::string reason, std::string file) noexcept; +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 +struct CompilerType final { + std::string fName; + std::string fValue; +}; +} // namespace Detail ///////////////////////////////////////////////////////////////////////////////////////// @@ -138,10 +128,10 @@ static int kMachine = LibCompiler::AssemblyFactory::kArchAMD64; ///////////////////////////////////////// -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; static std::vector<LibCompiler::CompilerKeyword> kKeywords; ///////////////////////////////////////// @@ -150,26 +140,25 @@ static std::vector<LibCompiler::CompilerKeyword> kKeywords; ///////////////////////////////////////// -static std::vector<std::string> kFileList; +static std::vector<std::string> kFileList; static LibCompiler::AssemblyFactory kFactory; -static Boolean kInStruct = false; -static Boolean kOnWhileLoop = false; -static Boolean kOnForLoop = false; -static Boolean kInBraces = false; -static size_t kBracesCount = 0UL; +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 NE C++ driver */ -class CompilerFrontendCPlusPlus final : public LibCompiler::ICompilerFrontend -{ -public: - explicit CompilerFrontendCPlusPlus() = default; - ~CompilerFrontendCPlusPlus() override = default; +class CompilerFrontendCPlusPlus final : public LibCompiler::ICompilerFrontend { + public: + explicit CompilerFrontendCPlusPlus() = default; + ~CompilerFrontendCPlusPlus() override = default; - LIBCOMPILER_COPY_DEFAULT(CompilerFrontendCPlusPlus); + LIBCOMPILER_COPY_DEFAULT(CompilerFrontendCPlusPlus); - Boolean Compile(const std::string text, const std::string file) override; + Boolean Compile(const std::string text, const std::string file) override; - const char* Language() override; + const char* Language() override; }; /// @internal compiler variables @@ -179,40 +168,21 @@ static CompilerFrontendCPlusPlus* kCompilerFrontend = nullptr; static std::vector<std::string> kRegisterMap; static std::vector<std::string> kRegisterList = { - "rbx", - "rsi", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", - "xmm12", - "xmm13", - "xmm14", - "xmm15", + "rbx", "rsi", "r10", "r11", "r12", "r13", "r14", "r15", "xmm12", "xmm13", "xmm14", "xmm15", }; /// @brief The PEF calling convention (caller must save rax, rbp) /// @note callee must return via **rax**. static std::vector<std::string> kRegisterConventionCallList = { - "r8", - "r9", - "r10", - "r11", - "r12", - "r13", - "r14", - "r15", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", }; static std::size_t kFunctionEmbedLevel = 0UL; /// detail namespaces -const char* CompilerFrontendCPlusPlus::Language() -{ - return "NeKernel C++"; +const char* CompilerFrontendCPlusPlus::Language() { + return "NeKernel C++"; } static std::uintptr_t kOrigin = 0x1000000; @@ -226,645 +196,553 @@ std::vector<std::pair<std::string, std::uintptr_t>> kOriginMap; ///////////////////////////////////////////////////////////////////////////////////////// -Boolean CompilerFrontendCPlusPlus::Compile(std::string text, - const std::string file) -{ - if (text.empty()) - return true; - - // Clean whitespace and tabs - std::string cleanLine = text; - cleanLine.erase(std::remove(cleanLine.begin(), cleanLine.end(), '\t'), cleanLine.end()); - cleanLine.erase(0, cleanLine.find_first_not_of(" \r\n")); - cleanLine.erase(cleanLine.find_last_not_of(" \r\n") + 1); - - // Skip empty, doc, or block comment lines - if (cleanLine.empty() || cleanLine.starts_with("///") || cleanLine.starts_with("//") || cleanLine.starts_with("/*")) - return true; - - std::size_t index = 0UL; - std::vector<std::pair<LibCompiler::CompilerKeyword, std::size_t>> keywords_list; - - Boolean found = false; - static Boolean commentBlock = false; - - for (auto& keyword : kKeywords) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - switch (keyword.keyword_kind) - { - case LibCompiler::kKeywordKindCommentMultiLineStart: { - commentBlock = true; - return true; - } - case LibCompiler::kKeywordKindCommentMultiLineEnd: { - commentBlock = false; - break; - } - case LibCompiler::kKeywordKindCommentInline: { - break; - } - default: - break; - } - - if (text[text.find(keyword.keyword_name) - 1] == '+' && - keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) - 1] == '-' && - keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) - continue; - - if (text[text.find(keyword.keyword_name) + 1] == '=' && - keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - - found = true; - } - } - - if (!found && !commentBlock) - { - for (size_t i = 0; i < text.size(); i++) - { - if (isalnum(text[i])) - { - Detail::print_error("syntax error: " + text, file); - return false; - } - } - } - - for (auto& keyword : keywords_list) - { - auto syntax_tree = LibCompiler::SyntaxLeafList::SyntaxLeaf(); - - switch (keyword.first.keyword_kind) - { - case LibCompiler::KeywordKind::kKeywordKindClass: { - ++kOnClassScope; - break; - } - case LibCompiler::KeywordKind::kKeywordKindIf: { - auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); - - if (expr.find(">=") != std::string::npos) - { - auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); - auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - - size_t i = right.size() - 1; - - try - { - while (!std::isalnum(right[i])) - { - right.erase(i, 1); - --i; - } - - right.erase(0, i); - } - catch (...) - { - right.erase(0, i); - } - - i = left.size() - 1; - try - { - while (!std::isalnum(left[i])) - { - left.erase(i, 1); - --i; - } - - left.erase(0, i); - } - catch (...) - { - left.erase(0, i); - } - - if (!isdigit(left[0]) || - !isdigit(right[0])) - { - auto indexRight = 0UL; - - auto& valueOfVar = !isdigit(left[0]) ? left : right; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + kRegisterList[indexRight + 1] + "\n"; - - goto done_iterarting_on_if; - } - - auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; - - syntax_tree.fUserValue += "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + kRegisterList[indexRight + 1] + "\n"; - - break; - } - } - - done_iterarting_on_if: - - std::string fnName = text; - fnName.erase(fnName.find(keyword.first.keyword_name)); - - for (auto& ch : fnName) - { - if (ch == ' ') - ch = '_'; - } - - syntax_tree.fUserValue += "jge __OFFSET_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n"; - } - - break; - } - case LibCompiler::KeywordKind::kKeywordKindFunctionStart: { - for (auto& ch : text) - { - if (isdigit(ch)) - { - goto dont_accept; - } - } - - goto accept; - - dont_accept: - return false; - - accept: - std::string fnName = text; - size_t indexFnName = 0; - - // this one is for the type. - for (auto& ch : text) - { - ++indexFnName; - - if (ch == '\t') - break; - - if (ch == ' ') - break; - } - - fnName = text.substr(indexFnName); - - if (text.find("return ") != std::string::npos) - { - text.erase(0, text.find("return ")); - break; - } - - if (text.ends_with(";") && text.find("return") == std::string::npos) - goto LC_write_assembly; - else if (text.size() <= indexFnName) - Detail::print_error("Invalid function name: " + fnName, file); - - indexFnName = 0; - - for (auto& ch : fnName) - { - if (ch == ' ' || - ch == '\t') - { - if (fnName[indexFnName - 1] != ')') - Detail::print_error("Invalid function name: " + fnName, file); - - if ((indexFnName + 1) != fnName.size()) - Detail::print_error("Extra characters after function name: " + fnName, file); - } - - ++indexFnName; - } - - syntax_tree.fUserValue = "public_segment .code64 __LIBCOMPILER_" + fnName + "\n"; - ++kFunctionEmbedLevel; - - kOriginMap.push_back({"__LIBCOMPILER_" + fnName, kOrigin}); - - break; - - LC_write_assembly: - auto it = std::find_if(kOriginMap.begin(), kOriginMap.end(), [&fnName](std::pair<std::string, std::uintptr_t> pair) -> bool { - return fnName == pair.first; - }); - - std::stringstream ss; - ss << std::hex << it->second; - - if (it != kOriginMap.end()) - { - syntax_tree.fUserValue = "jmp " + ss.str() + "\n"; - kOrigin += 1UL; - } - } - case LibCompiler::KeywordKind::kKeywordKindFunctionEnd: { - if (kOnClassScope) - --kOnClassScope; - - if (text.ends_with(";")) - break; - - --kFunctionEmbedLevel; - - if (kRegisterMap.size() > kRegisterList.size()) - { - --kFunctionEmbedLevel; - } - - if (kFunctionEmbedLevel < 1) - kRegisterMap.clear(); - - break; - } - case LibCompiler::KeywordKind::kKeywordKindEndInstr: - case LibCompiler::KeywordKind::kKeywordKindVariableInc: - case LibCompiler::KeywordKind::kKeywordKindVariableDec: - case LibCompiler::KeywordKind::kKeywordKindVariableAssign: { - std::string valueOfVar = ""; - - if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) - { - valueOfVar = text.substr(text.find("+=") + 2); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableDec) - { - valueOfVar = text.substr(text.find("-=") + 2); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) - { - valueOfVar = text.substr(text.find("=") + 1); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) - { - break; - } - - while (valueOfVar.find(";") != std::string::npos && - keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindEndInstr) - { - valueOfVar.erase(valueOfVar.find(";")); - } - - std::string varName = text; - - if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) - { - varName.erase(varName.find("+=")); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableDec) - { - varName.erase(varName.find("-=")); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) - { - varName.erase(varName.find("=")); - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) - { - varName.erase(varName.find(";")); - } - - static Boolean typeFound = false; - - for (auto& keyword : kKeywords) - { - if (keyword.keyword_kind == LibCompiler::kKeywordKindType) - { - if (text.find(keyword.keyword_name) != std::string::npos) - { - if (text[text.find(keyword.keyword_name)] == ' ') - { - typeFound = false; - continue; - } - - typeFound = true; - } - } - } - - std::string instr = "mov "; - - if (typeFound && keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableInc && - keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableDec) - { - if (kRegisterMap.size() > kRegisterList.size()) - { - ++kFunctionEmbedLevel; - } - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != valueOfVar) - { - if (valueOfVar[0] == '\"') - { - - syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } - else - { - syntax_tree.fUserValue = instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - } - - goto done; - } - } - - if (((int)indexRight - 1) < 0) - { - if (valueOfVar[0] == '\"') - { - - syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } - else - { - syntax_tree.fUserValue = instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - } - - goto done; - } - - if (valueOfVar[0] != '\"' && - valueOfVar[0] != '\'' && - !isdigit(valueOfVar[0])) - { - for (auto pair : kRegisterMap) - { - if (pair == valueOfVar) - goto done; - } - - Detail::print_error("Variable not declared: " + varName, file); - return false; - } - - done: - for (auto& keyword : kKeywords) - { - if (keyword.keyword_kind == LibCompiler::kKeywordKindType && - varName.find(keyword.keyword_name) != std::string::npos) - { - varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); - break; - } - } - - kRegisterMap.push_back(varName); - - break; - } - - if (kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindTypePtr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) - { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) - { - instr = "add "; - } - else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableDec) - { - instr = "sub "; - } - - std::string varErrCpy = varName; - - while (varName.find(" ") != std::string::npos) - { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != std::string::npos) - { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - for (size_t i = 0; !isalnum(valueOfVar[i]); i++) - { - if (i > valueOfVar.size()) - break; - - valueOfVar.erase(i, 1); - } - - while (valueOfVar.find(" ") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find(" "), 1); - } - - while (valueOfVar.find("\t") != std::string::npos) - { - valueOfVar.erase(valueOfVar.find("\t"), 1); - } - - constexpr auto cTrueVal = "true"; - constexpr auto cFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == cTrueVal) - { - valueOfVar = "1"; - } - else if (valueOfVar == cFalseVal) - { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != varName) - continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) - { - ++indexRight; - - if (pairRight != varName) - { - syntax_tree.fUserValue = instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - continue; - } - - syntax_tree.fUserValue = instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - break; - } - - break; - } - - if (syntax_tree.fUserValue.empty()) - { - Detail::print_error("Variable not declared: " + varName, file); - } - - break; - } - case LibCompiler::KeywordKind::kKeywordKindReturn: { - try - { - auto pos = text.find("return") + strlen("return") + 1; - std::string subText = text.substr(pos); - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (subText[0] != '\"' && - subText[0] != '\'') - { - if (!isdigit(subText[0])) - { - for (auto pair : kRegisterMap) - { - ++indxReg; - - if (pair != subText) - continue; - - syntax_tree.fUserValue = "mov rax, " + kRegisterList[indxReg - 1] + "\nret\n"; - kOrigin += 1UL; - - break; - } - } - else - { - syntax_tree.fUserValue = "mov rax, " + subText + "\nret\n"; - kOrigin += 1UL; - - break; - } - } - else - { - syntax_tree.fUserValue = "__LIBCOMPILER_LOCAL_RETURN_STRING: db " + subText + ", 0\nmov rcx, __LIBCOMPILER_LOCAL_RETURN_STRING\n"; - syntax_tree.fUserValue += "mov rax, rcx\nret\n"; - kOrigin += 1UL; - - break; - } - - if (syntax_tree.fUserValue.empty()) - { - if (subText.find("(") != std::string::npos) - { - subText.erase(subText.find("(")); - - auto it = std::find_if(kOriginMap.begin(), kOriginMap.end(), [&subText](std::pair<std::string, std::uintptr_t> pair) -> bool { - return pair.first.find(subText) != std::string::npos; - }); - - if (it == kOriginMap.end()) - Detail::print_error("Invalid return value: " + subText, file); - - std::stringstream ss; - ss << it->second; - - syntax_tree.fUserValue = "jmp " + ss.str() + "\nret\n"; - kOrigin += 1UL; - break; - } - } - - break; - } - catch (...) - { - syntax_tree.fUserValue = "ret\n"; - kOrigin += 1UL; - } - } - default: { - break; - } - } - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.push_back(syntax_tree); - } +Boolean CompilerFrontendCPlusPlus::Compile(std::string text, const std::string file) { + if (text.empty()) return true; + + // Clean whitespace and tabs + std::string cleanLine = text; + cleanLine.erase(std::remove(cleanLine.begin(), cleanLine.end(), '\t'), cleanLine.end()); + cleanLine.erase(0, cleanLine.find_first_not_of(" \r\n")); + cleanLine.erase(cleanLine.find_last_not_of(" \r\n") + 1); + + // Skip empty, doc, or block comment lines + if (cleanLine.empty() || cleanLine.starts_with("///") || cleanLine.starts_with("//") || + cleanLine.starts_with("/*")) + return true; + + std::size_t index = 0UL; + std::vector<std::pair<LibCompiler::CompilerKeyword, std::size_t>> keywords_list; + + Boolean found = false; + static Boolean commentBlock = false; + + for (auto& keyword : kKeywords) { + if (text.find(keyword.keyword_name) != std::string::npos) { + switch (keyword.keyword_kind) { + case LibCompiler::kKeywordKindCommentMultiLineStart: { + commentBlock = true; + return true; + } + case LibCompiler::kKeywordKindCommentMultiLineEnd: { + commentBlock = false; + break; + } + case LibCompiler::kKeywordKindCommentInline: { + break; + } + default: + break; + } + + if (text[text.find(keyword.keyword_name) - 1] == '+' && + keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) + 1] == '=' && + keyword.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableAssign) + continue; + + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + + found = true; + } + } + + if (!found && !commentBlock) { + for (size_t i = 0; i < text.size(); i++) { + if (isalnum(text[i])) { + Detail::print_error("syntax error: " + text, file); + return false; + } + } + } + + for (auto& keyword : keywords_list) { + auto syntax_tree = LibCompiler::SyntaxLeafList::SyntaxLeaf(); + + switch (keyword.first.keyword_kind) { + case LibCompiler::KeywordKind::kKeywordKindClass: { + ++kOnClassScope; + break; + } + case LibCompiler::KeywordKind::kKeywordKindIf: { + auto expr = text.substr( + text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, + text.find(")") - 1); + + if (expr.find(">=") != std::string::npos) { + auto left = text.substr( + text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, + expr.find("<=") + strlen("<=")); + auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); + + size_t i = right.size() - 1; + + try { + while (!std::isalnum(right[i])) { + right.erase(i, 1); + --i; + } + + right.erase(0, i); + } catch (...) { + right.erase(0, i); + } + + i = left.size() - 1; + try { + while (!std::isalnum(left[i])) { + left.erase(i, 1); + --i; + } + + left.erase(0, i); + } catch (...) { + left.erase(0, i); + } + + if (!isdigit(left[0]) || !isdigit(right[0])) { + auto indexRight = 0UL; + + auto& valueOfVar = !isdigit(left[0]) ? left : right; + + for (auto pairRight : kRegisterMap) { + ++indexRight; + + if (pairRight != valueOfVar) { + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += + "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + + kRegisterList[indexRight + 1] + "\n"; + + goto done_iterarting_on_if; + } + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += + "mov " + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + + kRegisterList[indexRight + 1] + "\n"; + + break; + } + } + + done_iterarting_on_if: + + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) { + if (ch == ' ') ch = '_'; + } + + syntax_tree.fUserValue += + "jge __OFFSET_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n"; + } + + break; + } + case LibCompiler::KeywordKind::kKeywordKindFunctionStart: { + for (auto& ch : text) { + if (isdigit(ch)) { + goto dont_accept; + } + } + + goto accept; + + dont_accept: + return false; + + accept: + std::string fnName = text; + size_t indexFnName = 0; + + // this one is for the type. + for (auto& ch : text) { + ++indexFnName; + + if (ch == '\t') break; + + if (ch == ' ') break; + } + + fnName = text.substr(indexFnName); + + if (text.find("return ") != std::string::npos) { + text.erase(0, text.find("return ")); + break; + } + + if (text.ends_with(";") && text.find("return") == std::string::npos) + goto LC_write_assembly; + else if (text.size() <= indexFnName) + Detail::print_error("Invalid function name: " + fnName, file); + + indexFnName = 0; + + for (auto& ch : fnName) { + if (ch == ' ' || ch == '\t') { + if (fnName[indexFnName - 1] != ')') + Detail::print_error("Invalid function name: " + fnName, file); + + if ((indexFnName + 1) != fnName.size()) + Detail::print_error("Extra characters after function name: " + fnName, file); + } + + ++indexFnName; + } + + syntax_tree.fUserValue = "public_segment .code64 __LIBCOMPILER_" + fnName + "\n"; + ++kFunctionEmbedLevel; + + kOriginMap.push_back({"__LIBCOMPILER_" + fnName, kOrigin}); + + break; + + LC_write_assembly: + auto it = std::find_if(kOriginMap.begin(), kOriginMap.end(), + [&fnName](std::pair<std::string, std::uintptr_t> pair) -> bool { + return fnName == pair.first; + }); + + std::stringstream ss; + ss << std::hex << it->second; + + if (it != kOriginMap.end()) { + syntax_tree.fUserValue = "jmp " + ss.str() + "\n"; + kOrigin += 1UL; + } + } + case LibCompiler::KeywordKind::kKeywordKindFunctionEnd: { + if (kOnClassScope) --kOnClassScope; + + if (text.ends_with(";")) break; + + --kFunctionEmbedLevel; + + if (kRegisterMap.size() > kRegisterList.size()) { + --kFunctionEmbedLevel; + } + + if (kFunctionEmbedLevel < 1) kRegisterMap.clear(); + + break; + } + case LibCompiler::KeywordKind::kKeywordKindEndInstr: + case LibCompiler::KeywordKind::kKeywordKindVariableInc: + case LibCompiler::KeywordKind::kKeywordKindVariableDec: + case LibCompiler::KeywordKind::kKeywordKindVariableAssign: { + std::string valueOfVar = ""; + + if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) { + valueOfVar = text.substr(text.find("+=") + 2); + } else if (keyword.first.keyword_kind == + LibCompiler::KeywordKind::kKeywordKindVariableDec) { + valueOfVar = text.substr(text.find("-=") + 2); + } else if (keyword.first.keyword_kind == + LibCompiler::KeywordKind::kKeywordKindVariableAssign) { + valueOfVar = text.substr(text.find("=") + 1); + } else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) { + break; + } + + while (valueOfVar.find(";") != std::string::npos && + keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindEndInstr) { + valueOfVar.erase(valueOfVar.find(";")); + } + + std::string varName = text; + + if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) { + varName.erase(varName.find("+=")); + } else if (keyword.first.keyword_kind == + LibCompiler::KeywordKind::kKeywordKindVariableDec) { + varName.erase(varName.find("-=")); + } else if (keyword.first.keyword_kind == + LibCompiler::KeywordKind::kKeywordKindVariableAssign) { + varName.erase(varName.find("=")); + } else if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) { + varName.erase(varName.find(";")); + } + + static Boolean typeFound = false; + + for (auto& keyword : kKeywords) { + if (keyword.keyword_kind == LibCompiler::kKeywordKindType) { + if (text.find(keyword.keyword_name) != std::string::npos) { + if (text[text.find(keyword.keyword_name)] == ' ') { + typeFound = false; + continue; + } + + typeFound = true; + } + } + } + + std::string instr = "mov "; + + if (typeFound && + keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableInc && + keyword.first.keyword_kind != LibCompiler::KeywordKind::kKeywordKindVariableDec) { + if (kRegisterMap.size() > kRegisterList.size()) { + ++kFunctionEmbedLevel; + } + + while (varName.find(" ") != std::string::npos) { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) { + varName.erase(varName.find("\t"), 1); + } + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) { + if (i > valueOfVar.size()) break; + + valueOfVar.erase(i, 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + if (valueOfVar == cTrueVal) { + valueOfVar = "1"; + } else if (valueOfVar == cFalseVal) { + valueOfVar = "0"; + } + + std::size_t indexRight = 0UL; + + for (auto pairRight : kRegisterMap) { + ++indexRight; + + if (pairRight != valueOfVar) { + if (valueOfVar[0] == '\"') { + syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + + ": db " + valueOfVar + ", 0\n\n"; + syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + + "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; + kOrigin += 1UL; + } else { + syntax_tree.fUserValue = + instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + kOrigin += 1UL; + } + + goto done; + } + } + + if (((int) indexRight - 1) < 0) { + if (valueOfVar[0] == '\"') { + syntax_tree.fUserValue = "segment .data64 __LIBCOMPILER_LOCAL_VAR_" + varName + + ": db " + valueOfVar + ", 0\n"; + syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + + "__LIBCOMPILER_LOCAL_VAR_" + varName + "\n"; + kOrigin += 1UL; + } else { + syntax_tree.fUserValue = + instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + kOrigin += 1UL; + } + + goto done; + } + + if (valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && !isdigit(valueOfVar[0])) { + for (auto pair : kRegisterMap) { + if (pair == valueOfVar) goto done; + } + + Detail::print_error("Variable not declared: " + varName, file); + return false; + } + + done: + for (auto& keyword : kKeywords) { + if (keyword.keyword_kind == LibCompiler::kKeywordKindType && + varName.find(keyword.keyword_name) != std::string::npos) { + varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); + break; + } + } + + kRegisterMap.push_back(varName); + + break; + } + + if (kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == LibCompiler::kKeywordKindTypePtr) { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindEndInstr) { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == LibCompiler::KeywordKind::kKeywordKindVariableInc) { + instr = "add "; + } else if (keyword.first.keyword_kind == + LibCompiler::KeywordKind::kKeywordKindVariableDec) { + instr = "sub "; + } + + std::string varErrCpy = varName; + + while (varName.find(" ") != std::string::npos) { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) { + varName.erase(varName.find("\t"), 1); + } + + std::size_t indxReg = 0UL; + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) { + if (i > valueOfVar.size()) break; + + valueOfVar.erase(i, 1); + } + + while (valueOfVar.find(" ") != std::string::npos) { + valueOfVar.erase(valueOfVar.find(" "), 1); + } + + while (valueOfVar.find("\t") != std::string::npos) { + valueOfVar.erase(valueOfVar.find("\t"), 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + /// interpet boolean values, since we're on C++ + + if (valueOfVar == cTrueVal) { + valueOfVar = "1"; + } else if (valueOfVar == cFalseVal) { + valueOfVar = "0"; + } + + for (auto pair : kRegisterMap) { + ++indxReg; + + if (pair != varName) continue; + + std::size_t indexRight = 0ul; + + for (auto pairRight : kRegisterMap) { + ++indexRight; + + if (pairRight != varName) { + syntax_tree.fUserValue = + instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + kOrigin += 1UL; + continue; + } + + syntax_tree.fUserValue = + instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n"; + kOrigin += 1UL; + break; + } + + break; + } + + if (syntax_tree.fUserValue.empty()) { + Detail::print_error("Variable not declared: " + varName, file); + } + + break; + } + case LibCompiler::KeywordKind::kKeywordKindReturn: { + try { + auto pos = text.find("return") + strlen("return") + 1; + std::string subText = text.substr(pos); + subText = subText.erase(subText.find(";")); + size_t indxReg = 0UL; + + if (subText[0] != '\"' && subText[0] != '\'') { + if (!isdigit(subText[0])) { + for (auto pair : kRegisterMap) { + ++indxReg; + + if (pair != subText) continue; + + syntax_tree.fUserValue = "mov rax, " + kRegisterList[indxReg - 1] + "\nret\n"; + kOrigin += 1UL; + + break; + } + } else { + syntax_tree.fUserValue = "mov rax, " + subText + "\nret\n"; + kOrigin += 1UL; + + break; + } + } else { + syntax_tree.fUserValue = "__LIBCOMPILER_LOCAL_RETURN_STRING: db " + subText + + ", 0\nmov rcx, __LIBCOMPILER_LOCAL_RETURN_STRING\n"; + syntax_tree.fUserValue += "mov rax, rcx\nret\n"; + kOrigin += 1UL; + + break; + } + + if (syntax_tree.fUserValue.empty()) { + if (subText.find("(") != std::string::npos) { + subText.erase(subText.find("(")); + + auto it = + std::find_if(kOriginMap.begin(), kOriginMap.end(), + [&subText](std::pair<std::string, std::uintptr_t> pair) -> bool { + return pair.first.find(subText) != std::string::npos; + }); + + if (it == kOriginMap.end()) + Detail::print_error("Invalid return value: " + subText, file); + + std::stringstream ss; + ss << it->second; + + syntax_tree.fUserValue = "jmp " + ss.str() + "\nret\n"; + kOrigin += 1UL; + break; + } + } + + break; + } catch (...) { + syntax_tree.fUserValue = "ret\n"; + kOrigin += 1UL; + } + } + default: { + break; + } + } + + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.push_back(syntax_tree); + } lc_compile_ok: - return true; + return true; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -875,295 +753,275 @@ lc_compile_ok: ///////////////////////////////////////////////////////////////////////////////////////// -class AssemblyCPlusPlusInterface final ASSEMBLY_INTERFACE -{ -public: - explicit AssemblyCPlusPlusInterface() = default; - ~AssemblyCPlusPlusInterface() override = default; +class AssemblyCPlusPlusInterface final ASSEMBLY_INTERFACE { + public: + explicit AssemblyCPlusPlusInterface() = default; + ~AssemblyCPlusPlusInterface() override = default; - LIBCOMPILER_COPY_DEFAULT(AssemblyCPlusPlusInterface); + LIBCOMPILER_COPY_DEFAULT(AssemblyCPlusPlusInterface); - [[maybe_unused]] static Int32 Arch() noexcept - { - return LibCompiler::AssemblyFactory::kArchAMD64; - } + [[maybe_unused]] static Int32 Arch() noexcept { return LibCompiler::AssemblyFactory::kArchAMD64; } - Int32 CompileToFormat(std::string& src, Int32 arch) override - { - if (arch != AssemblyCPlusPlusInterface::Arch()) - return 1; + Int32 CompileToFormat(std::string& src, Int32 arch) override { + if (arch != AssemblyCPlusPlusInterface::Arch()) return 1; - if (kCompilerFrontend == nullptr) - return 1; + if (kCompilerFrontend == nullptr) return 1; - /* @brief copy contents wihtout extension */ - std::string src_file = src; - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + /* @brief copy contents wihtout extension */ + std::string src_file = src; + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - const char* cExts[] = kAsmFileExts; + const char* cExts[] = kAsmFileExts; - std::string dest = src_file; - dest += cExts[2]; + std::string dest = src_file; + dest += cExts[2]; - if (dest.empty()) - { - dest = "CXX-LibCompiler-"; + if (dest.empty()) { + dest = "CXX-LibCompiler-"; - std::random_device rd; - auto seed_data = std::array<int, std::mt19937::state_size>{}; + 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::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); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); - auto gen = uuids::uuid_random_generator(generator); + auto gen = uuids::uuid_random_generator(generator); - auto id = gen(); - dest += uuids::to_string(id); - } + auto id = gen(); + dest += uuids::to_string(id); + } - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - auto fmt = LibCompiler::current_date(); + auto fmt = LibCompiler::current_date(); - (*kState.fOutputAssembly) << "; Repository Path: /" << src_file << "\n"; + (*kState.fOutputAssembly) << "; Repository Path: /" << src_file << "\n"; - std::filesystem::path path = std::filesystem::path("./"); + std::filesystem::path path = std::filesystem::path("./"); - while (path != Detail::expand_home(std::filesystem::path("~"))) - { - for (auto const& dir_entry : std::filesystem::recursive_directory_iterator{path}) - { - if (dir_entry.is_directory() && - dir_entry.path().string().find(".git") != std::string::npos) - goto break_loop; - } + while (path != Detail::expand_home(std::filesystem::path("~"))) { + for (auto const& dir_entry : std::filesystem::recursive_directory_iterator{path}) { + if (dir_entry.is_directory() && dir_entry.path().string().find(".git") != std::string::npos) + goto break_loop; + } - path = path.parent_path(); - break_loop: - (*kState.fOutputAssembly) << "; Repository Style: Git\n"; - break; - } + path = path.parent_path(); + break_loop: + (*kState.fOutputAssembly) << "; Repository Style: Git\n"; + break; + } - std::stringstream stream; - stream << kOrigin; - std::string result(stream.str()); + std::stringstream stream; + stream << kOrigin; + std::string result(stream.str()); - (*kState.fOutputAssembly) - << "; Assembler Dialect: AMD64 LibCompiler Assembler. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; - (*kState.fOutputAssembly) << "#bits 64\n#org " + result - << "\n"; + (*kState.fOutputAssembly) + << "; Assembler Dialect: AMD64 LibCompiler Assembler. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; + (*kState.fOutputAssembly) << "#bits 64\n#org " + result << "\n"; - kState.fSyntaxTree = new LibCompiler::SyntaxLeafList(); + kState.fSyntaxTree = new LibCompiler::SyntaxLeafList(); - // =================================== - // Parse source file. - // =================================== + // =================================== + // Parse source file. + // =================================== - std::string line_source; + std::string line_source; - while (std::getline(src_fp, line_source)) - { - kCompilerFrontend->Compile(line_source, src); - } + while (std::getline(src_fp, line_source)) { + kCompilerFrontend->Compile(line_source, src); + } - for (auto& ast_generated : kState.fSyntaxTree->fLeafList) - { - (*kState.fOutputAssembly) << ast_generated.fUserValue; - } + for (auto& ast_generated : kState.fSyntaxTree->fLeafList) { + (*kState.fOutputAssembly) << ast_generated.fUserValue; + } - kState.fOutputAssembly->flush(); - kState.fOutputAssembly->close(); + kState.fOutputAssembly->flush(); + kState.fOutputAssembly->close(); - delete kState.fSyntaxTree; - kState.fSyntaxTree = nullptr; + delete kState.fSyntaxTree; + kState.fSyntaxTree = nullptr; - if (kAcceptableErrors > 0) - return 1; + if (kAcceptableErrors > 0) return 1; - return kExitOK; - } + return kExitOK; + } }; ///////////////////////////////////////////////////////////////////////////////////////// -static void cxx_print_help() -{ - kSplashCxx(); - kPrintF("%s", "No help available, see:\n"); - kPrintF("%s", "nekernel.org/docs/cxxdrv\n"); +static void cxx_print_help() { + kSplashCxx(); + kPrintF("%s", "No help available, see:\n"); + kPrintF("%s", "nekernel.org/docs/cxxdrv\n"); } ///////////////////////////////////////////////////////////////////////////////////////// -#define kExtListCxx \ - { \ - ".cpp", ".cxx", ".cc", ".c++", ".cp" \ - } - -LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) -{ - Boolean skip = false; - - kKeywords.push_back({.keyword_name = "if", .keyword_kind = LibCompiler::kKeywordKindIf}); - kKeywords.push_back({.keyword_name = "else", .keyword_kind = LibCompiler::kKeywordKindElse}); - kKeywords.push_back({.keyword_name = "else if", .keyword_kind = LibCompiler::kKeywordKindElseIf}); - - kKeywords.push_back({.keyword_name = "class", .keyword_kind = LibCompiler::kKeywordKindClass}); - kKeywords.push_back({.keyword_name = "struct", .keyword_kind = LibCompiler::kKeywordKindClass}); - kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = LibCompiler::kKeywordKindNamespace}); - kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = LibCompiler::kKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "using", .keyword_kind = LibCompiler::kKeywordKindTypedef}); - kKeywords.push_back({.keyword_name = "{", .keyword_kind = LibCompiler::kKeywordKindBodyStart}); - kKeywords.push_back({.keyword_name = "}", .keyword_kind = LibCompiler::kKeywordKindBodyEnd}); - kKeywords.push_back({.keyword_name = "auto", .keyword_kind = LibCompiler::kKeywordKindVariable}); - kKeywords.push_back({.keyword_name = "int", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "Boolean", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "short", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "char", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "long", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "float", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "double", .keyword_kind = LibCompiler::kKeywordKindType}); - kKeywords.push_back({.keyword_name = "void", .keyword_kind = LibCompiler::kKeywordKindType}); - - kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = LibCompiler::kKeywordKindVariablePtr}); - kKeywords.push_back({.keyword_name = "int*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "Boolean*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "short*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "char*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "long*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "float*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "double*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - kKeywords.push_back({.keyword_name = "void*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); - - kKeywords.push_back({.keyword_name = "(", .keyword_kind = LibCompiler::kKeywordKindFunctionStart}); - kKeywords.push_back({.keyword_name = ")", .keyword_kind = LibCompiler::kKeywordKindFunctionEnd}); - kKeywords.push_back({.keyword_name = "=", .keyword_kind = LibCompiler::kKeywordKindVariableAssign}); - kKeywords.push_back({.keyword_name = "+=", .keyword_kind = LibCompiler::kKeywordKindVariableInc}); - kKeywords.push_back({.keyword_name = "-=", .keyword_kind = LibCompiler::kKeywordKindVariableDec}); - kKeywords.push_back({.keyword_name = "const", .keyword_kind = LibCompiler::kKeywordKindConstant}); - kKeywords.push_back({.keyword_name = "*", .keyword_kind = LibCompiler::kKeywordKindPtr}); - kKeywords.push_back({.keyword_name = "->", .keyword_kind = LibCompiler::kKeywordKindPtrAccess}); - kKeywords.push_back({.keyword_name = ".", .keyword_kind = LibCompiler::kKeywordKindAccess}); - kKeywords.push_back({.keyword_name = ",", .keyword_kind = LibCompiler::kKeywordKindArgSeparator}); - kKeywords.push_back({.keyword_name = ";", .keyword_kind = LibCompiler::kKeywordKindEndInstr}); - kKeywords.push_back({.keyword_name = ":", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "public:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "private:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "final", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); - kKeywords.push_back({.keyword_name = "return", .keyword_kind = LibCompiler::kKeywordKindReturn}); - kKeywords.push_back({.keyword_name = "--*", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "*/", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineStart}); - kKeywords.push_back({.keyword_name = "--/", .keyword_kind = LibCompiler::kKeywordKindCommentInline}); - kKeywords.push_back({.keyword_name = "==", .keyword_kind = LibCompiler::kKeywordKindEq}); - kKeywords.push_back({.keyword_name = "!=", .keyword_kind = LibCompiler::kKeywordKindNotEq}); - kKeywords.push_back({.keyword_name = ">=", .keyword_kind = LibCompiler::kKeywordKindGreaterEq}); - kKeywords.push_back({.keyword_name = "<=", .keyword_kind = LibCompiler::kKeywordKindLessEq}); - - kFactory.Mount(new AssemblyCPlusPlusInterface()); - kCompilerFrontend = new CompilerFrontendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) - { - if (argv[index][0] == '-') - { - if (skip) - { - skip = false; - continue; - } - - if (strcmp(argv[index], "-version") == 0) - { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "-cxx-verbose") == 0) - { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0) - { - cxx_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "-cxx-dialect") == 0) - { - if (kCompilerFrontend) - std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "-max-err") == 0) - { - try - { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) - { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - Detail::print_error(err, "cxxdrv"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - Boolean found = false; - - for (std::string ext : exts) - { - if (argv_i.find(ext) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - if (kState.fVerbose) - { - Detail::print_error(argv_i + " is not a valid C++ source.\n", "cxxdrv"); - } - - return 1; - } - - std::cout << "CPlusPlusCompilerAMD64: Building: " << argv[index] << std::endl; - - if (kFactory.Compile(argv_i, kMachine) != kExitOK) - return 1; - } - - return kExitOK; +#define kExtListCxx \ + { ".cpp", ".cxx", ".cc", ".c++", ".cp" } + +LIBCOMPILER_MODULE(CompilerCPlusPlusAMD64) { + Boolean skip = false; + + kKeywords.push_back({.keyword_name = "if", .keyword_kind = LibCompiler::kKeywordKindIf}); + kKeywords.push_back({.keyword_name = "else", .keyword_kind = LibCompiler::kKeywordKindElse}); + kKeywords.push_back({.keyword_name = "else if", .keyword_kind = LibCompiler::kKeywordKindElseIf}); + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = LibCompiler::kKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = LibCompiler::kKeywordKindClass}); + kKeywords.push_back( + {.keyword_name = "namespace", .keyword_kind = LibCompiler::kKeywordKindNamespace}); + kKeywords.push_back( + {.keyword_name = "typedef", .keyword_kind = LibCompiler::kKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = LibCompiler::kKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = LibCompiler::kKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = LibCompiler::kKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = LibCompiler::kKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "Boolean", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = LibCompiler::kKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = LibCompiler::kKeywordKindType}); + + kKeywords.push_back( + {.keyword_name = "auto*", .keyword_kind = LibCompiler::kKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back( + {.keyword_name = "Boolean*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back( + {.keyword_name = "unsigned*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back( + {.keyword_name = "double*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = LibCompiler::kKeywordKindTypePtr}); + + kKeywords.push_back( + {.keyword_name = "(", .keyword_kind = LibCompiler::kKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = LibCompiler::kKeywordKindFunctionEnd}); + kKeywords.push_back( + {.keyword_name = "=", .keyword_kind = LibCompiler::kKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = LibCompiler::kKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = LibCompiler::kKeywordKindVariableDec}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = LibCompiler::kKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = LibCompiler::kKeywordKindPtr}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = LibCompiler::kKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = LibCompiler::kKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = LibCompiler::kKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = LibCompiler::kKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); + kKeywords.push_back( + {.keyword_name = "public:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); + kKeywords.push_back( + {.keyword_name = "private:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); + kKeywords.push_back( + {.keyword_name = "protected:", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); + kKeywords.push_back( + {.keyword_name = "final", .keyword_kind = LibCompiler::kKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = LibCompiler::kKeywordKindReturn}); + kKeywords.push_back( + {.keyword_name = "--*", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineStart}); + kKeywords.push_back( + {.keyword_name = "*/", .keyword_kind = LibCompiler::kKeywordKindCommentMultiLineStart}); + kKeywords.push_back( + {.keyword_name = "--/", .keyword_kind = LibCompiler::kKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = LibCompiler::kKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = LibCompiler::kKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = LibCompiler::kKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = LibCompiler::kKeywordKindLessEq}); + + kFactory.Mount(new AssemblyCPlusPlusInterface()); + kCompilerFrontend = new CompilerFrontendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) { + if (argv[index][0] == '-') { + if (skip) { + skip = false; + continue; + } + + if (strcmp(argv[index], "-version") == 0) { + kSplashCxx(); + return kExitOK; + } + + if (strcmp(argv[index], "-cxx-verbose") == 0) { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0) { + cxx_print_help(); + + return kExitOK; + } + + if (strcmp(argv[index], "-cxx-dialect") == 0) { + if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; + + return kExitOK; + } + + if (strcmp(argv[index], "-max-err") == 0) { + try { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + Detail::print_error(err, "cxxdrv"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + Boolean found = false; + + for (std::string ext : exts) { + if (argv_i.find(ext) != std::string::npos) { + found = true; + break; + } + } + + if (!found) { + if (kState.fVerbose) { + Detail::print_error(argv_i + " is not a valid C++ source.\n", "cxxdrv"); + } + + return 1; + } + + std::cout << "CPlusPlusCompilerAMD64: Building: " << argv[index] << std::endl; + + if (kFactory.Compile(argv_i, kMachine) != kExitOK) return 1; + } + + return kExitOK; } // Last rev 8-1-24 diff --git a/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc b/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc index 336ca5a..aa3407a 100644 --- a/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc +++ b/dev/LibCompiler/src/CPlusPlusCompilerPreProcessor.cc @@ -9,8 +9,8 @@ /// BUGS: 0 -#include <LibCompiler/Parser.h> #include <LibCompiler/ErrorID.h> +#include <LibCompiler/Parser.h> #include <algorithm> #include <filesystem> #include <fstream> @@ -32,64 +32,56 @@ typedef Int32 (*bpp_parser_fn_t)(std::string& line, std::ifstream& hdr_file, std ///////////////////////////////////////////////////////////////////////////////////////// -namespace Detail -{ - enum - { - kEqual, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, - }; - - struct bpp_macro_condition final - { - int32_t fType; - std::string fTypeName; - }; - - struct bpp_macro final - { - std::vector<std::string> fArgs; - std::string fName; - std::string fValue; - - void Print() - { - std::cout << "name: " << fName << "\n"; - std::cout << "value: " << fValue << "\n"; - - for (auto& arg : fArgs) - { - std::cout << "arg: " << arg << "\n"; - } - } - }; - - class bpp_pragma final - { - public: - explicit bpp_pragma() = default; - ~bpp_pragma() = default; - - LIBCOMPILER_COPY_DEFAULT(bpp_pragma); - - std::string fMacroName; - bpp_parser_fn_t fParse; - }; -} // namespace Detail - -static std::vector<std::string> kFiles; +namespace Detail { +enum { + kEqual, + kGreaterEqThan, + kLesserEqThan, + kGreaterThan, + kLesserThan, + kNotEqual, +}; + +struct bpp_macro_condition final { + int32_t fType; + std::string fTypeName; +}; + +struct bpp_macro final { + std::vector<std::string> fArgs; + std::string fName; + std::string fValue; + + void Print() { + std::cout << "name: " << fName << "\n"; + std::cout << "value: " << fValue << "\n"; + + for (auto& arg : fArgs) { + std::cout << "arg: " << arg << "\n"; + } + } +}; + +class bpp_pragma final { + public: + explicit bpp_pragma() = default; + ~bpp_pragma() = default; + + LIBCOMPILER_COPY_DEFAULT(bpp_pragma); + + std::string fMacroName; + bpp_parser_fn_t fParse; +}; +} // namespace Detail + +static std::vector<std::string> kFiles; static std::vector<Detail::bpp_macro> kMacros; -static std::vector<std::string> kIncludes; +static std::vector<std::string> kIncludes; static std::string kWorkingDir; -static std::vector<std::string> kKeywords = { - "include", "if", "pragma", "def", "elif", - "ifdef", "ifndef", "else", "warning", "error"}; +static std::vector<std::string> kKeywords = {"include", "if", "pragma", "def", "elif", + "ifdef", "ifndef", "else", "warning", "error"}; #define kKeywordCxxCnt kKeywords.size() @@ -100,182 +92,145 @@ static std::vector<std::string> kKeywords = { ///////////////////////////////////////////////////////////////////////////////////////// -int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, - Detail::bpp_macro& macro, - bool& inactive_code, - bool& defined, - std::string& 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) != std::string::npos) - { - if (macro.fValue == "0") - { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } - else if (cond.fType == Detail::kNotEqual) - { - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != std::string::npos) - { - if (substr_macro.find(macro.fValue) != std::string::npos) - { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - auto substr_macro = - macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - std::string number; - - for (auto& macro_num : kMacros) - { - if (substr_macro.find(macro_num.fName) != std::string::npos) - { - for (size_t i = 0; i < macro_num.fName.size(); ++i) - { - if (isdigit(macro_num.fValue[i])) - { - number += macro_num.fValue[i]; - } - else - { - number.clear(); - break; - } - } - - break; - } - } - - size_t y = 2; - - /* last try */ - for (; y < macro_str.size(); y++) - { - if (isdigit(macro_str[y])) - { - for (size_t x = y; x < macro_str.size(); x++) - { - if (macro_str[x] == ' ') - break; - - number += macro_str[x]; - } - - break; - } - } - - size_t rhs = atol(macro.fValue.c_str()); - size_t lhs = atol(number.c_str()); - - if (lhs == 0) - { - number.clear(); - ++y; - - for (; y < macro_str.size(); y++) - { - if (isdigit(macro_str[y])) - { - for (size_t x = y; x < macro_str.size(); x++) - { - if (macro_str[x] == ' ') - break; - - number += macro_str[x]; - } - - break; - } - } - - lhs = atol(number.c_str()); - } - - if (cond.fType == 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; +int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, + bool& inactive_code, bool& defined, std::string& 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) != std::string::npos) { + if (macro.fValue == "0") { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + } else if (cond.fType == Detail::kNotEqual) { + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + if (substr_macro.find(macro.fName) != std::string::npos) { + if (substr_macro.find(macro.fValue) != std::string::npos) { + defined = false; + inactive_code = true; + + return 1; + } + + defined = true; + inactive_code = false; + + return 1; + } + + return 0; + } + + auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); + + std::string number; + + for (auto& macro_num : kMacros) { + if (substr_macro.find(macro_num.fName) != std::string::npos) { + for (size_t i = 0; i < macro_num.fName.size(); ++i) { + if (isdigit(macro_num.fValue[i])) { + number += macro_num.fValue[i]; + } else { + number.clear(); + break; + } + } + + break; + } + } + + size_t y = 2; + + /* last try */ + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + size_t rhs = atol(macro.fValue.c_str()); + size_t lhs = atol(number.c_str()); + + if (lhs == 0) { + number.clear(); + ++y; + + for (; y < macro_str.size(); y++) { + if (isdigit(macro_str[y])) { + for (size_t x = y; x < macro_str.size(); x++) { + if (macro_str[x] == ' ') break; + + number += macro_str[x]; + } + + break; + } + } + + lhs = atol(number.c_str()); + } + + if (cond.fType == 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; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -293,613 +248,484 @@ std::vector<std::string> kAllIncludes; ///////////////////////////////////////////////////////////////////////////////////////// -void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) -{ - std::string hdr_line; - std::string line_after_include; - - bool inactive_code = false; - bool defined = false; - - try - { - while (std::getline(hdr_file, hdr_line)) - { - if (inactive_code) - { - if (hdr_line.find("#endif") == std::string::npos) - { - continue; - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("#endif") != std::string::npos) - { - - inactive_code = false; - } - - if (hdr_line.find("*/") != std::string::npos) - { - continue; - } - } - - if (hdr_line.find("--/") != std::string::npos) - { - hdr_line.erase(hdr_line.find("--/")); - } - - if (hdr_line.find("--*") != std::string::npos) - { - inactive_code = true; - // get rid of comment. - hdr_line.erase(hdr_line.find("--*")); - } - - /// BPP 'brief' documentation. - if (hdr_line.find("@brief") != std::string::npos) - { - hdr_line.erase(hdr_line.find("@brief")); - - // TODO: Write an <file_name>.html or append to it. - } - - if (hdr_line[0] == kMacroPrefix && - hdr_line.find("endif") != std::string::npos) - { - if (!defined && inactive_code) - { - inactive_code = false; - defined = false; - - continue; - } - - continue; - } - - if (!defined && inactive_code) - { - continue; - } - - if (defined && inactive_code) - { - continue; - } - - for (auto macro : kMacros) - { - if (LibCompiler::find_word(hdr_line, macro.fName)) - { - if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != LibCompiler::String::npos) - { - if (!macro.fArgs.empty()) - { - LibCompiler::String symbol_val = macro.fValue; - std::vector<LibCompiler::String> args; - - size_t x_arg_indx = 0; - - LibCompiler::String line_after_define = hdr_line; - LibCompiler::String str_arg; - - if (line_after_define.find("(") != LibCompiler::String::npos) - { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) - { - if (subc == ' ' || subc == '\t') - continue; - - if (subc == ',' || subc == ')') - { - if (str_arg.empty()) - continue; - - args.push_back(str_arg); - - str_arg.clear(); - - continue; - } - - str_arg.push_back(subc); - } - } - - for (auto arg : macro.fArgs) - { - if (symbol_val.find(macro.fArgs[x_arg_indx]) != LibCompiler::String::npos) - { - symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), macro.fArgs[x_arg_indx].size(), - args[x_arg_indx]); - ++x_arg_indx; - } - else - { - throw std::runtime_error("bpp: 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 ") != std::string::npos) - { - auto line_after_define = - hdr_line.substr(hdr_line.find("define ") + strlen("define ")); - - std::string macro_value; - std::string macro_key; - - std::size_t pos = 0UL; - - std::vector<std::string> args; - bool on_args = false; - - for (auto& ch : line_after_define) - { - ++pos; - - if (ch == '(') - { - on_args = true; - continue; - } - - if (ch == ')') - { - on_args = false; - continue; - } - - if (ch == '\\') - continue; - - if (on_args) - continue; - - if (ch == ' ') - { - for (size_t i = pos; i < line_after_define.size(); i++) - { - macro_value += line_after_define[i]; - } - - break; - } - - macro_key += ch; - } - - std::string str; - - if (line_after_define.find("(") != LibCompiler::String::npos) - { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) - { - if (subc == ',' || subc == ')') - { - if (str.empty()) - continue; - - args.push_back(str); - - str.clear(); - - continue; - } - - str.push_back(subc); - } - } - - 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") != std::string::npos) - { - auto line_after_ifndef = - hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - std::string macro; - - for (auto& ch : line_after_ifndef) - { - if (ch == ' ') - { - break; - } - - macro += ch; - } - - if (macro == "0") - { - defined = true; - inactive_code = false; - continue; - } - - if (macro == "1") - { - defined = false; - inactive_code = true; - - continue; - } - - bool found = false; - - defined = true; - inactive_code = false; - - for (auto& macro_ref : kMacros) - { - if (hdr_line.find(macro_ref.fName) != std::string::npos) - { - found = true; - break; - } - } - - if (found) - { - defined = false; - inactive_code = true; - - continue; - } - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != std::string::npos) - { - if (!defined && inactive_code) - { - inactive_code = false; - defined = true; - - continue; - } - else - { - defined = false; - inactive_code = true; - - continue; - } - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifdef") != std::string::npos) - { - auto line_after_ifdef = - hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - std::string macro; - - for (auto& ch : line_after_ifdef) - { - if (ch == ' ') - { - break; - } - - macro += ch; - } - - if (macro == "0") - { - defined = false; - inactive_code = true; - - continue; - } - - if (macro == "1") - { - defined = true; - inactive_code = false; - - continue; - } - - defined = false; - inactive_code = true; - - for (auto& macro_ref : kMacros) - { - if (hdr_line.find(macro_ref.fName) != std::string::npos) - { - defined = true; - inactive_code = false; - - break; - } - } - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != std::string::npos) - { - inactive_code = true; - - std::vector<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) != std::string::npos) - { - for (auto& found_macro : kMacros) - { - if (hdr_line.find(found_macro.fName) != std::string::npos) - { - good_to_go = - bpp_parse_if_condition(macro_condition, found_macro, - inactive_code, defined, hdr_line); - - break; - } - } - } - } - - if (good_to_go) - continue; - - auto line_after_if = - hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); - std::string macro; - - for (auto& ch : line_after_if) - { - if (ch == ' ') - { - break; - } - - macro += ch; - } - - if (macro == "0") - { - defined = false; - inactive_code = true; - continue; - } - - if (macro == "1") - { - defined = true; - inactive_code = false; - - continue; - } - - // last try, is it defined to be one? - for (auto& macro_ref : kMacros) - { - if (macro_ref.fName.find(macro) != std::string::npos && - macro_ref.fValue == "1") - { - inactive_code = false; - defined = true; - - break; - } - } - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != std::string::npos) - { - auto line_after_warning = - hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - std::string message; - - for (auto& ch : line_after_warning) - { - if (ch == '\r' || ch == '\n') - { - break; - } - - message += ch; - } - - std::cout << "warn: " << message << std::endl; - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != std::string::npos) - { - auto line_after_warning = - hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - std::string message; - - for (auto& ch : line_after_warning) - { - if (ch == '\r' || ch == '\n') - { - break; - } - - message += ch; - } - - throw std::runtime_error("error: " + message); - } - else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("include ") != std::string::npos) - { - line_after_include = - hdr_line.substr(hdr_line.find("include ") + strlen("include ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), - line_after_include); - - if (it != kAllIncludes.cend()) - { - continue; - } - - std::string path; - - kAllIncludes.push_back(line_after_include); - - bool enable = false; - bool not_local = false; - - for (auto& ch : line_after_include) - { - if (ch == ' ') - continue; - - if (ch == '<') - { - not_local = true; - enable = true; - - continue; - } - - if (ch == '\"') - { - not_local = false; - enable = true; - continue; - } - - if (enable) - { - path += ch; - } - } - - if (not_local) - { - bool open = false; - - if (path.ends_with('>')) - { - path.erase(path.find('>')); - } - - if (path.ends_with('"')) - { - path.erase(path.find('"')); - } - - for (auto& include : kIncludes) - { - std::string header_path = include; - header_path.push_back('-'); - header_path += path; - - std::ifstream header(header_path); - - if (!header.is_open()) - continue; - - open = true; - - bpp_parse_file(header, pp_out); - - break; - } - - if (!open) - { - throw std::runtime_error("bpp: no such include file: " + path); - } - } - else - { - std::ifstream header(path); - - if (!header.is_open()) - throw std::runtime_error("bpp: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } - else - { - std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) - << "\n"; - continue; - } - } - } - catch (std::out_of_range& oor) - { - return; - } +void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) { + std::string hdr_line; + std::string line_after_include; + + bool inactive_code = false; + bool defined = false; + + try { + while (std::getline(hdr_file, hdr_line)) { + if (inactive_code) { + if (hdr_line.find("#endif") == std::string::npos) { + continue; + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("#endif") != std::string::npos) { + inactive_code = false; + } + + if (hdr_line.find("*/") != std::string::npos) { + continue; + } + } + + if (hdr_line.find("--/") != std::string::npos) { + hdr_line.erase(hdr_line.find("--/")); + } + + if (hdr_line.find("--*") != std::string::npos) { + inactive_code = true; + // get rid of comment. + hdr_line.erase(hdr_line.find("--*")); + } + + /// BPP 'brief' documentation. + if (hdr_line.find("@brief") != std::string::npos) { + hdr_line.erase(hdr_line.find("@brief")); + + // TODO: Write an <file_name>.html or append to it. + } + + if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = false; + + continue; + } + + continue; + } + + if (!defined && inactive_code) { + continue; + } + + if (defined && inactive_code) { + continue; + } + + for (auto macro : kMacros) { + if (LibCompiler::find_word(hdr_line, macro.fName)) { + if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != + LibCompiler::String::npos) { + if (!macro.fArgs.empty()) { + LibCompiler::String symbol_val = macro.fValue; + std::vector<LibCompiler::String> args; + + size_t x_arg_indx = 0; + + LibCompiler::String line_after_define = hdr_line; + LibCompiler::String str_arg; + + if (line_after_define.find("(") != LibCompiler::String::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ' ' || subc == '\t') continue; + + if (subc == ',' || subc == ')') { + if (str_arg.empty()) continue; + + args.push_back(str_arg); + + str_arg.clear(); + + continue; + } + + str_arg.push_back(subc); + } + } + + for (auto arg : macro.fArgs) { + if (symbol_val.find(macro.fArgs[x_arg_indx]) != LibCompiler::String::npos) { + symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), + macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); + ++x_arg_indx; + } else { + throw std::runtime_error("bpp: 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 ") != std::string::npos) { + auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); + + std::string macro_value; + std::string macro_key; + + std::size_t pos = 0UL; + + std::vector<std::string> args; + bool on_args = false; + + for (auto& ch : line_after_define) { + ++pos; + + if (ch == '(') { + on_args = true; + continue; + } + + if (ch == ')') { + on_args = false; + continue; + } + + if (ch == '\\') continue; + + if (on_args) continue; + + if (ch == ' ') { + for (size_t i = pos; i < line_after_define.size(); i++) { + macro_value += line_after_define[i]; + } + + break; + } + + macro_key += ch; + } + + std::string str; + + if (line_after_define.find("(") != LibCompiler::String::npos) { + line_after_define.erase(0, line_after_define.find("(") + 1); + + for (auto& subc : line_after_define) { + if (subc == ',' || subc == ')') { + if (str.empty()) continue; + + args.push_back(str); + + str.clear(); + + continue; + } + + str.push_back(subc); + } + } + + 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") != std::string::npos) { + auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); + std::string macro; + + for (auto& ch : line_after_ifndef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = true; + inactive_code = false; + continue; + } + + if (macro == "1") { + defined = false; + inactive_code = true; + + continue; + } + + bool found = false; + + defined = true; + inactive_code = false; + + for (auto& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + found = true; + break; + } + } + + if (found) { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("else") != std::string::npos) { + if (!defined && inactive_code) { + inactive_code = false; + defined = true; + + continue; + } else { + defined = false; + inactive_code = true; + + continue; + } + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifdef") != std::string::npos) { + auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); + std::string macro; + + for (auto& ch : line_after_ifdef) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + defined = false; + inactive_code = true; + + for (auto& macro_ref : kMacros) { + if (hdr_line.find(macro_ref.fName) != std::string::npos) { + defined = true; + inactive_code = false; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("if") != std::string::npos) { + inactive_code = true; + + std::vector<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) != std::string::npos) { + for (auto& found_macro : kMacros) { + if (hdr_line.find(found_macro.fName) != std::string::npos) { + good_to_go = bpp_parse_if_condition(macro_condition, found_macro, inactive_code, + defined, hdr_line); + + break; + } + } + } + } + + if (good_to_go) continue; + + auto line_after_if = hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); + std::string macro; + + for (auto& ch : line_after_if) { + if (ch == ' ') { + break; + } + + macro += ch; + } + + if (macro == "0") { + defined = false; + inactive_code = true; + continue; + } + + if (macro == "1") { + defined = true; + inactive_code = false; + + continue; + } + + // last try, is it defined to be one? + for (auto& macro_ref : kMacros) { + if (macro_ref.fName.find(macro) != std::string::npos && macro_ref.fValue == "1") { + inactive_code = false; + defined = true; + + break; + } + } + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("warning") != std::string::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); + std::string message; + + for (auto& ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + std::cout << "warn: " << message << std::endl; + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("error") != std::string::npos) { + auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); + std::string message; + + for (auto& ch : line_after_warning) { + if (ch == '\r' || ch == '\n') { + break; + } + + message += ch; + } + + throw std::runtime_error("error: " + message); + } else if (hdr_line[0] == kMacroPrefix && hdr_line.find("include ") != std::string::npos) { + line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); + + kIncludeFile: + auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); + + if (it != kAllIncludes.cend()) { + continue; + } + + std::string path; + + kAllIncludes.push_back(line_after_include); + + bool enable = false; + bool not_local = false; + + for (auto& ch : line_after_include) { + if (ch == ' ') continue; + + if (ch == '<') { + not_local = true; + enable = true; + + continue; + } + + if (ch == '\"') { + not_local = false; + enable = true; + continue; + } + + if (enable) { + path += ch; + } + } + + if (not_local) { + bool open = false; + + if (path.ends_with('>')) { + path.erase(path.find('>')); + } + + if (path.ends_with('"')) { + path.erase(path.find('"')); + } + + for (auto& include : kIncludes) { + std::string header_path = include; + header_path.push_back('-'); + header_path += path; + + std::ifstream header(header_path); + + if (!header.is_open()) continue; + + open = true; + + bpp_parse_file(header, pp_out); + + break; + } + + if (!open) { + throw std::runtime_error("bpp: no such include file: " + path); + } + } else { + std::ifstream header(path); + + if (!header.is_open()) throw std::runtime_error("bpp: no such include file: " + path); + + bpp_parse_file(header, pp_out); + } + } else { + std::cerr << ("bpp: unknown pre-processor directive, " + hdr_line) << "\n"; + continue; + } + } + } catch (std::out_of_range& oor) { + return; + } } ///////////////////////////////////////////////////////////////////////////////////////// @@ -908,177 +734,157 @@ void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) ///////////////////////////////////////////////////////////////////////////////////////// -LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) -{ - try - { - bool skip = false; - bool double_skip = false; +LIBCOMPILER_MODULE(CPlusPlusPreprocessorMain) { + try { + bool skip = false; + bool double_skip = false; + + Detail::bpp_macro macro_1; + + macro_1.fName = "__true"; + macro_1.fValue = "1"; + + kMacros.push_back(macro_1); + + Detail::bpp_macro macro_unreachable; + + macro_unreachable.fName = "__unreachable"; + macro_unreachable.fValue = "__libcompiler_unreachable"; + + kMacros.push_back(macro_unreachable); + + Detail::bpp_macro macro_0; - Detail::bpp_macro macro_1; + macro_0.fName = "__false"; + macro_0.fValue = "0"; - macro_1.fName = "__true"; - macro_1.fValue = "1"; + kMacros.push_back(macro_0); - kMacros.push_back(macro_1); + Detail::bpp_macro macro_zka; - Detail::bpp_macro macro_unreachable; + macro_zka.fName = "__LIBCOMPILER__"; + macro_zka.fValue = "1"; - macro_unreachable.fName = "__unreachable"; - macro_unreachable.fValue = "__libcompiler_unreachable"; + kMacros.push_back(macro_zka); - kMacros.push_back(macro_unreachable); + Detail::bpp_macro macro_cxx; - Detail::bpp_macro macro_0; + macro_cxx.fName = "__cplusplus"; + macro_cxx.fValue = "202302L"; - macro_0.fName = "__false"; - macro_0.fValue = "0"; + kMacros.push_back(macro_cxx); - kMacros.push_back(macro_0); + Detail::bpp_macro macro_size_t; + macro_size_t.fName = "__SIZE_TYPE__"; + macro_size_t.fValue = "unsigned long long int"; - Detail::bpp_macro macro_zka; + kMacros.push_back(macro_size_t); - macro_zka.fName = "__LIBCOMPILER__"; - macro_zka.fValue = "1"; + macro_size_t.fName = "__UINT32_TYPE__"; + macro_size_t.fValue = "unsigned int"; - kMacros.push_back(macro_zka); + kMacros.push_back(macro_size_t); - Detail::bpp_macro macro_cxx; + macro_size_t.fName = "__UINTPTR_TYPE__"; + macro_size_t.fValue = "unsigned int"; - macro_cxx.fName = "__cplusplus"; - macro_cxx.fValue = "202302L"; + kMacros.push_back(macro_size_t); - kMacros.push_back(macro_cxx); + for (auto index = 1UL; index < argc; ++index) { + if (skip) { + skip = false; + continue; + } - Detail::bpp_macro macro_size_t; - macro_size_t.fName = "__SIZE_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; + if (double_skip) { + ++index; + double_skip = false; + continue; + } - kMacros.push_back(macro_size_t); + if (argv[index][0] == '-') { + if (strcmp(argv[index], "--bpp:ver") == 0) { + printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); + return 0; + } - macro_size_t.fName = "__UINT32_TYPE__"; - macro_size_t.fValue = "unsigned int"; + if (strcmp(argv[index], "--bpp:?") == 0) { + printf("%s\n", "NE Preprocessor Driver v1.11, (c) Amlal El Mahrouss"); + printf("%s\n", "--bpp:working-dir <path>: set directory to working path."); + printf("%s\n", "--bpp:include-dir <path>: add directory to include path."); + printf("%s\n", "--bpp:def <name> <value>: define a macro."); + printf("%s\n", "--bpp:ver: print the version."); + printf("%s\n", "--bpp:?: show help (this current command)."); - kMacros.push_back(macro_size_t); + return 0; + } - macro_size_t.fName = "__UINTPTR_TYPE__"; - macro_size_t.fValue = "unsigned int"; + if (strcmp(argv[index], "--bpp:include-dir") == 0) { + std::string inc = argv[index + 1]; - kMacros.push_back(macro_size_t); + skip = true; - for (auto index = 1UL; index < argc; ++index) - { - if (skip) - { - skip = false; - continue; - } + kIncludes.push_back(inc); + } - if (double_skip) - { - ++index; - double_skip = false; - continue; - } + if (strcmp(argv[index], "--bpp:working-dir") == 0) { + std::string inc = argv[index + 1]; + skip = true; + kWorkingDir = inc; + } - if (argv[index][0] == '-') - { - if (strcmp(argv[index], "--bpp:ver") == 0) - { - printf("%s\n", "bpp v1.11, (c) Amlal El Mahrouss"); - return 0; - } + if (strcmp(argv[index], "--bpp:def") == 0 && argv[index + 1] != nullptr && + argv[index + 2] != nullptr) { + std::string macro_key = argv[index + 1]; - if (strcmp(argv[index], "--bpp:?") == 0) - { - printf("%s\n", "NE Preprocessor Driver v1.11, (c) Amlal El Mahrouss"); - printf("%s\n", "--bpp:working-dir <path>: set directory to working path."); - printf("%s\n", "--bpp:include-dir <path>: add directory to include path."); - printf("%s\n", "--bpp:def <name> <value>: define a macro."); - printf("%s\n", "--bpp:ver: print the version."); - printf("%s\n", "--bpp:?: show help (this current command)."); + std::string macro_value; + bool is_string = false; - return 0; - } + 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 += "\""; - if (strcmp(argv[index], "--bpp:include-dir") == 0) - { - std::string inc = argv[index + 1]; + break; + } + } - skip = true; + macro_value += argv[index + 2]; - kIncludes.push_back(inc); - } + if (is_string) macro_value += "\""; - if (strcmp(argv[index], "--bpp:working-dir") == 0) - { - std::string inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } + Detail::bpp_macro macro; + macro.fName = macro_key; + macro.fValue = macro_value; - if (strcmp(argv[index], "--bpp:def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) - { - std::string macro_key = argv[index + 1]; + kMacros.push_back(macro); - std::string macro_value; - bool is_string = false; + double_skip = true; + } - 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 += "\""; + continue; + } - break; - } - } + kFiles.emplace_back(argv[index]); + } - macro_value += argv[index + 2]; + if (kFiles.empty()) return LIBCOMPILER_EXEC_ERROR; - if (is_string) - macro_value += "\""; + for (auto& file : kFiles) { + if (!std::filesystem::exists(file)) continue; - Detail::bpp_macro macro; - macro.fName = macro_key; - macro.fValue = macro_value; + std::ifstream file_descriptor(file); + std::ofstream file_descriptor_pp(file + ".pp"); - kMacros.push_back(macro); + bpp_parse_file(file_descriptor, file_descriptor_pp); + } - double_skip = true; - } - - continue; - } + return 0; + } catch (const std::runtime_error& e) { + std::cout << e.what() << '\n'; + } - kFiles.emplace_back(argv[index]); - } - - if (kFiles.empty()) - return LIBCOMPILER_EXEC_ERROR; - - for (auto& file : kFiles) - { - if (!std::filesystem::exists(file)) - continue; - - std::ifstream file_descriptor(file); - std::ofstream file_descriptor_pp(file + ".pp"); - - bpp_parse_file(file_descriptor, file_descriptor_pp); - } - - return 0; - } - catch (const std::runtime_error& e) - { - std::cout << e.what() << '\n'; - } - - return 1; + return 1; } // Last rev 8-1-24 diff --git a/dev/LibCompiler/src/Detail/AsmUtils.h b/dev/LibCompiler/src/Detail/AsmUtils.h index 997564c..358700a 100644 --- a/dev/LibCompiler/src/Detail/AsmUtils.h +++ b/dev/LibCompiler/src/Detail/AsmUtils.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -11,106 +11,86 @@ using namespace LibCompiler; -namespace Detail -{ - extern void print_error(std::string reason, std::string file) noexcept; - extern void print_warning(std::string reason, std::string file) noexcept; -} // namespace Detail +namespace Detail { +extern void print_error(std::string reason, std::string file) noexcept; +extern void print_warning(std::string reason, std::string file) noexcept; +} // namespace Detail /// @brief Get Number from lineBuffer. /// @param lineBuffer the lineBuffer to fetch from. /// @param numberKey where to seek that number. /// @return -static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) -{ - auto pos = lineBuffer.find(numberKey) + numberKey.size(); - - while (lineBuffer[pos] == ' ') - { - ++pos; - } - - switch (lineBuffer[pos + 1]) - { - case 'x': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + lineBuffer, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) - { - kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) - { - if (errno != 0) - { - Detail::print_error("invalid binary number:" + lineBuffer, "LibCompiler"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) - { - kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) - { - if (errno != 0) - { - Detail::print_error("invalid octal number: " + lineBuffer, "LibCompiler"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) - { - kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) - { - if (errno != 0) - { - Detail::print_error("invalid hex number: " + lineBuffer, "LibCompiler"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) - { - kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) - << "\n"; - } - - return numOffset; - } - } +static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) { + auto pos = lineBuffer.find(numberKey) + numberKey.size(); + + while (lineBuffer[pos] == ' ') { + ++pos; + } + + switch (lineBuffer[pos + 1]) { + case 'x': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) { + if (errno != 0) { + Detail::print_error("invalid hex number: " + lineBuffer, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); + + if (kVerbose) { + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + case 'b': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) { + if (errno != 0) { + Detail::print_error("invalid binary number:" + lineBuffer, "LibCompiler"); + throw std::runtime_error("invalid_bin"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + case 'o': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) { + if (errno != 0) { + Detail::print_error("invalid octal number: " + lineBuffer, "LibCompiler"); + throw std::runtime_error("invalid_octal"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + default: { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + Detail::print_error("invalid hex number: " + lineBuffer, "LibCompiler"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); + + if (kVerbose) { + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + } } diff --git a/dev/LibCompiler/src/Detail/ClUtils.h b/dev/LibCompiler/src/Detail/ClUtils.h index fe788a2..024d0d2 100644 --- a/dev/LibCompiler/src/Detail/ClUtils.h +++ b/dev/LibCompiler/src/Detail/ClUtils.h @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ diff --git a/dev/LibCompiler/src/DynamicLinkerPEF.cc b/dev/LibCompiler/src/DynamicLinkerPEF.cc index 6410885..abbf364 100644 --- a/dev/LibCompiler/src/DynamicLinkerPEF.cc +++ b/dev/LibCompiler/src/DynamicLinkerPEF.cc @@ -1,9 +1,9 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved + Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved - @file DynamicLinker64PEF.cc - @brief: C++ 64-Bit PEF Linker. + @file DynamicLinker64PEF.cc + @brief: C++ 64-Bit PEF Linker. ------------------------------------------- */ @@ -31,756 +31,635 @@ #include <LibCompiler/AE.h> #include <cstdint> -#define kLinkerVersionStr "\e[0;97m NeKernel 64-Bit Linker (Preferred Executable) %s, (c) Amlal El Mahrouss 2024-2025, all rights reserved.\n" +#define kLinkerVersionStr \ + "\e[0;97m NeKernel 64-Bit Linker (Preferred Executable) %s, (c) Amlal El Mahrouss 2024-2025, " \ + "all rights reserved.\n" #define MemoryCopy(DST, SRC, SZ) memcpy(DST, SRC, SZ) -#define StringCompare(DST, SRC) strcmp(DST, SRC) +#define StringCompare(DST, SRC) strcmp(DST, SRC) -#define kPefNoCpu (0U) +#define kPefNoCpu (0U) #define kPefNoSubCpu (0U) -#define kStdOut (std::cout << "\e[0;31m" \ - << "ld64: " \ - << "\e[0;97m") +#define kStdOut (std::cout << "\e[0;31m" << "ld64: " << "\e[0;97m") #define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId (0x5046FF) -#define kLinkerAbiContainer "Container:ABI:" +#define kLinkerId (0x5046FF) +#define kLinkerAbiContainer "Container:ABI:" -#define kPrintF printf +#define kPrintF printf #define kLinkerSplash() kPrintF(kLinkerVersionStr, kDistVersion) /// @brief PEF stack size symbol. #define kLinkerStackSizeSymbol "__PEFSizeOfReserveStack" -namespace Detail -{ - struct DynamicLinkerBlob final - { - std::vector<CharType> mBlob{}; // PEF code/bss/data blob. - UIntPtr mOffset{0UL}; // the offset of the PEF container header... - }; -} // namespace Detail - -enum -{ - kABITypeStart = 0x1010, /* Invalid ABI start of ABI list. */ - kABITypeNE = 0x5046, /* PF (NeKernel's PEF ABI) */ - kABITypeInvalid = 0xFFFF, +namespace Detail { +struct DynamicLinkerBlob final { + std::vector<CharType> mBlob{}; // PEF code/bss/data blob. + UIntPtr mOffset{0UL}; // the offset of the PEF container header... }; +} // namespace Detail -static LibCompiler::String kOutput = "a.out"; -static Int32 kAbi = kABITypeNE; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = LibCompiler::kPefArchInvalid; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; -static Bool kVerbose = false; +enum { + kABITypeStart = 0x1010, /* Invalid ABI start of ABI list. */ + kABITypeNE = 0x5046, /* PF (NeKernel's PEF ABI) */ + kABITypeInvalid = 0xFFFF, +}; + +static LibCompiler::String kOutput = "a.out"; +static Int32 kAbi = kABITypeNE; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = LibCompiler::kPefArchInvalid; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; +static Bool kVerbose = false; /* ld64 is to be found, mld is to be found at runtime. */ static const CharType* kLdDefineSymbol = ":UndefinedSymbol:"; static const CharType* kLdDynamicSym = ":RuntimeSymbol:"; /* object code and list. */ -static std::vector<LibCompiler::String> kObjectList; +static std::vector<LibCompiler::String> kObjectList; static std::vector<Detail::DynamicLinkerBlob> kObjectBytes; -static uintptr_t kMIBCount = 8; +static uintptr_t kMIBCount = 8; static uintptr_t kByteCount = 1024; /// @brief NE 64-bit Linker. /// @note This linker is made for PEF executable, thus NE based OSes. -LIBCOMPILER_MODULE(DynamicLinker64PEF) -{ - bool is_executable = true; - - /** - * @brief parse flags and trigger options. - */ - for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) - { - if (StringCompare(argv[linker_arg], "-help") == 0) - { - kLinkerSplash(); - - kStdOut << "-version: Show linker version.\n"; - kStdOut << "-help: Show linker help.\n"; - kStdOut << "-ld-verbose: Enable linker trace.\n"; - kStdOut << "-dylib: Output as a Dyanmic PEF.\n"; - kStdOut << "-fat: Output as a FAT PEF.\n"; - kStdOut << "-32k: Output as a 32x0 PEF.\n"; - kStdOut << "-64k: Output as a 64x0 PEF.\n"; - kStdOut << "-amd64: Output as a AMD64 PEF.\n"; - kStdOut << "-rv64: Output as a RISC-V PEF.\n"; - kStdOut << "-power64: Output as a POWER PEF.\n"; - kStdOut << "-arm64: Output as a ARM64 PEF.\n"; - kStdOut << "-output: Select the output file name.\n"; - - return EXIT_SUCCESS; - } - else if (StringCompare(argv[linker_arg], "-version") == 0) - { - kLinkerSplash(); - return EXIT_SUCCESS; - } - else if (StringCompare(argv[linker_arg], "-fat-binary") == 0) - { - kFatBinaryEnable = true; - - continue; - } - else if (StringCompare(argv[linker_arg], "-64k") == 0) - { - kArch = LibCompiler::kPefArch64000; - - continue; - } - else if (StringCompare(argv[linker_arg], "-amd64") == 0) - { - kArch = LibCompiler::kPefArchAMD64; - - continue; - } - else if (StringCompare(argv[linker_arg], "-32k") == 0) - { - kArch = LibCompiler::kPefArch32000; - - continue; - } - else if (StringCompare(argv[linker_arg], "-power64") == 0) - { - kArch = LibCompiler::kPefArchPowerPC; - - continue; - } - else if (StringCompare(argv[linker_arg], "-riscv64") == 0) - { - kArch = LibCompiler::kPefArchRISCV; - - continue; - } - else if (StringCompare(argv[linker_arg], "-arm64") == 0) - { - kArch = LibCompiler::kPefArchARM64; - - continue; - } - else if (StringCompare(argv[linker_arg], "-ld-verbose") == 0) - { - kVerbose = true; - - continue; - } - else if (StringCompare(argv[linker_arg], "-dylib") == 0) - { - if (kOutput.empty()) - { - continue; - } - - if (kOutput.find(kPefExt) != LibCompiler::String::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } - else if (StringCompare(argv[linker_arg], "-output") == 0) - { - if ((linker_arg + 1) > argc) - continue; - - kOutput = argv[linker_arg + 1]; - ++linker_arg; - - continue; - } - else - { - if (argv[linker_arg][0] == '-') - { - kStdOut << "unknown flag: " << argv[linker_arg] << "\n"; - return EXIT_FAILURE; - } - - kObjectList.emplace_back(argv[linker_arg]); - - continue; - } - } - - if (kOutput.empty()) - { - kStdOut << "no output filename set." << std::endl; - return LIBCOMPILER_EXEC_ERROR; - } - else if (kObjectList.empty()) - { - kStdOut << "no input files." << std::endl; - return LIBCOMPILER_EXEC_ERROR; - } - else - { - namespace FS = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) - { - if (!FS::exists(obj)) - { - // if filesystem doesn't find file - // -> throw error. - kStdOut << "no such file: " << obj << std::endl; - return LIBCOMPILER_EXEC_ERROR; - } - } - } - - // PEF expects a valid target architecture when outputing a binary. - if (kArch == 0) - { - kStdOut << "no target architecture set, can't continue." << std::endl; - return LIBCOMPILER_EXEC_ERROR; - } - - LibCompiler::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = is_executable ? LibCompiler::kPefKindExec : LibCompiler::kPefKindDylib; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // 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(LibCompiler::PEFContainer); - - std::ofstream output_fc(kOutput, std::ofstream::binary); - - if (output_fc.bad()) - { - if (kVerbose) - { - kStdOut << "error: " << strerror(errno) << "\n"; - } - - return LIBCOMPILER_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector<LibCompiler::PEFCommandHeader> command_headers; - LibCompiler::Utils::AEReadableProtocol reader_protocol{}; - - for (const auto& objectFile : kObjectList) - { - if (!std::filesystem::exists(objectFile)) - continue; - - LibCompiler::AEHeader hdr{}; - - reader_protocol.FP = std::ifstream(objectFile, std::ifstream::binary); - reader_protocol.FP >> hdr; - - auto ae_header = hdr; - - if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && - ae_header.fSize == sizeof(LibCompiler::AEHeader)) - { - if (ae_header.fArch != kArch) - { - if (kVerbose) - kStdOut << "info: is this a FAT binary? : "; - - if (!kFatBinaryEnable) - { - if (kVerbose) - kStdOut << "No.\n"; - - kStdOut << "error: object " << objectFile - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - return LIBCOMPILER_FAT_ERROR; - } - else - { - if (kVerbose) - { - kStdOut << "Architecture matches what we expect.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= ae_header.fArch; - std::size_t cnt = ae_header.fCount; - - if (kVerbose) - kStdOut << "object header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - char_type* raw_ae_records = - new char_type[cnt * sizeof(LibCompiler::AERecordHeader)]; - - if (!raw_ae_records) - { - if (kVerbose) - kStdOut << "allocation failure for records of n: " << cnt << "\n"; - } - - memset(raw_ae_records, 0, cnt * sizeof(LibCompiler::AERecordHeader)); - - auto* ae_records = reader_protocol.Read(raw_ae_records, cnt); - - for (size_t ae_record_index = 0; ae_record_index < cnt; - ++ae_record_index) - { - LibCompiler::PEFCommandHeader command_header{0}; - std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; - - MemoryCopy(command_header.Name, ae_records[ae_record_index].fName, - kPefNameLen); - - LibCompiler::String cmd_hdr_name(command_header.Name); - - // check this header if it's any valid. - if (cmd_hdr_name.find(kPefCode64) == - LibCompiler::String::npos && - cmd_hdr_name.find(kPefData64) == - LibCompiler::String::npos && - cmd_hdr_name.find(kPefZero64) == - LibCompiler::String::npos) - { - if (cmd_hdr_name.find(kPefStart) == - LibCompiler::String::npos && - *command_header.Name == 0) - { - if (cmd_hdr_name.find(kLdDefineSymbol) != - LibCompiler::String::npos) - { - goto ld_mark_header; - } - else - { - continue; - } - } - } - - if (cmd_hdr_name.find(kPefStart) != - LibCompiler::String::npos && - cmd_hdr_name.find(kPefCode64) != - LibCompiler::String::npos) - { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offset_of_obj; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; - command_header.Cpu = ae_header.fArch; - command_header.SubCpu = ae_header.fSubArch; - - if (kVerbose) - { - kStdOut << "Record: " - << ae_records[ae_record_index].fName << " is marked.\n"; - - kStdOut << "Record offset: " << command_header.Offset << "\n"; - } - - command_headers.emplace_back(command_header); - } - - delete[] raw_ae_records; - raw_ae_records = nullptr; - - std::vector<char> bytes; - bytes.resize(ae_header.fCodeSize); - - // TODO: Port this to NeFS. - - reader_protocol.FP.seekg(std::streamsize(ae_header.fStartCode)); - reader_protocol.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); - - kObjectBytes.push_back({.mBlob = bytes, .mOffset = ae_header.fStartCode}); - - // Blob was written, close fp. - - reader_protocol.FP.close(); - - continue; - } - - kStdOut << "Not an object container: " << objectFile << std::endl; - // don't continue, it is a fatal error. - return LIBCOMPILER_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - output_fc << pef_container; - - if (kVerbose) - { - kStdOut << "Wrote container header.\n"; - } - - output_fc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector<LibCompiler::String> not_found; - std::vector<LibCompiler::String> symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - for (auto& command_hdr : command_headers) - { - // check if this symbol needs to be resolved. - if (LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) != - LibCompiler::String::npos && - LibCompiler::String(command_hdr.Name).find(kLdDynamicSym) == LibCompiler::String::npos) - { - if (kVerbose) - kStdOut << "Found undefined symbol: " << command_hdr.Name << "\n"; - - if (auto it = std::find(not_found.begin(), not_found.end(), - LibCompiler::String(command_hdr.Name)); - it == not_found.end()) - { - not_found.emplace_back(command_hdr.Name); - } - } - - symbols.emplace_back(command_hdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < command_headers.size(); - ++not_found_idx) - { - if (const auto it = std::find(not_found.begin(), not_found.end(), - LibCompiler::String(command_headers[not_found_idx].Name)); - it != not_found.end()) - { - LibCompiler::String symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == LibCompiler::String::npos) - continue; - - // erase the lookup prefix. - symbol_imp.erase( - 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != LibCompiler::String::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); +LIBCOMPILER_MODULE(DynamicLinker64PEF) { + bool is_executable = true; + + /** + * @brief parse flags and trigger options. + */ + for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) { + if (StringCompare(argv[linker_arg], "-help") == 0) { + kLinkerSplash(); + + kStdOut << "-version: Show linker version.\n"; + kStdOut << "-help: Show linker help.\n"; + kStdOut << "-ld-verbose: Enable linker trace.\n"; + kStdOut << "-dylib: Output as a Dyanmic PEF.\n"; + kStdOut << "-fat: Output as a FAT PEF.\n"; + kStdOut << "-32k: Output as a 32x0 PEF.\n"; + kStdOut << "-64k: Output as a 64x0 PEF.\n"; + kStdOut << "-amd64: Output as a AMD64 PEF.\n"; + kStdOut << "-rv64: Output as a RISC-V PEF.\n"; + kStdOut << "-power64: Output as a POWER PEF.\n"; + kStdOut << "-arm64: Output as a ARM64 PEF.\n"; + kStdOut << "-output: Select the output file name.\n"; + + return EXIT_SUCCESS; + } else if (StringCompare(argv[linker_arg], "-version") == 0) { + kLinkerSplash(); + return EXIT_SUCCESS; + } else if (StringCompare(argv[linker_arg], "-fat-binary") == 0) { + kFatBinaryEnable = true; + + continue; + } else if (StringCompare(argv[linker_arg], "-64k") == 0) { + kArch = LibCompiler::kPefArch64000; + + continue; + } else if (StringCompare(argv[linker_arg], "-amd64") == 0) { + kArch = LibCompiler::kPefArchAMD64; + + continue; + } else if (StringCompare(argv[linker_arg], "-32k") == 0) { + kArch = LibCompiler::kPefArch32000; + + continue; + } else if (StringCompare(argv[linker_arg], "-power64") == 0) { + kArch = LibCompiler::kPefArchPowerPC; + + continue; + } else if (StringCompare(argv[linker_arg], "-riscv64") == 0) { + kArch = LibCompiler::kPefArchRISCV; + + continue; + } else if (StringCompare(argv[linker_arg], "-arm64") == 0) { + kArch = LibCompiler::kPefArchARM64; + + continue; + } else if (StringCompare(argv[linker_arg], "-ld-verbose") == 0) { + kVerbose = true; + + continue; + } else if (StringCompare(argv[linker_arg], "-dylib") == 0) { + if (kOutput.empty()) { + continue; + } + + if (kOutput.find(kPefExt) != LibCompiler::String::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } else if (StringCompare(argv[linker_arg], "-output") == 0) { + if ((linker_arg + 1) > argc) continue; + + kOutput = argv[linker_arg + 1]; + ++linker_arg; + + continue; + } else { + if (argv[linker_arg][0] == '-') { + kStdOut << "unknown flag: " << argv[linker_arg] << "\n"; + return EXIT_FAILURE; + } + + kObjectList.emplace_back(argv[linker_arg]); + + continue; + } + } + + if (kOutput.empty()) { + kStdOut << "no output filename set." << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } else if (kObjectList.empty()) { + kStdOut << "no input files." << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } else { + namespace FS = std::filesystem; + + // check for existing files, if they don't throw an error. + for (auto& obj : kObjectList) { + if (!FS::exists(obj)) { + // if filesystem doesn't find file + // -> throw error. + kStdOut << "no such file: " << obj << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } + } + } + + // PEF expects a valid target architecture when outputing a binary. + if (kArch == 0) { + kStdOut << "no target architecture set, can't continue." << std::endl; + return LIBCOMPILER_EXEC_ERROR; + } + + LibCompiler::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = is_executable ? LibCompiler::kPefKindExec : LibCompiler::kPefKindDylib; + pef_container.SubCpu = kSubArch; + pef_container.Linker = kLinkerId; // 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(LibCompiler::PEFContainer); + + std::ofstream output_fc(kOutput, std::ofstream::binary); + + if (output_fc.bad()) { + if (kVerbose) { + kStdOut << "error: " << strerror(errno) << "\n"; + } + + return LIBCOMPILER_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector<LibCompiler::PEFCommandHeader> command_headers; + LibCompiler::Utils::AEReadableProtocol reader_protocol{}; + + for (const auto& objectFile : kObjectList) { + if (!std::filesystem::exists(objectFile)) continue; + + LibCompiler::AEHeader hdr{}; + + reader_protocol.FP = std::ifstream(objectFile, std::ifstream::binary); + reader_protocol.FP >> hdr; + + auto ae_header = hdr; + + if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && + ae_header.fSize == sizeof(LibCompiler::AEHeader)) { + if (ae_header.fArch != kArch) { + if (kVerbose) kStdOut << "info: is this a FAT binary? : "; + + if (!kFatBinaryEnable) { + if (kVerbose) kStdOut << "No.\n"; + + kStdOut << "error: object " << objectFile + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + return LIBCOMPILER_FAT_ERROR; + } else { + if (kVerbose) { + kStdOut << "Architecture matches what we expect.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= ae_header.fArch; + std::size_t cnt = ae_header.fCount; + + if (kVerbose) kStdOut << "object header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = new char_type[cnt * sizeof(LibCompiler::AERecordHeader)]; + + if (!raw_ae_records) { + if (kVerbose) kStdOut << "allocation failure for records of n: " << cnt << "\n"; + } + + memset(raw_ae_records, 0, cnt * sizeof(LibCompiler::AERecordHeader)); + + auto* ae_records = reader_protocol.Read(raw_ae_records, cnt); + + for (size_t ae_record_index = 0; ae_record_index < cnt; ++ae_record_index) { + LibCompiler::PEFCommandHeader command_header{0}; + std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; + + MemoryCopy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); + + LibCompiler::String cmd_hdr_name(command_header.Name); + + // check this header if it's any valid. + if (cmd_hdr_name.find(kPefCode64) == LibCompiler::String::npos && + cmd_hdr_name.find(kPefData64) == LibCompiler::String::npos && + cmd_hdr_name.find(kPefZero64) == LibCompiler::String::npos) { + if (cmd_hdr_name.find(kPefStart) == LibCompiler::String::npos && + *command_header.Name == 0) { + if (cmd_hdr_name.find(kLdDefineSymbol) != LibCompiler::String::npos) { + goto ld_mark_header; + } else { + continue; + } + } + } + + if (cmd_hdr_name.find(kPefStart) != LibCompiler::String::npos && + cmd_hdr_name.find(kPefCode64) != LibCompiler::String::npos) { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offset_of_obj; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = ae_header.fArch; + command_header.SubCpu = ae_header.fSubArch; + + if (kVerbose) { + kStdOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; + + kStdOut << "Record offset: " << command_header.Offset << "\n"; + } + + command_headers.emplace_back(command_header); + } + + delete[] raw_ae_records; + raw_ae_records = nullptr; + + std::vector<char> bytes; + bytes.resize(ae_header.fCodeSize); + + // TODO: Port this to NeFS. + + reader_protocol.FP.seekg(std::streamsize(ae_header.fStartCode)); + reader_protocol.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); + + kObjectBytes.push_back({.mBlob = bytes, .mOffset = ae_header.fStartCode}); + + // Blob was written, close fp. + + reader_protocol.FP.close(); + + continue; + } + + kStdOut << "Not an object container: " << objectFile << std::endl; + // don't continue, it is a fatal error. + return LIBCOMPILER_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + output_fc << pef_container; + + if (kVerbose) { + kStdOut << "Wrote container header.\n"; + } + + output_fc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector<LibCompiler::String> not_found; + std::vector<LibCompiler::String> symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& command_hdr : command_headers) { + // check if this symbol needs to be resolved. + if (LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) != LibCompiler::String::npos && + LibCompiler::String(command_hdr.Name).find(kLdDynamicSym) == LibCompiler::String::npos) { + if (kVerbose) kStdOut << "Found undefined symbol: " << command_hdr.Name << "\n"; + + if (auto it = + std::find(not_found.begin(), not_found.end(), LibCompiler::String(command_hdr.Name)); + it == not_found.end()) { + not_found.emplace_back(command_hdr.Name); + } + } + + symbols.emplace_back(command_hdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < command_headers.size(); ++not_found_idx) { + if (const auto it = std::find(not_found.begin(), not_found.end(), + LibCompiler::String(command_headers[not_found_idx].Name)); + it != not_found.end()) { + LibCompiler::String symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == LibCompiler::String::npos) continue; + + // erase the lookup prefix. + symbol_imp.erase(0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != LibCompiler::String::npos) + symbol_imp.erase(symbol_imp.find('$'), 1); + + // the reason we do is because, this may not match the symbol, and we need + // to look for other matching symbols. + for (auto& command_hdr : command_headers) { + if (LibCompiler::String(command_hdr.Name).find(symbol_imp) != LibCompiler::String::npos && + LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) == + LibCompiler::String::npos) { + LibCompiler::String undefined_symbol = command_hdr.Name; + auto result_of_sym = undefined_symbol.substr(undefined_symbol.find(symbol_imp)); + + for (int i = 0; result_of_sym[i] != 0; ++i) { + if (result_of_sym[i] != symbol_imp[i]) goto ld_continue_search; + } + + not_found.erase(it); + + if (kVerbose) kStdOut << "found symbol: " << command_hdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) { + if (kVerbose) + kStdOut << "undefined entrypoint: " << kPefStart + << ", you may have forget to link " + "against your compiler's runtime library.\n"; + + kStdOut << "undefined entrypoint " << kPefStart << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + LibCompiler::PEFCommandHeader date_cmd_hdr{}; + + time_t timestamp = time(nullptr); + + LibCompiler::String timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size()); + + date_cmd_hdr.Flags = 0; + date_cmd_hdr.Kind = LibCompiler::kPefZero; + date_cmd_hdr.Offset = output_fc.tellp(); + date_cmd_hdr.Size = timeStampStr.size(); + + command_headers.push_back(date_cmd_hdr); + + LibCompiler::PEFCommandHeader abi_cmd_hdr{}; + + LibCompiler::String abi = kLinkerAbiContainer; + + switch (kArch) { + case LibCompiler::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case LibCompiler::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case LibCompiler::kPefArch32000: + case LibCompiler::kPefArch64000: { + abi += " ZWS"; + break; + } + default: { + abi += " IDK"; + break; + } + } + + MemoryCopy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); + + abi_cmd_hdr.Size = abi.size(); + abi_cmd_hdr.Offset = output_fc.tellp(); + abi_cmd_hdr.Flags = 0; + abi_cmd_hdr.Kind = LibCompiler::kPefLinkerID; + + command_headers.push_back(abi_cmd_hdr); + + LibCompiler::PEFCommandHeader stack_cmd_hdr{0}; + + stack_cmd_hdr.Cpu = kArch; + stack_cmd_hdr.Flags = 0; + stack_cmd_hdr.Size = sizeof(uintptr_t); + stack_cmd_hdr.Offset = 0; + + MemoryCopy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); + + command_headers.push_back(stack_cmd_hdr); + + LibCompiler::PEFCommandHeader uuid_cmd_hdr{}; + + std::random_device rd; + + auto seedData = std::array<int, std::mt19937::state_size>{}; + std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); + std::seed_seq seq(std::begin(seedData), std::end(seedData)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid id = gen(); + auto uuidStr = uuids::to_string(id); + + MemoryCopy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + MemoryCopy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); + + uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name); + uuid_cmd_hdr.Offset = output_fc.tellp(); + uuid_cmd_hdr.Flags = LibCompiler::kPefLinkerID; + uuid_cmd_hdr.Kind = LibCompiler::kPefZero; + + command_headers.push_back(uuid_cmd_hdr); + + // prepare a symbol vector. + std::vector<LibCompiler::String> undef_symbols; + std::vector<LibCompiler::String> dupl_symbols; + std::vector<LibCompiler::String> resolve_symbols; + + constexpr Int32 cPaddingOffset = 16; + + size_t previous_offset = + (command_headers.size() * sizeof(LibCompiler::PEFCommandHeader)) + cPaddingOffset; + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; commandHeaderIndex < command_headers.size(); + ++commandHeaderIndex) { + if (LibCompiler::String(command_headers[commandHeaderIndex].Name).find(kLdDefineSymbol) != + LibCompiler::String::npos && + LibCompiler::String(command_headers[commandHeaderIndex].Name).find(kLdDynamicSym) == + LibCompiler::String::npos) { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + LibCompiler::String symbol_name = command_headers[commandHeaderIndex].Name; + + if (!symbol_name.empty()) { + undef_symbols.emplace_back(symbol_name); + } + + command_headers[commandHeaderIndex].Offset += previous_offset; + previous_offset += command_headers[commandHeaderIndex].Size; + + LibCompiler::String name = command_headers[commandHeaderIndex].Name; + + /// so this is valid when we get to the entrypoint. + /// it is always a code64 container. And should equal to kPefStart as well. + /// this chunk of code updates the pef_container.Start with the updated offset. + if (name.find(kPefStart) != LibCompiler::String::npos && + name.find(kPefCode64) != LibCompiler::String::npos) { + pef_container.Start = command_headers[commandHeaderIndex].Offset; + auto tellCurPos = output_fc.tellp(); + + output_fc.seekp(0); + output_fc << pef_container; + + output_fc.seekp(tellCurPos); + } + + if (kVerbose) { + kStdOut << "Command header name: " << name << "\n"; + kStdOut << "Real address of command header content: " + << command_headers[commandHeaderIndex].Offset << "\n"; + } + + output_fc << command_headers[commandHeaderIndex]; + + for (size_t sub_command_header_index = 0UL; sub_command_header_index < command_headers.size(); + ++sub_command_header_index) { + if (sub_command_header_index == commandHeaderIndex) continue; + + if (LibCompiler::String(command_headers[sub_command_header_index].Name) + .find(kLdDefineSymbol) != LibCompiler::String::npos && + LibCompiler::String(command_headers[sub_command_header_index].Name).find(kLdDynamicSym) == + LibCompiler::String::npos) { + if (kVerbose) { + kStdOut << "ignore :UndefinedSymbol: command header...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& command_hdr = command_headers[sub_command_header_index]; + + if (command_hdr.Name == LibCompiler::String(command_headers[commandHeaderIndex].Name)) { + if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(), command_hdr.Name) == + dupl_symbols.cend()) { + dupl_symbols.emplace_back(command_hdr.Name); + } + + if (kVerbose) kStdOut << "found duplicate symbol: " << command_hdr.Name << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!dupl_symbols.empty()) { + for (auto& symbol : dupl_symbols) { + kStdOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; + } + + return LIBCOMPILER_EXEC_ERROR; + } + + // step 2.5: write program bytes. - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto& command_hdr : command_headers) - { - if (LibCompiler::String(command_hdr.Name).find(symbol_imp) != - LibCompiler::String::npos && - LibCompiler::String(command_hdr.Name).find(kLdDefineSymbol) == - LibCompiler::String::npos) - { - LibCompiler::String undefined_symbol = command_hdr.Name; - auto result_of_sym = - undefined_symbol.substr(undefined_symbol.find(symbol_imp)); + for (auto& struct_of_blob : kObjectBytes) { + output_fc.write(struct_of_blob.mBlob.data(), struct_of_blob.mBlob.size()); + } - for (int i = 0; result_of_sym[i] != 0; ++i) - { - if (result_of_sym[i] != symbol_imp[i]) - goto ld_continue_search; - } + if (kVerbose) { + kStdOut << "wrote contents of: " << kOutput << "\n"; + } - not_found.erase(it); + // step 3: check if we have those symbols + + std::vector<LibCompiler::String> unreferenced_symbols; + + for (auto& command_hdr : command_headers) { + if (auto it = + std::find(not_found.begin(), not_found.end(), LibCompiler::String(command_hdr.Name)); + it != not_found.end()) { + unreferenced_symbols.emplace_back(command_hdr.Name); + } + } - if (kVerbose) - kStdOut << "found symbol: " << command_hdr.Name << "\n"; + if (!unreferenced_symbols.empty()) { + for (auto& unreferenced_symbol : unreferenced_symbols) { + kStdOut << "undefined symbol " << unreferenced_symbol << "\n"; + } - break; - } - } + return LIBCOMPILER_EXEC_ERROR; + } - ld_continue_search: - continue; - } - } + if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || + !unreferenced_symbols.empty()) { + if (kVerbose) { + kStdOut << "file: " << kOutput << ", is corrupt, removing file...\n"; + } - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) - { - if (kVerbose) - kStdOut - << "undefined entrypoint: " << kPefStart << ", you may have forget to link " - "against your compiler's runtime library.\n"; + return LIBCOMPILER_EXEC_ERROR; + } - kStdOut << "undefined entrypoint " << kPefStart - << " for executable: " << kOutput << "\n"; - } - - // step 4: write all PEF commands. - - LibCompiler::PEFCommandHeader date_cmd_hdr{}; - - time_t timestamp = time(nullptr); - - LibCompiler::String timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size()); - - date_cmd_hdr.Flags = 0; - date_cmd_hdr.Kind = LibCompiler::kPefZero; - date_cmd_hdr.Offset = output_fc.tellp(); - date_cmd_hdr.Size = timeStampStr.size(); - - command_headers.push_back(date_cmd_hdr); - - LibCompiler::PEFCommandHeader abi_cmd_hdr{}; - - LibCompiler::String abi = kLinkerAbiContainer; - - switch (kArch) - { - case LibCompiler::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case LibCompiler::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case LibCompiler::kPefArch32000: - case LibCompiler::kPefArch64000: { - abi += " ZWS"; - break; - } - default: { - abi += " IDK"; - break; - } - } - - MemoryCopy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); - - abi_cmd_hdr.Size = abi.size(); - abi_cmd_hdr.Offset = output_fc.tellp(); - abi_cmd_hdr.Flags = 0; - abi_cmd_hdr.Kind = LibCompiler::kPefLinkerID; - - command_headers.push_back(abi_cmd_hdr); - - LibCompiler::PEFCommandHeader stack_cmd_hdr{0}; - - stack_cmd_hdr.Cpu = kArch; - stack_cmd_hdr.Flags = 0; - stack_cmd_hdr.Size = sizeof(uintptr_t); - stack_cmd_hdr.Offset = 0; - - MemoryCopy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); - - command_headers.push_back(stack_cmd_hdr); - - LibCompiler::PEFCommandHeader uuid_cmd_hdr{}; - - std::random_device rd; - - auto seedData = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - MemoryCopy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - MemoryCopy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), - uuidStr.size()); - - uuid_cmd_hdr.Size = strlen(uuid_cmd_hdr.Name); - uuid_cmd_hdr.Offset = output_fc.tellp(); - uuid_cmd_hdr.Flags = LibCompiler::kPefLinkerID; - uuid_cmd_hdr.Kind = LibCompiler::kPefZero; - - command_headers.push_back(uuid_cmd_hdr); - - // prepare a symbol vector. - std::vector<LibCompiler::String> undef_symbols; - std::vector<LibCompiler::String> dupl_symbols; - std::vector<LibCompiler::String> resolve_symbols; - - constexpr Int32 cPaddingOffset = 16; - - size_t previous_offset = (command_headers.size() * sizeof(LibCompiler::PEFCommandHeader)) + cPaddingOffset; - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; - commandHeaderIndex < command_headers.size(); ++commandHeaderIndex) - { - if (LibCompiler::String(command_headers[commandHeaderIndex].Name) - .find(kLdDefineSymbol) != LibCompiler::String::npos && - LibCompiler::String(command_headers[commandHeaderIndex].Name) - .find(kLdDynamicSym) == LibCompiler::String::npos) - { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - LibCompiler::String symbol_name = command_headers[commandHeaderIndex].Name; - - if (!symbol_name.empty()) - { - undef_symbols.emplace_back(symbol_name); - } - - command_headers[commandHeaderIndex].Offset += previous_offset; - previous_offset += command_headers[commandHeaderIndex].Size; - - LibCompiler::String name = command_headers[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kPefStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != LibCompiler::String::npos && - name.find(kPefCode64) != LibCompiler::String::npos) - { - pef_container.Start = command_headers[commandHeaderIndex].Offset; - auto tellCurPos = output_fc.tellp(); - - output_fc.seekp(0); - output_fc << pef_container; - - output_fc.seekp(tellCurPos); - } - - if (kVerbose) - { - kStdOut << "Command header name: " << name << "\n"; - kStdOut << "Real address of command header content: " << command_headers[commandHeaderIndex].Offset << "\n"; - } - - output_fc << command_headers[commandHeaderIndex]; - - for (size_t sub_command_header_index = 0UL; - sub_command_header_index < command_headers.size(); - ++sub_command_header_index) - { - if (sub_command_header_index == commandHeaderIndex) - continue; - - if (LibCompiler::String(command_headers[sub_command_header_index].Name) - .find(kLdDefineSymbol) != LibCompiler::String::npos && - LibCompiler::String(command_headers[sub_command_header_index].Name) - .find(kLdDynamicSym) == LibCompiler::String::npos) - { - if (kVerbose) - { - kStdOut << "ignore :UndefinedSymbol: command header...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto& command_hdr = command_headers[sub_command_header_index]; - - if (command_hdr.Name == - LibCompiler::String(command_headers[commandHeaderIndex].Name)) - { - if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(), - command_hdr.Name) == dupl_symbols.cend()) - { - dupl_symbols.emplace_back(command_hdr.Name); - } - - if (kVerbose) - kStdOut << "found duplicate symbol: " << command_hdr.Name - << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!dupl_symbols.empty()) - { - for (auto& symbol : dupl_symbols) - { - kStdOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; - } - - return LIBCOMPILER_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto& struct_of_blob : kObjectBytes) - { - output_fc.write(struct_of_blob.mBlob.data(), struct_of_blob.mBlob.size()); - } - - if (kVerbose) - { - kStdOut << "wrote contents of: " << kOutput << "\n"; - } - - // step 3: check if we have those symbols - - std::vector<LibCompiler::String> unreferenced_symbols; - - for (auto& command_hdr : command_headers) - { - if (auto it = std::find(not_found.begin(), not_found.end(), - LibCompiler::String(command_hdr.Name)); - it != not_found.end()) - { - unreferenced_symbols.emplace_back(command_hdr.Name); - } - } - - if (!unreferenced_symbols.empty()) - { - for (auto& unreferenced_symbol : unreferenced_symbols) - { - kStdOut << "undefined symbol " << unreferenced_symbol << "\n"; - } - - return LIBCOMPILER_EXEC_ERROR; - } - - if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || - !unreferenced_symbols.empty()) - { - if (kVerbose) - { - kStdOut << "file: " << kOutput - << ", is corrupt, removing file...\n"; - } - - return LIBCOMPILER_EXEC_ERROR; - } - - return LIBCOMPILER_SUCCESSS; + return LIBCOMPILER_SUCCESSS; } // Last rev 13-1-24 diff --git a/dev/LibCompiler/src/StringView.cc b/dev/LibCompiler/src/StringView.cc index a3bbb4c..41ee636 100644 --- a/dev/LibCompiler/src/StringView.cc +++ b/dev/LibCompiler/src/StringView.cc @@ -20,237 +20,188 @@ #include <LibCompiler/StringView.h> -namespace LibCompiler -{ - CharType* StringView::Data() - { - return m_Data; - } - - const CharType* StringView::CData() const - { - return m_Data; - } - - SizeType StringView::Length() const - { - return strlen(m_Data); - } - - bool StringView::operator==(const StringView& rhs) const - { - if (rhs.Length() != Length()) - return false; - - for (SizeType index = 0; index < Length(); ++index) - { - if (rhs.m_Data[index] != m_Data[index]) - return false; - } - - return true; - } - - bool StringView::operator==(const CharType* rhs) const - { - if (string_length(rhs) != Length()) - return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) - { - if (rhs[index] != m_Data[index]) - return false; - } - - return true; - } - - bool StringView::operator!=(const StringView& rhs) const - { - if (rhs.Length() != Length()) - return false; - - for (SizeType index = 0; index < rhs.Length(); ++index) - { - if (rhs.m_Data[index] == m_Data[index]) - return false; - } - - return true; - } - - bool StringView::operator!=(const CharType* rhs) const - { - if (string_length(rhs) != Length()) - return false; - - for (SizeType index = 0; index < string_length(rhs); ++index) - { - if (rhs[index] == m_Data[index]) - return false; - } - - return true; - } - - StringView StringBuilder::Construct(const CharType* data) - { - if (!data || *data == 0) - return StringView(0); - - StringView view(strlen(data)); - view += data; - - return view; - } - - const char* StringBuilder::FromInt(const char* fmt, int i) - { - if (!fmt) - return ("-1"); - - auto ret_len = 8 + string_length(fmt); - char* ret = new char[ret_len]; - - if (!ret) - return ("-1"); - - memset(ret, 0, ret_len); - - CharType result[sizeof(int64_t)]; - - if (!to_str(result, sizeof(int64_t), i)) - { - delete[] ret; - return ("-1"); - } - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(result); - - for (SizeType idx = 0; idx < fmt_len; ++idx) - { - if (fmt[idx] == '%') - { - SizeType result_cnt = idx; - - for (auto y_idx = 0; y_idx < res_len; ++y_idx) - { - ret[y_idx] = result[result_cnt]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ - } - - const char* StringBuilder::FromBool(const char* fmt, bool i) - { - if (!fmt) - return ("?"); - - const char* boolean_expr = i ? "true" : "false"; - char* ret = new char[i ? 4 : 5 + string_length(fmt)]; - - if (!ret) - return ("?"); - - const auto fmt_len = string_length(fmt); - const auto res_len = string_length(boolean_expr); - - for (SizeType idx = 0; idx < fmt_len; ++idx) - { - if (fmt[idx] == '%') - { - SizeType result_cnt = idx; - - for (auto y_idx = idx; y_idx < res_len; ++y_idx) - { - ret[result_cnt] = boolean_expr[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; - } +namespace LibCompiler { +CharType* StringView::Data() { + return m_Data; +} - bool StringBuilder::Equals(const char* lhs, const char* rhs) - { - if (string_length(rhs) != string_length(lhs)) - return false; +const CharType* StringView::CData() const { + return m_Data; +} - for (SizeType index = 0; index < string_length(rhs); ++index) - { - if (rhs[index] != lhs[index]) - return false; - } - - return true; - } +SizeType StringView::Length() const { + return strlen(m_Data); +} - const char* StringBuilder::Format(const char* fmt, const char* fmtRight) - { - if (!fmt || !fmtRight) - return ("?"); - - char* ret = new char[string_length(fmtRight) + string_length(fmtRight)]; - if (!ret) - return ("?"); - - for (SizeType idx = 0; idx < string_length(fmt); ++idx) - { - if (fmt[idx] == '%') - { - SizeType result_cnt = idx; - - for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) - { - ret[result_cnt] = fmtRight[y_idx]; - ++result_cnt; - } - - break; - } - - ret[idx] = fmt[idx]; - } - - return ret; - } - - StringView& StringView::operator+=(const CharType* rhs) - { - if (strlen(rhs) > this->m_Sz) - { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); - this->m_Cur += strlen(rhs); - - return *this; - } - - StringView& StringView::operator+=(const StringView& rhs) - { - if (rhs.m_Cur > this->m_Sz) - { - throw std::runtime_error("out_of_bounds: StringView"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); - this->m_Cur += strlen(rhs.CData()); - - return *this; - } -} // namespace LibCompiler +bool StringView::operator==(const StringView& rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < Length(); ++index) { + if (rhs.m_Data[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator==(const CharType* rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const StringView& rhs) const { + if (rhs.Length() != Length()) return false; + + for (SizeType index = 0; index < rhs.Length(); ++index) { + if (rhs.m_Data[index] == m_Data[index]) return false; + } + + return true; +} + +bool StringView::operator!=(const CharType* rhs) const { + if (string_length(rhs) != Length()) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] == m_Data[index]) return false; + } + + return true; +} + +StringView StringBuilder::Construct(const CharType* data) { + if (!data || *data == 0) return StringView(0); + + StringView view(strlen(data)); + view += data; + + return view; +} + +const char* StringBuilder::FromInt(const char* fmt, int i) { + if (!fmt) return ("-1"); + + auto ret_len = 8 + string_length(fmt); + char* ret = new char[ret_len]; + + if (!ret) return ("-1"); + + memset(ret, 0, ret_len); + + CharType result[sizeof(int64_t)]; + + if (!to_str(result, sizeof(int64_t), i)) { + delete[] ret; + return ("-1"); + } + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(result); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = 0; y_idx < res_len; ++y_idx) { + ret[y_idx] = result[result_cnt]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; /* Copy that ret into a buffer, Alloca allocates to the stack */ +} + +const char* StringBuilder::FromBool(const char* fmt, bool i) { + if (!fmt) return ("?"); + + const char* boolean_expr = i ? "true" : "false"; + char* ret = new char[i ? 4 : 5 + string_length(fmt)]; + + if (!ret) return ("?"); + + const auto fmt_len = string_length(fmt); + const auto res_len = string_length(boolean_expr); + + for (SizeType idx = 0; idx < fmt_len; ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (auto y_idx = idx; y_idx < res_len; ++y_idx) { + ret[result_cnt] = boolean_expr[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +bool StringBuilder::Equals(const char* lhs, const char* rhs) { + if (string_length(rhs) != string_length(lhs)) return false; + + for (SizeType index = 0; index < string_length(rhs); ++index) { + if (rhs[index] != lhs[index]) return false; + } + + return true; +} + +const char* StringBuilder::Format(const char* fmt, const char* fmtRight) { + if (!fmt || !fmtRight) return ("?"); + + char* ret = new char[string_length(fmtRight) + string_length(fmtRight)]; + if (!ret) return ("?"); + + for (SizeType idx = 0; idx < string_length(fmt); ++idx) { + if (fmt[idx] == '%') { + SizeType result_cnt = idx; + + for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { + ret[result_cnt] = fmtRight[y_idx]; + ++result_cnt; + } + + break; + } + + ret[idx] = fmt[idx]; + } + + return ret; +} + +StringView& StringView::operator+=(const CharType* rhs) { + if (strlen(rhs) > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs, strlen(rhs)); + this->m_Cur += strlen(rhs); + + return *this; +} + +StringView& StringView::operator+=(const StringView& rhs) { + if (rhs.m_Cur > this->m_Sz) { + throw std::runtime_error("out_of_bounds: StringView"); + } + + memcpy(this->m_Data + this->m_Cur, rhs.CData(), strlen(rhs.CData())); + this->m_Cur += strlen(rhs.CData()); + + return *this; +} +} // namespace LibCompiler diff --git a/dev/LibDebugger/DebuggerContract.h b/dev/LibDebugger/DebuggerContract.h index 0ef88a2..0f4bc10 100644 --- a/dev/LibDebugger/DebuggerContract.h +++ b/dev/LibDebugger/DebuggerContract.h @@ -1,49 +1,44 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ #pragma once #include <cstdint> -#include <unordered_map> #include <string> +#include <unordered_map> + +namespace LibDebugger { +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 Breakpoint(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; } -namespace LibDebugger -{ - 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 Breakpoint(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; - std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; - }; -} // namespace LibDebugger + protected: + ProcessID m_pid; + std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; +}; +} // namespace LibDebugger diff --git a/dev/LibDebugger/NeKernelContract.h b/dev/LibDebugger/NeKernelContract.h index e6b40d0..8e54ab2 100644 --- a/dev/LibDebugger/NeKernelContract.h +++ b/dev/LibDebugger/NeKernelContract.h @@ -1,6 +1,6 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ #ifndef LD_NEKERNEL_CONTRACT_H @@ -21,47 +21,43 @@ #define kDebugMag3 'G' #define kDebugSourceFile 23 -#define kDebugLine 33 -#define kDebugTeam 43 -#define kDebugEOP 49 - -namespace LibDebugger::NeKernel -{ - class NeKernelContract; - - namespace Detail - { - class NeKernelPortHeader; - - inline constexpr size_t kDebugTypeLen = 256U; - - typedef char rt_debug_type[kDebugTypeLen]; - - class NeKernelPortHeader final - { - public: - int16_t fPort; - int16_t fPortBsy; - }; - } // namespace Detail - - class NeKernelContract : public DebuggerContract - { - public: - NeKernelContract(); - virtual ~NeKernelContract(); - - // Override additional methods from DebuggerContract - virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept override; - virtual bool Breakpoint(std::string symbol) noexcept override; - virtual bool Break() noexcept override; - virtual bool Continue() noexcept override; - virtual bool Detach() noexcept override; - - private: - std::string m_ip_address; - std::string m_port; - }; -} // namespace LibDebugger::NeKernel - -#endif // LD_NEKERNEL_CONTRACT_H
\ No newline at end of file +#define kDebugLine 33 +#define kDebugTeam 43 +#define kDebugEOP 49 + +namespace LibDebugger::NeKernel { +class NeKernelContract; + +namespace Detail { + class NeKernelPortHeader; + + inline constexpr size_t kDebugTypeLen = 256U; + + typedef char rt_debug_type[kDebugTypeLen]; + + class NeKernelPortHeader final { + public: + int16_t fPort; + int16_t fPortBsy; + }; +} // namespace Detail + +class NeKernelContract : public DebuggerContract { + public: + NeKernelContract(); + virtual ~NeKernelContract(); + + // Override additional methods from DebuggerContract + virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept override; + virtual bool Breakpoint(std::string symbol) noexcept override; + virtual bool Break() noexcept override; + virtual bool Continue() noexcept override; + virtual bool Detach() noexcept override; + + private: + std::string m_ip_address; + std::string m_port; +}; +} // namespace LibDebugger::NeKernel + +#endif // LD_NEKERNEL_CONTRACT_H
\ No newline at end of file diff --git a/dev/LibDebugger/POSIXMachContract.h b/dev/LibDebugger/POSIXMachContract.h index fbfe928..5904cd2 100644 --- a/dev/LibDebugger/POSIXMachContract.h +++ b/dev/LibDebugger/POSIXMachContract.h @@ -1,5 +1,5 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ #pragma once @@ -9,163 +9,150 @@ /// @file POSIXMachContract.h /// @brief POSIX Mach debugger. -#include <LibDebugger/DebuggerContract.h> #include <LibCompiler/Defines.h> +#include <LibDebugger/DebuggerContract.h> +#include <stdint.h> #include <sys/ptrace.h> #include <sys/types.h> -#include <sys/wait.h> #include <sys/user.h> +#include <sys/wait.h> #include <unistd.h> -#include <stdint.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 <mach-o/dyld.h> -#include <dlfcn.h> -LC_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); +LC_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); -LC_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); +LC_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_ATTACH PT_ATTACHEXC +#define PTRACE_DETACH PT_DETACH #define PTRACE_POKETEXT PT_WRITE_I -#define PTRACE_CONT PT_CONTINUE +#define PTRACE_CONT PT_CONTINUE #define PTRACE_PEEKTEXT PT_READ_I -namespace LibDebugger::POSIX -{ - /// \brief POSIXMachContract engine interface class in C++ - /// \author Amlal El Mahrouss - class POSIXMachContract : public DebuggerContract - { - public: - explicit POSIXMachContract() = default; - ~POSIXMachContract() override = default; +namespace LibDebugger::POSIX { +/// \brief POSIXMachContract engine interface class in C++ +/// \author Amlal El Mahrouss +class POSIXMachContract : public DebuggerContract { + public: + explicit POSIXMachContract() = default; + ~POSIXMachContract() override = default; - public: - POSIXMachContract& operator=(const POSIXMachContract&) = default; - POSIXMachContract(const POSIXMachContract&) = default; + public: + POSIXMachContract& operator=(const POSIXMachContract&) = default; + POSIXMachContract(const POSIXMachContract&) = default; - public: - BOOL Attach(std::string path, std::string argv, ProcessID& pid) noexcept override - { - pid = fork(); + public: + BOOL Attach(std::string path, std::string argv, ProcessID& pid) noexcept override { + pid = fork(); - if (pid == 0) - { - if (argv.empty()) - { - ptrace(PT_TRACE_ME, 0, nullptr, 0); - kill(getpid(), SIGSTOP); - } + if (pid == 0) { + if (argv.empty()) { + ptrace(PT_TRACE_ME, 0, nullptr, 0); + kill(getpid(), SIGSTOP); + } - std::vector<char*> argv_arr; + 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); + 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()); + execv(path.c_str(), argv_arr.data()); - _exit(1); - } + _exit(1); + } - m_path = path; - m_pid = pid; + m_path = path; + m_pid = pid; - pid = this->m_pid; + pid = this->m_pid; - return true; - } + return true; + } - void SetPath(std::string path) noexcept - { - if (path.empty()) - { - return; - } + void SetPath(std::string path) noexcept { + if (path.empty()) { + return; + } - m_path = path; - } + m_path = path; + } - BOOL Breakpoint(std::string 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); + BOOL Breakpoint(std::string 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; - } + if (handle == nullptr) { + return false; + } - auto addr = dlsym(handle, symbol.c_str()); + auto addr = dlsym(handle, symbol.c_str()); - if (addr == nullptr) - { - return false; - } + if (addr == nullptr) { + return false; + } - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); - uint32_t brk_inst = 0xD43E0000; + 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)); + 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 true; + } - return false; - } + return false; + } - BOOL Break() noexcept override - { - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); + BOOL Break() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); - kern_return_t ret = task_suspend(task); + kern_return_t ret = task_suspend(task); - return ret == KERN_SUCCESS; - } + return ret == KERN_SUCCESS; + } - BOOL Continue() noexcept override - { - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); + BOOL Continue() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); - kern_return_t ret = task_resume(task); + kern_return_t ret = task_resume(task); - return ret == KERN_SUCCESS; - } + return ret == KERN_SUCCESS; + } - BOOL Detach() noexcept override - { - this->Continue(); + BOOL Detach() noexcept override { + this->Continue(); - task_read_t task; - task_for_pid(mach_task_self(), m_pid, &task); + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); - kern_return_t kr = mach_port_deallocate(mach_task_self(), task); + kern_return_t kr = mach_port_deallocate(mach_task_self(), task); - return kr = KERN_SUCCESS; - } + return kr = KERN_SUCCESS; + } - private: - ProcessID m_pid{0}; - std::string m_path; - }; -} // namespace LibDebugger::POSIX + private: + ProcessID m_pid{0}; + std::string m_path; +}; +} // namespace LibDebugger::POSIX #endif diff --git a/dev/LibDebugger/src/POSIXMachContract.cc b/dev/LibDebugger/src/POSIXMachContract.cc index 2f30f09..2753e9a 100644 --- a/dev/LibDebugger/src/POSIXMachContract.cc +++ b/dev/LibDebugger/src/POSIXMachContract.cc @@ -1,120 +1,102 @@ /*** - (C) 2025 Amlal El Mahrouss + (C) 2025 Amlal El Mahrouss */ - #ifdef __APPLE__ +#ifdef __APPLE__ -#include <iostream> #include <LibCompiler/Defines.h> -#include <Vendor/Dialogs.h> #include <LibDebugger/POSIXMachContract.h> +#include <Vendor/Dialogs.h> #include <cstdint> +#include <iostream> #include <string> -static BOOL kKeepRunning = false; +static BOOL kKeepRunning = false; static LibDebugger::POSIX::POSIXMachContract kDebugger; -static LibDebugger::ProcessID kPID = 0L; -static LibDebugger::CAddress kActiveAddress = nullptr; -static std::string kPath = ""; +static LibDebugger::ProcessID kPID = 0L; +static LibDebugger::CAddress kActiveAddress = nullptr; +static std::string kPath = ""; #define kBlank "\e[0;30m" -#define kRed "\e[0;31m" +#define kRed "\e[0;31m" #define kWhite "\e[0;97m" #define kStdOut (std::cout << kRed << "dbg: " << kWhite) /// @internal /// @brief Handles CTRL-C signal on debugger. -static void dbgi_ctrlc_handler(std::int32_t _) -{ - if (!kPID) - { - return; - } +static void dbgi_ctrlc_handler(std::int32_t _) { + if (!kPID) { + return; + } - auto list = kDebugger.Get(); + auto list = kDebugger.Get(); - kDebugger.Break(); + kDebugger.Break(); - pfd::notify("Debugger Event", "Breakpoint hit!"); + pfd::notify("Debugger Event", "Breakpoint hit!"); - kKeepRunning = false; + kKeepRunning = false; } -LIBCOMPILER_MODULE(DebuggerMachPOSIX) -{ - pfd::notify("Debugger Event", "Userland Debugger\n(C) 2025 Amlal El Mahrouss, all rights reserved."); - - if (argc >= 3 && std::string(argv[1]) == "-p" && - argv[2] != nullptr) - { - kPath = argv[2]; - kDebugger.SetPath(kPath); - - kStdOut << "[+] Path set to: " << kPath << "\n"; - } - - ::signal(SIGINT, dbgi_ctrlc_handler); - - while (YES) - { - if (kKeepRunning) - { - continue; - } - - std::string cmd; - std::getline(std::cin, cmd); - - if (cmd == "c" || - cmd == "cont" || - cmd == "continue") - { - if (kDebugger.Continue()) - { - kKeepRunning = true; - - kStdOut << "[+] Continuing...\n"; - - pfd::notify("Debugger Event", "Continuing..."); - } - } - - if (cmd == "d" || - cmd == "detach") - kDebugger.Detach(); - - if (cmd == "start") - { - kStdOut << "[?] Enter a argument to use: "; - std::getline(std::cin, cmd); - - kDebugger.Attach(kPath, cmd, kPID); - } - - if (cmd == "exit") - { - if (kPID > 0) - kDebugger.Detach(); - - break; - } - - if (cmd == "break" || - cmd == "b") - { - kStdOut << "[?] Enter a symbol to break on: "; - - std::getline(std::cin, cmd); - - if (kDebugger.Breakpoint(cmd)) - { - pfd::notify("Debugger Event", "Add Breakpoint at: " + cmd); - } - } - } - - return EXIT_SUCCESS; +LIBCOMPILER_MODULE(DebuggerMachPOSIX) { + pfd::notify("Debugger Event", + "Userland Debugger\n(C) 2025 Amlal El Mahrouss, all rights reserved."); + + if (argc >= 3 && std::string(argv[1]) == "-p" && argv[2] != nullptr) { + kPath = argv[2]; + kDebugger.SetPath(kPath); + + kStdOut << "[+] Path set to: " << kPath << "\n"; + } + + ::signal(SIGINT, dbgi_ctrlc_handler); + + while (YES) { + if (kKeepRunning) { + continue; + } + + std::string cmd; + std::getline(std::cin, cmd); + + if (cmd == "c" || cmd == "cont" || cmd == "continue") { + if (kDebugger.Continue()) { + kKeepRunning = true; + + kStdOut << "[+] Continuing...\n"; + + pfd::notify("Debugger Event", "Continuing..."); + } + } + + if (cmd == "d" || cmd == "detach") kDebugger.Detach(); + + if (cmd == "start") { + kStdOut << "[?] Enter a argument to use: "; + std::getline(std::cin, cmd); + + kDebugger.Attach(kPath, cmd, kPID); + } + + if (cmd == "exit") { + if (kPID > 0) kDebugger.Detach(); + + break; + } + + if (cmd == "break" || cmd == "b") { + kStdOut << "[?] Enter a symbol to break on: "; + + std::getline(std::cin, cmd); + + if (kDebugger.Breakpoint(cmd)) { + pfd::notify("Debugger Event", "Add Breakpoint at: " + cmd); + } + } + } + + return EXIT_SUCCESS; } #endif
\ No newline at end of file diff --git a/dev/Vendor/Dialogs.h b/dev/Vendor/Dialogs.h index fd64026..ce50b81 100644 --- a/dev/Vendor/Dialogs.h +++ b/dev/Vendor/Dialogs.h @@ -16,45 +16,45 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif -#include <windows.h> #include <commdlg.h> -#include <shlobj.h> -#include <shobjidl.h> // IFileDialog #include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> // IFileDialog #include <strsafe.h> -#include <future> // std::async -#include <userenv.h> // GetUserProfileDirectory() +#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() +#define _POSIX_C_SOURCE 2 // for popen() #endif #ifdef __APPLE__ #ifndef _DARWIN_C_SOURCE #define _DARWIN_C_SOURCE #endif #endif -#include <cstdio> // popen() -#include <cstdlib> // std::getenv() -#include <fcntl.h> // fcntl() -#include <unistd.h> // read(), pipe(), dup2(), getuid() -#include <csignal> // ::kill, std::signal -#include <sys/stat.h> // stat() -#include <sys/wait.h> // waitpid() -#include <pwd.h> // getpwnam() +#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 <string> // std::string -#include <memory> // std::shared_ptr -#include <iostream> // std::ostream -#include <map> // std::map -#include <set> // std::set -#include <regex> // std::regex -#include <thread> // std::mutex, std::this_thread -#include <chrono> // std::chrono +#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 @@ -67,1915 +67,1672 @@ #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(); +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); + 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); + void start(int exit_code); #else - void start_process(std::vector<std::string> const& command); + void start_process(std::vector<std::string> const& command); #endif - ~executor(); + ~executor(); - protected: - bool ready(int timeout = default_wait_timeout); - void stop(); + protected: + bool ready(int timeout = default_wait_timeout); + void stop(); - private: - bool m_running = false; - std::string m_stdout; - int m_exit_code = -1; + 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; + 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 + // FIXME: do something #else - pid_t m_pid = 0; - int m_fd = -1; + pid_t m_pid = 0; + int m_fd = -1; #endif - }; + }; - class platform - { - protected: + 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()))) - { - } - - 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; - }; + // 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()))) {} + + 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(); + }; + + 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); + 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); + std::string select_folder_vista(IFileDialog* ifd, bool force_path); #endif - std::wstring m_wtitle; - std::wstring m_wdefault_path; + std::wstring m_wtitle; + std::wstring m_wdefault_path; - std::vector<std::string> m_vector_result; + 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); + }; + +} // 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")]] + // 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); + 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")]] + // 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. - // + 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 +// internal free functions implementations - namespace internal - { +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; - } + 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. + // 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 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; - } + 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 + // This is necessary until C++17 which will have std::filesystem::is_directory - static inline bool is_directory(std::string const& path) - { + 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); + auto attr = GetFileAttributesA(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); #elif __EMSCRIPTEN__ - // TODO - return false; + // TODO + return false; #else - struct stat s; - return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); + 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 + // This is necessary because getenv is not thread-safe - static inline std::string getenv(std::string const& str) - { + 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 ""; + 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 : ""; + auto buf = std::getenv(str.c_str()); + return buf ? buf : ""; #endif - } + } - } // namespace internal +} // namespace internal - // settings implementation +// settings implementation - inline settings::settings(bool resync) - { - flags(flag::is_scanned) &= !resync; +inline settings::settings(bool resync) { + flags(flag::is_scanned) &= !resync; - if (flags(flag::is_scanned)) - return; + 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; + 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(); + 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; - } + 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; - } + flags(flag::is_scanned) = true; +} - inline bool settings::available() - { +inline bool settings::available() { #if _WIN32 - return true; + return true; #elif __APPLE__ - return true; + return true; #elif __EMSCRIPTEN__ - // FIXME: Return true after implementation is complete. - return false; + // 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); + 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::verbose(bool value) { + settings().flags(flag::is_verbose) = value; +} - inline void settings::rescan() - { - settings(/* resync = */ true); - } +inline void settings::rescan() { + settings(/* resync = */ true); +} - // Check whether a program is present using “which”. - inline bool settings::check_program(std::string const& program) - { +// Check whether a program is present using “which”. +inline bool settings::check_program(std::string const& program) { #if _WIN32 - (void)program; - return false; + (void) program; + return false; #elif __EMSCRIPTEN__ - (void)program; - return false; + (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; + 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 - { +inline bool settings::is_osascript() const { #if __APPLE__ - return true; + return true; #else - return false; + 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() - { +} + +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; - } + // 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 "/"; + 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; + // 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); + 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; + 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 "/"; - } + return "/"; +} - inline std::string path::separator() - { +inline std::string path::separator() { #if _WIN32 - return "\\"; + return "\\"; #else - return "/"; + return "/"; #endif - } +} - // executor implementation +// 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 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() - { +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); - } - } + 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 + // FIXME: do something + return false; // cannot kill #else - ::kill(m_pid, SIGKILL); + ::kill(m_pid, SIGKILL); #endif - stop(); - return true; - } + 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; - } +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; - } +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; - } +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; - } +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 internal::executor::~executor() { + stop(); +} - inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) - { - if (!m_running) - return true; +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(); - } + 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; + // 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); + 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; - } + m_running = false; + return true; +} - inline void internal::executor::stop() - { - // Loop until the user closes the dialog - while (!ready()) - ; - } +inline void internal::executor::stop() { + // Loop until the user closes the dialog + while (!ready()); +} - // dll implementation +// dll implementation #if _WIN32 - inline internal::platform::dll::dll(std::string const& name) - : handle(::LoadLibraryA(name.c_str())) - { - } +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 +inline internal::platform::dll::~dll() { + if (handle) ::FreeLibrary(handle); +} +#endif // _WIN32 - // ole32_dll implementation +// 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; - } +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 +// 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 - { +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"}; + 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"}; + 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: +} + +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"; + return "info"; #else - return "information"; + 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 */) - { + } +} + +// 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) - { + 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); - } + 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 ""; - }); + 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; + // 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); + 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() - { +inline std::string internal::file_dialog::string_result() { #if _WIN32 - return m_async->result(); + 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; + 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() - { +inline std::vector<std::string> internal::file_dialog::vector_result() { #if _WIN32 - m_async->result(); - return m_vector_result; + 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; + 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; - } +// 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; - } +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 +// 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; +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()); + // 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; + // 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); + 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 +// message implementation - inline message::message(std::string const& title, - std::string const& text, - choice _choice /* = choice::ok_cancel */, - icon _icon /* = icon::info */) - { +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 ""; - }); + // 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)); + 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; + 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); + } + + 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
\ No newline at end of file +} + +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
\ No newline at end of file diff --git a/tests/example.cc b/tests/example.cc index 718e46f..83e664a 100644 --- a/tests/example.cc +++ b/tests/example.cc @@ -1,19 +1,16 @@ #define AppMain int __ImageStart #warning TestCase #1 -int bar() -{ - int yyy = 100; - return yyy; +int bar() { + int yyy = 100; + return yyy; } -int foo() -{ - int arg1 = 0; - return bar(); +int foo() { + int arg1 = 0; + return bar(); } -AppMain() -{ - return foo(); +AppMain() { + return foo(); } diff --git a/tools/asm.cc b/tools/asm.cc index 4845c99..118ab22 100644 --- a/tools/asm.cc +++ b/tools/asm.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -9,8 +9,8 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/Version.h> -#include <iostream> #include <cstring> +#include <iostream> #include <string> #include <vector> @@ -19,94 +19,79 @@ LC_IMPORT_C int AssemblerMainARM64(int argc, char const* argv[]); LC_IMPORT_C int AssemblerMain64x0(int argc, char const* argv[]); LC_IMPORT_C int AssemblerMainAMD64(int argc, char const* argv[]); -enum AsmKind : Int32 -{ - kX64Assembler, - k64X0Assembler, - kPOWER64Assembler, - kARM64Assembler, - kAssemblerCount, +enum AsmKind : Int32 { + kX64Assembler, + k64X0Assembler, + kPOWER64Assembler, + kARM64Assembler, + kAssemblerCount, }; -int main(int argc, char const* argv[]) -{ - std::vector<const char*> arg_vec_cstr; - arg_vec_cstr.push_back(argv[0]); +int main(int argc, char const* argv[]) { + std::vector<const char*> arg_vec_cstr; + arg_vec_cstr.push_back(argv[0]); - const Int32 kInvalidAssembler = -1; - Int32 asm_type = kInvalidAssembler; + const Int32 kInvalidAssembler = -1; + Int32 asm_type = kInvalidAssembler; - for (size_t index_arg = 1; index_arg < argc; ++index_arg) - { - if (strstr(argv[index_arg], "--asm:h")) - { - std::printf("asm: Frontend Assembler (64x0, power64, arm64, x64).\n"); - std::printf("asm: Version: %s, Release: %s.\n", kDistVersion, kDistRelease); - std::printf("asm: Designed by Amlal El Mahrouss, Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved.\n"); - std::printf("LibCompiler: Designed by Amlal El Mahrouss, Copyright (C) 2024-2025 Amlal El Mahrouss, all rights reserved.\n"); + for (size_t index_arg = 1; index_arg < argc; ++index_arg) { + if (strstr(argv[index_arg], "--asm:h")) { + std::printf("asm: Frontend Assembler (64x0, power64, arm64, x64).\n"); + std::printf("asm: Version: %s, Release: %s.\n", kDistVersion, kDistRelease); + std::printf( + "asm: Designed by Amlal El Mahrouss, Copyright (C) 2024-2025 Amlal El Mahrouss, all " + "rights reserved.\n"); + std::printf( + "LibCompiler: Designed by Amlal El Mahrouss, Copyright (C) 2024-2025 Amlal El Mahrouss, " + "all rights reserved.\n"); - return 0; - } - else if (strstr(argv[index_arg], "--asm:x64")) - { - asm_type = kX64Assembler; - } - else if (strstr(argv[index_arg], "--asm:aarch64")) - { - asm_type = kARM64Assembler; - } - else if (strstr(argv[index_arg], "--asm:64x0")) - { - asm_type = k64X0Assembler; - } - else if (strstr(argv[index_arg], "--asm:power64")) - { - asm_type = kPOWER64Assembler; - } - else - { - arg_vec_cstr.push_back(argv[index_arg]); - } - } + return 0; + } else if (strstr(argv[index_arg], "--asm:x64")) { + asm_type = kX64Assembler; + } else if (strstr(argv[index_arg], "--asm:aarch64")) { + asm_type = kARM64Assembler; + } else if (strstr(argv[index_arg], "--asm:64x0")) { + asm_type = k64X0Assembler; + } else if (strstr(argv[index_arg], "--asm:power64")) { + asm_type = kPOWER64Assembler; + } else { + arg_vec_cstr.push_back(argv[index_arg]); + } + } - switch (asm_type) - { - case kPOWER64Assembler: { - if (int32_t code = AssemblerMainPower64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) - { - std::printf("asm: frontend exited with code %i.\n", code); - return code; - } - break; - } - case k64X0Assembler: { - if (int32_t code = AssemblerMain64x0(arg_vec_cstr.size(), arg_vec_cstr.data()); code) - { - std::printf("asm: frontend exited with code %i.\n", code); - return code; - } - break; - } - case kARM64Assembler: { - if (int32_t code = AssemblerMainARM64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) - { - std::printf("asm: frontend exited with code %i.\n", code); - return code; - } - break; - } - case kX64Assembler: { - if (int32_t code = AssemblerMainAMD64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) - { - std::printf("asm: frontend exited with code %i.\n", code); - return code; - } - break; - } - default: { - return EXIT_FAILURE; - } - } + switch (asm_type) { + case kPOWER64Assembler: { + if (int32_t code = AssemblerMainPower64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) { + std::printf("asm: frontend exited with code %i.\n", code); + return code; + } + break; + } + case k64X0Assembler: { + if (int32_t code = AssemblerMain64x0(arg_vec_cstr.size(), arg_vec_cstr.data()); code) { + std::printf("asm: frontend exited with code %i.\n", code); + return code; + } + break; + } + case kARM64Assembler: { + if (int32_t code = AssemblerMainARM64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) { + std::printf("asm: frontend exited with code %i.\n", code); + return code; + } + break; + } + case kX64Assembler: { + if (int32_t code = AssemblerMainAMD64(arg_vec_cstr.size(), arg_vec_cstr.data()); code) { + std::printf("asm: frontend exited with code %i.\n", code); + return code; + } + break; + } + default: { + return EXIT_FAILURE; + } + } - return EXIT_SUCCESS; + return EXIT_SUCCESS; } diff --git a/tools/cppdrv.cc b/tools/cppdrv.cc index 72cfb36..8b6238b 100644 --- a/tools/cppdrv.cc +++ b/tools/cppdrv.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -10,21 +10,18 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/ErrorID.h> #include <LibCompiler/Version.h> -#include <iostream> #include <cstring> +#include <iostream> #include <vector> LC_IMPORT_C int CPlusPlusPreprocessorMain(int argc, char const* argv[]); -int main(int argc, char const* argv[]) -{ - if (auto code = CPlusPlusPreprocessorMain(2, argv); - code > 0) - { - std::printf("cppdrv: preprocessor exited with code %i.\n", code); +int main(int argc, char const* argv[]) { + if (auto code = CPlusPlusPreprocessorMain(2, argv); code > 0) { + std::printf("cppdrv: preprocessor exited with code %i.\n", code); - return LIBCOMPILER_EXEC_ERROR; - } + return LIBCOMPILER_EXEC_ERROR; + } - return LIBCOMPILER_SUCCESSS; + return LIBCOMPILER_SUCCESSS; }
\ No newline at end of file diff --git a/tools/cxxdrv.cc b/tools/cxxdrv.cc index 1d59c5c..400e116 100644 --- a/tools/cxxdrv.cc +++ b/tools/cxxdrv.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -10,66 +10,52 @@ #include <LibCompiler/Defines.h> #include <LibCompiler/ErrorID.h> #include <LibCompiler/Version.h> -#include <iostream> #include <cstring> #include <vector> LC_IMPORT_C int CompilerCPlusPlusAMD64(int argc, char const* argv[]); LC_IMPORT_C int AssemblerMainAMD64(int argc, char const* argv[]); -int main(int argc, char const* argv[]) -{ - std::vector<std::string> args_list_cxx; - std::vector<std::string> args_list_asm; - - for (size_t index_arg = 0; index_arg < argc; ++index_arg) - { - if (strstr(argv[index_arg], ".cxx") || - strstr(argv[index_arg], ".cpp") || - strstr(argv[index_arg], ".cc") || - strstr(argv[index_arg], ".c++") || - strstr(argv[index_arg], ".C")) - { - std::string arg = argv[index_arg]; - - arg += ".pp.masm"; - args_list_asm.push_back(arg); - - arg = argv[index_arg]; - arg += ".pp"; - - args_list_cxx.push_back(arg); - } - else if (strstr(argv[index_arg], ".c")) - { - std::printf("cxxdrv: error: Not a C driver.\n"); - return EXIT_FAILURE; - } - } - - for (auto& cli : args_list_cxx) - { - const char* arr_cli[] = {argv[0], cli.data()}; - - if (auto code = CompilerCPlusPlusAMD64(2, arr_cli); - code > 0) - { - std::printf("cxxdrv: compiler exited with code %i.\n", code); - - return LIBCOMPILER_EXEC_ERROR; - } - } - - for (auto& cli : args_list_asm) - { - const char* arr_cli[] = {argv[0], cli.data()}; - - if (auto code = AssemblerMainAMD64(2, arr_cli); - code > 0) - { - std::printf("cxxdrv: assembler exited with code %i.\n", code); - } - } - - return LIBCOMPILER_EXEC_ERROR; +int main(int argc, char const* argv[]) { + std::vector<std::string> args_list_cxx; + std::vector<std::string> args_list_asm; + + for (size_t index_arg = 0; index_arg < argc; ++index_arg) { + if (strstr(argv[index_arg], ".cxx") || strstr(argv[index_arg], ".cpp") || + strstr(argv[index_arg], ".cc") || strstr(argv[index_arg], ".c++") || + strstr(argv[index_arg], ".C")) { + std::string arg = argv[index_arg]; + + arg += ".pp.masm"; + args_list_asm.push_back(arg); + + arg = argv[index_arg]; + arg += ".pp"; + + args_list_cxx.push_back(arg); + } else if (strstr(argv[index_arg], ".c")) { + std::printf("cxxdrv: error: Not a C driver.\n"); + return EXIT_FAILURE; + } + } + + for (auto& cli : args_list_cxx) { + const char* arr_cli[] = {argv[0], cli.data()}; + + if (auto code = CompilerCPlusPlusAMD64(2, arr_cli); code > 0) { + std::printf("cxxdrv: compiler exited with code %i.\n", code); + + return LIBCOMPILER_EXEC_ERROR; + } + } + + for (auto& cli : args_list_asm) { + const char* arr_cli[] = {argv[0], cli.data()}; + + if (auto code = AssemblerMainAMD64(2, arr_cli); code > 0) { + std::printf("cxxdrv: assembler exited with code %i.\n", code); + } + } + + return LIBCOMPILER_EXEC_ERROR; } diff --git a/tools/dbg.cc b/tools/dbg.cc index 67b942e..b9be862 100644 --- a/tools/dbg.cc +++ b/tools/dbg.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -13,7 +13,6 @@ LC_IMPORT_C int DebuggerMachPOSIX(int argc, char const* argv[]); /// @brief Debugger entrypoint. /// @return Status code of debugger. -int main(int argc, char const* argv[]) -{ - return DebuggerMachPOSIX(argc, argv); +int main(int argc, char const* argv[]) { + return DebuggerMachPOSIX(argc, argv); } diff --git a/tools/kdbg.cc b/tools/kdbg.cc index 5aae438..11901e3 100644 --- a/tools/kdbg.cc +++ b/tools/kdbg.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -13,7 +13,6 @@ LC_IMPORT_C int DebuggerNeKernel(int argc, char const* argv[]); /// @brief Debugger entrypoint. /// @return Status code of debugger. -int main(int argc, char const* argv[]) -{ - return DebuggerNeKernel(argc, argv); +int main(int argc, char const* argv[]) { + return DebuggerNeKernel(argc, argv); } diff --git a/tools/ld64.cc b/tools/ld64.cc index 48c1368..fec1314 100644 --- a/tools/ld64.cc +++ b/tools/ld64.cc @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved + Copyright (C) 2024-2025 Amlal EL Mahrous, all rights reserved ------------------------------------------- */ @@ -11,12 +11,10 @@ LC_IMPORT_C int DynamicLinker64PEF(int argc, char const* argv[]); -int main(int argc, char const* argv[]) -{ - if (argc < 1) - { - return 1; - } +int main(int argc, char const* argv[]) { + if (argc < 1) { + return 1; + } - return DynamicLinker64PEF(argc, argv); + return DynamicLinker64PEF(argc, argv); } |
