From bbe2c77243c541ca7e0075149f5be3262eb89523 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Mon, 24 Nov 2025 03:05:29 +0100 Subject: feat! breaking changes on necti sources. Signed-off-by: Amlal El Mahrouss --- dev/CompilerKit/AE.h | 136 -- dev/CompilerKit/Compiler.h | 222 --- dev/CompilerKit/Defines.h | 173 --- dev/CompilerKit/ErrorID.h | 29 - dev/CompilerKit/ErrorOr.h | 55 - dev/CompilerKit/Frontend.h | 138 -- dev/CompilerKit/Macros.h | 28 - dev/CompilerKit/PEF.h | 137 -- dev/CompilerKit/Ref.h | 77 - dev/CompilerKit/StringKit.h | 94 -- dev/CompilerKit/UUID.h | 826 ----------- dev/CompilerKit/Version.h | 15 - dev/CompilerKit/XCOFF.h | 43 - dev/CompilerKit/ck-osx-san.json | 30 - dev/CompilerKit/ck-osx.json | 25 - dev/CompilerKit/ck-posix.json | 24 - dev/CompilerKit/impl/32x0.h | 93 -- dev/CompilerKit/impl/64x0.h | 100 -- dev/CompilerKit/impl/Aarch64.h | 41 - dev/CompilerKit/impl/PowerPC.h | 1557 -------------------- dev/CompilerKit/impl/X64.h | 49 - dev/CompilerKit/src/AssemblyFactory.cc | 52 - dev/CompilerKit/src/Backend/Assembler32x0.cc | 39 - dev/CompilerKit/src/Backend/Assembler64x0.cc | 874 ----------- dev/CompilerKit/src/Backend/AssemblerAMD64.cc | 1204 --------------- dev/CompilerKit/src/Backend/AssemblerARM64.cc | 587 -------- dev/CompilerKit/src/Backend/AssemblerPowerPC.cc | 911 ------------ dev/CompilerKit/src/Frontend.cc | 61 - dev/CompilerKit/src/Frontend/CCompiler64x0.cc | 1287 ---------------- dev/CompilerKit/src/Frontend/CCompilerARM64.cc | 1286 ---------------- dev/CompilerKit/src/Frontend/CCompilerPower64.cc | 1304 ---------------- .../src/Frontend/CPlusPlusCompilerAMD64.cc | 906 ------------ dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc | 678 --------- dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc | 893 ----------- dev/CompilerKit/src/StringKit.cc | 179 --- dev/CompilerKit/utils/AsmUtils.h | 92 -- dev/CompilerKit/utils/CompilerUtils.h | 116 -- dev/CompilerKit/utils/DylibHelpers.h | 63 - 38 files changed, 14424 deletions(-) delete mode 100644 dev/CompilerKit/AE.h delete mode 100644 dev/CompilerKit/Compiler.h delete mode 100644 dev/CompilerKit/Defines.h delete mode 100644 dev/CompilerKit/ErrorID.h delete mode 100644 dev/CompilerKit/ErrorOr.h delete mode 100644 dev/CompilerKit/Frontend.h delete mode 100644 dev/CompilerKit/Macros.h delete mode 100644 dev/CompilerKit/PEF.h delete mode 100644 dev/CompilerKit/Ref.h delete mode 100644 dev/CompilerKit/StringKit.h delete mode 100644 dev/CompilerKit/UUID.h delete mode 100644 dev/CompilerKit/Version.h delete mode 100644 dev/CompilerKit/XCOFF.h delete mode 100644 dev/CompilerKit/ck-osx-san.json delete mode 100644 dev/CompilerKit/ck-osx.json delete mode 100644 dev/CompilerKit/ck-posix.json delete mode 100644 dev/CompilerKit/impl/32x0.h delete mode 100644 dev/CompilerKit/impl/64x0.h delete mode 100644 dev/CompilerKit/impl/Aarch64.h delete mode 100644 dev/CompilerKit/impl/PowerPC.h delete mode 100644 dev/CompilerKit/impl/X64.h delete mode 100644 dev/CompilerKit/src/AssemblyFactory.cc delete mode 100644 dev/CompilerKit/src/Backend/Assembler32x0.cc delete mode 100644 dev/CompilerKit/src/Backend/Assembler64x0.cc delete mode 100644 dev/CompilerKit/src/Backend/AssemblerAMD64.cc delete mode 100644 dev/CompilerKit/src/Backend/AssemblerARM64.cc delete mode 100644 dev/CompilerKit/src/Backend/AssemblerPowerPC.cc delete mode 100644 dev/CompilerKit/src/Frontend.cc delete mode 100644 dev/CompilerKit/src/Frontend/CCompiler64x0.cc delete mode 100644 dev/CompilerKit/src/Frontend/CCompilerARM64.cc delete mode 100644 dev/CompilerKit/src/Frontend/CCompilerPower64.cc delete mode 100644 dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc delete mode 100644 dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc delete mode 100644 dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc delete mode 100644 dev/CompilerKit/src/StringKit.cc delete mode 100644 dev/CompilerKit/utils/AsmUtils.h delete mode 100644 dev/CompilerKit/utils/CompilerUtils.h delete mode 100644 dev/CompilerKit/utils/DylibHelpers.h (limited to 'dev/CompilerKit') diff --git a/dev/CompilerKit/AE.h b/dev/CompilerKit/AE.h deleted file mode 100644 index 7b6d9b4..0000000 --- a/dev/CompilerKit/AE.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#ifndef _NECTI_AE_H_ -#define _NECTI_AE_H_ - -#include - -#define kAEVer (0x0121) - -#define kAEMag0 'A' -#define kAEMag1 'E' - -#define kAESymbolLen (255) -#define kAEPad (8) -#define kAEMagLen (2) -#define kAENullType (0x00) - -/// @author Amlal El Mahrouss - -/// @brief -// Advanced Executable File Format for ld64. -// Reloctable by offset is the default strategy. -// You can also relocate at runtime but that's up to the operating system loader. - -namespace CompilerKit { -// @brief Advanced Executable Header -// One thing to keep in mind. -// This object format, is reloctable. -typedef struct AEHeader final { - Char fMagic[kAEMagLen] = {}; - UInt16 fVersion{kAEVer}; - Char fArch{}; - Char fSubArch{}; - SizeType fCount{}; - Char fSize{}; - SizeType fStartCode{}; - SizeType fCodeSize{}; - Char fPad[kAEPad] = {}; -} PACKED AEHeader, *AEHeaderPtr; - -// @brief Advanced Executable Record. -// Could be data, code or bss. -// fKind must be filled with PEF fields. - -typedef struct AERecordHeader final { - Char fName[kAESymbolLen]; - SizeType fKind; - SizeType fSize; - SizeType fFlags; - UIntPtr fOffset; - Char fPad[kAEPad]; -} PACKED AERecordHeader, *AERecordHeaderPtr; - -enum { - kKindRelocationByOffset = 0x23f, - kKindRelocationAtRuntime = 0x34f, -}; -} // namespace CompilerKit - -// provide operator<< for AE - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::AEHeader)); - - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AERecordHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::AERecordHeader)); - - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::AEHeader)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AERecordHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::AERecordHeader)); - return fp; -} - -namespace CompilerKit::Utils { -/** - * @brief AE Reader protocol - * - */ -class AEReadableProtocol final { - public: - std::ifstream file_pointer_; - - public: - explicit AEReadableProtocol() = default; - ~AEReadableProtocol() = default; - - NECTI_COPY_DELETE(AEReadableProtocol); - - /** - * @brief Read AE Record headers. - * - * @param raw the containing buffer - * @param sz it's size (1 = one AERecordHeader, 2 two AERecordHeader(s)) - * @return AERecordHeaderPtr - */ - AERecordHeaderPtr Read(char* raw, std::size_t sz) { - if (!raw) return nullptr; - - return this->Read_(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 - TypeClass* Read_(char* raw, std::size_t sz) { - file_pointer_.read(raw, std::streamsize(sz)); - return reinterpret_cast(raw); - } -}; -} // namespace CompilerKit::Utils - -#endif /* ifndef _NECTI_AE_H_ */ \ No newline at end of file diff --git a/dev/CompilerKit/Compiler.h b/dev/CompilerKit/Compiler.h deleted file mode 100644 index 1f24370..0000000 --- a/dev/CompilerKit/Compiler.h +++ /dev/null @@ -1,222 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include -#include - -#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface -#define CK_ENCODER : public ::CompilerKit::EncoderInterface - -namespace CompilerKit { -class AssemblyFactory; -class AssemblyInterface; - -/// =========================================================== /// -/// @brief Simple assembly factory -/// =========================================================== /// -class AssemblyFactory final { - public: - explicit AssemblyFactory() = default; - ~AssemblyFactory() = default; - - NECTI_COPY_DEFAULT(AssemblyFactory); - - public: - enum { - kArchInvalid = 0, - kArchAMD64 = 100, - kArch32x0, - kArch64x0, - kArchRISCV, - kArchPowerPC, - kArchAARCH64, - kArchUnknown, - kArchCount = kArchUnknown - kArchAMD64, - }; - - Int32 Compile(std::string sourceFile, const Int32& arch) noexcept; - - void Mount(AssemblyInterface* mountPtr) noexcept; - AssemblyInterface* Unmount() noexcept; - - private: - AssemblyInterface* fMounted{nullptr}; -}; - -/// =========================================================== /// -/// @brief Assembly to binary generator class. -/// @note This interface creates according to the CPU target of the child class. -/// =========================================================== /// -class AssemblyInterface { - public: - explicit AssemblyInterface() = default; - virtual ~AssemblyInterface() = default; - - NECTI_COPY_DEFAULT(AssemblyInterface); - - virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } - - /// =========================================================== /// - /// @brief compile to object file. - /// @note Example C++ -> MASM -> AE object. - /// =========================================================== /// - virtual Int32 CompileToFormat(std::string src, Int32 arch) = 0; -}; - -/// =========================================================== /// -/// @brief Number casting unions for different sizes. -/// =========================================================== /// -union NumberCastBase { - NumberCastBase() = default; - ~NumberCastBase() = default; -}; - -union NumberCast64 final { - NumberCast64() = default; - explicit NumberCast64(UInt64 raw) : raw(raw) {} - - ~NumberCast64() { raw = 0; } - - Char number[8]; - UInt64 raw; -}; - -union NumberCast32 final { - NumberCast32() = default; - explicit NumberCast32(UInt32 raw) : raw(raw) {} - - ~NumberCast32() { raw = 0; } - - Char number[4]; - UInt32 raw; -}; - -union NumberCast16 final { - NumberCast16() = default; - explicit NumberCast16(UInt16 raw) : raw(raw) {} - - ~NumberCast16() { raw = 0; } - - Char number[2]; - UInt16 raw; -}; - -union NumberCast8 final { - NumberCast8() = default; - explicit NumberCast8(UInt8 raw) : raw(raw) {} - - ~NumberCast8() { raw = 0; } - - Char number; - UInt8 raw; -}; - -/// =========================================================== /// -/// @brief Assembly encoder interface. -/// =========================================================== /// -class EncoderInterface { - public: - explicit EncoderInterface() = default; - virtual ~EncoderInterface() = default; - - NECTI_COPY_DEFAULT(EncoderInterface); - - virtual std::string CheckLine(std::string line, std::string file) = 0; - virtual bool WriteLine(std::string line, std::string file) = 0; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; -}; - -/// =========================================================== /// -/// @brief Different architecture encoders. -/// =========================================================== /// - -#ifdef __ASM_NEED_AMD64__ - -class EncoderAMD64 final : public EncoderInterface { - public: - explicit EncoderAMD64() = default; - ~EncoderAMD64() override = default; - - NECTI_COPY_DEFAULT(EncoderAMD64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; - - virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); - virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); -}; - -#endif // __ASM_NEED_AMD64__ - -#ifdef __ASM_NEED_ARM64__ - -class EncoderARM64 final : public EncoderInterface { - public: - explicit EncoderARM64() = default; - ~EncoderARM64() override = default; - - NECTI_COPY_DEFAULT(EncoderARM64); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_ARM64__ - -#ifdef __ASM_NEED_64x0__ - -class Encoder64x0 final : public EncoderInterface { - public: - explicit Encoder64x0() = default; - ~Encoder64x0() override = default; - - NECTI_COPY_DEFAULT(Encoder64x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_64x0__ - -#ifdef __ASM_NEED_32x0__ - -class Encoder32x0 final : public EncoderInterface { - public: - explicit Encoder32x0() = default; - ~Encoder32x0() override = default; - - NECTI_COPY_DEFAULT(Encoder32x0); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_32x0__ - -#ifdef __ASM_NEED_PPC__ - -class EncoderPowerPC final : public EncoderInterface { - public: - explicit EncoderPowerPC() = default; - ~EncoderPowerPC() override = default; - - NECTI_COPY_DEFAULT(EncoderPowerPC); - - virtual std::string CheckLine(std::string line, std::string file) override; - virtual bool WriteLine(std::string line, std::string file) override; - virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; -}; - -#endif // __ASM_NEED_32x0__ -} // namespace CompilerKit diff --git a/dev/CompilerKit/Defines.h b/dev/CompilerKit/Defines.h deleted file mode 100644 index d036767..0000000 --- a/dev/CompilerKit/Defines.h +++ /dev/null @@ -1,173 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#ifndef __NECTI_DEFINES_H__ -#define __NECTI_DEFINES_H__ - -/// =========================================================== /// -/// @file Defines.h -/// @author Amlal El Mahrouss -/// @brief Basic defines and types for CompilerKit. -/// =========================================================== /// - -#ifndef Yes -#define Yes true -#endif // ifndef Yes - -#ifndef No -#define No false -#endif // ifndef No - -#ifndef YES -#define YES true -#endif // ifndef YES - -#ifndef NO -#define NO false -#endif // ifndef NO - -#define SizeType size_t - -#define VoidPtr void* -#define voidPtr VoidPtr - -#define UIntPtr uintptr_t - -#define Int64 int64_t -#define UInt64 uint64_t - -#define Int32 int -#define UInt32 unsigned - -#define Bool bool - -#define Int16 int16_t -#define UInt16 uint16_t - -#define Int8 int8_t -#define UInt8 uint8_t - -#define Char char -#define Boolean bool - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define nullPtr std::nullptr_t - -#define MUST_PASS(E) assert(E) - -#ifndef __FORCE_STRLEN -#define __FORCE_STRLEN 1 - -#define string_length(len) strlen(len) -#endif - -#ifndef __FORCE_MEMCPY -#define __FORCE_MEMCPY 1 - -#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) -#endif - -#define ATTRIBUTE(X) __attribute__((X)) -#define PACKED ATTRIBUTE(packed) - -#define kObjectFileExt ".obj" -#define kBinaryFileExt ".bin" - -#define kAsmFileExts \ - { ".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64" } - -#define kAsmFileExtsMax (7U) - -#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) - -#ifdef MSVC -#pragma scalar_storage_order big - endian -#endif // ifdef MSVC - -#define NECTI_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define NECTI_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#define CK_IMPORT_C extern "C" -#define CK_IMPORT extern -namespace CompilerKit { -inline constexpr int kBaseYear = 1900; - -typedef std::string STLString; - -inline STLString current_date() noexcept { - auto time_data = time(nullptr); - auto time_struct = gmtime(&time_data); - - STLString fmt = std::to_string(kBaseYear + time_struct->tm_year); - - fmt += "-"; - fmt += std::to_string(time_struct->tm_mon + 1); - fmt += "-"; - fmt += std::to_string(time_struct->tm_mday); - - return fmt; -} - -inline bool to_str(Char* str, Int32 limit, Int32 base) noexcept { - if (limit == 0) return false; - - Int32 copy_limit = limit; - Int32 cnt = 0; - Int32 ret = base; - - while (limit != 1) { - ret = ret % 10; - str[cnt] = ret; - - ++cnt; - --limit; - --ret; - } - - str[copy_limit] = '\0'; - return true; -} - -inline bool install_signal(Int32 signal, void (*handler)(int)) noexcept { - if (handler == nullptr) return false; - - if (::signal(signal, handler) == SIG_ERR) { - return false; - } - - return true; -} -} // namespace CompilerKit - -#endif /* ifndef __NECTI_DEFINES_H__ */ diff --git a/dev/CompilerKit/ErrorID.h b/dev/CompilerKit/ErrorID.h deleted file mode 100644 index 35039ab..0000000 --- a/dev/CompilerKit/ErrorID.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -#include - -/// =========================================================== /// -/// @file ErrorID.h -/// @author Amlal El Mahrouss -/// @brief Error IDs for CompilerKit. -/// =========================================================== /// - -#define NECTI_SUCCESS 0 -#define NECTI_EXEC_ERROR -30 -#define NECTI_FILE_NOT_FOUND -31 -#define NECTI_DIR_NOT_FOUND -32 -#define NECTI_FILE_EXISTS -33 -#define NECTI_TOO_LONG -34 -#define NECTI_INVALID_DATA -35 -#define NECTI_UNIMPLEMENTED -36 -#define NECTI_FAT_ERROR -37 -#define NECTI_INVALID_ARCH -38 diff --git a/dev/CompilerKit/ErrorOr.h b/dev/CompilerKit/ErrorOr.h deleted file mode 100644 index ac42c19..0000000 --- a/dev/CompilerKit/ErrorOr.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -/// =========================================================== /// -/// @file ErrorOr.h -/// @author Amlal El Mahrouss -/// @brief ErrorOr for CompilerKit. -/// =========================================================== /// - -#include -#include -#include -#include - -namespace CompilerKit { -using ErrorT = Int32; - -template -class ErrorOr final { - public: - ErrorOr() = default; - ~ErrorOr() = default; - - public: - explicit ErrorOr(ErrorT err) : mId(err) {} - explicit ErrorOr(nullPtr null) {} - explicit ErrorOr(T klass) : mRef(klass) {} - - ErrorOr& operator=(const ErrorOr&) = default; - ErrorOr(const ErrorOr&) = default; - - Ref Leak() { return mRef; } - - ErrorT Error() { return mId; } - - Bool HasError() { return mId != NECTI_SUCCESS; } - - explicit operator bool() { return mRef; } - - private: - Ref mRef; - ErrorT mId{0}; -}; - -using ErrorOrAny = ErrorOr; -using ErrorOrString = ErrorOr; -} // namespace CompilerKit diff --git a/dev/CompilerKit/Frontend.h b/dev/CompilerKit/Frontend.h deleted file mode 100644 index df70048..0000000 --- a/dev/CompilerKit/Frontend.h +++ /dev/null @@ -1,138 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include - -#define CK_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface - -namespace CompilerKit { -inline static auto kInvalidFrontend = "(null)"; - -struct SyntaxLeafList; -struct SyntaxLeafList; -struct CompilerKeyword; - -/// =========================================================== /// -/// @note we want to do that to separate keywords. -/// =========================================================== /// - -enum KeywordKind { - kKeywordKindNamespace, - kKeywordKindFunctionStart, - kKeywordKindFunctionEnd, - kKeywordKindVariable, - kKeywordKindVariablePtr, - kKeywordKindType, - kKeywordKindTypePtr, - kKeywordKindExpressionBegin, - kKeywordKindExpressionEnd, - kKeywordKindArgSeparator, - kKeywordKindBodyStart, - kKeywordKindBodyEnd, - kKeywordKindClass, - kKeywordKindPtrAccess, - kKeywordKindAccess, - kKeywordKindIf, - kKeywordKindElse, - kKeywordKindElseIf, - kKeywordKindVariableAssign, - kKeywordKindVariableDec, - kKeywordKindVariableInc, - kKeywordKindConstant, - kKeywordKindTypedef, - kKeywordKindEndInstr, - kKeywordKindSpecifier, - kKeywordKindInvalid, - kKeywordKindReturn, - kKeywordKindCommentInline, - kKeywordKindCommentMultiLineStart, - kKeywordKindCommentMultiLineEnd, - kKeywordKindEq, - kKeywordKindNotEq, - kKeywordKindGreaterEq, - kKeywordKindLessEq, - kKeywordKindPtr, -}; - -/// =========================================================== /// -/// \brief Compiler keyword information struct. -/// =========================================================== /// -struct CompilerKeyword { - CompilerKeyword(STLString name, KeywordKind kind) : keyword_name(name), keyword_kind(kind) {} - - STLString keyword_name{""}; - KeywordKind keyword_kind{kKeywordKindInvalid}; -}; - -struct SyntaxLeafList final { - struct SyntaxLeaf final { - Int32 fUserType{0U}; - CompilerKeyword fUserData{"", kKeywordKindInvalid}; - - STLString fUserValue{""}; - struct SyntaxLeaf* fNext{nullptr}; - }; - - std::vector fLeafList; - SizeType fNumLeafs{0}; - - SizeType SizeOf() { return fNumLeafs; } - std::vector& Get() { return fLeafList; } - SyntaxLeaf& At(SizeType index) { return fLeafList[index]; } -}; - -/// =========================================================== /// -/// find the perfect matching word in a haystack. -/// \param haystack base string -/// \param needle the string we search for. -/// \return if we found it or not. -/// =========================================================== /// -Bool find_word(STLString haystack, STLString needle) noexcept; - -/// =========================================================== /// -/// find a word within strict conditions and returns a range of it. -/// \param haystack -/// \param needle -/// \return position of needle. -/// =========================================================== /// -SizeType find_word_range(STLString haystack, STLString needle) noexcept; - -/// =========================================================== /// -/// @brief Compiler backend, implements a frontend, such as C, C++... -/// See Toolchain, for some examples. -/// =========================================================== /// -class CompilerFrontendInterface { - public: - explicit CompilerFrontendInterface() = default; - virtual ~CompilerFrontendInterface() = default; - - NECTI_COPY_DEFAULT(CompilerFrontendInterface); - - /// =========================================================== /// - // NOTE: cast this to your user defined ast. - /// =========================================================== /// - typedef VoidPtr AstType; - - /// =========================================================== /// - //! @brief Compile a syntax tree ouf of the text. - //! Also takes the source file name for metadata. - /// =========================================================== /// - - virtual CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) = 0; - - /// =========================================================== /// - //! @brief What language are we dealing with? - /// =========================================================== /// - virtual const char* Language() { return kInvalidFrontend; } - - /// =========================================================== /// - /// @brief Checks if language is a valid frontend. - /// =========================================================== /// - virtual bool IsValid() { return strcmp(this->Language(), kInvalidFrontend) > 0; } -}; -} // namespace CompilerKit diff --git a/dev/CompilerKit/Macros.h b/dev/CompilerKit/Macros.h deleted file mode 100644 index 6cef758..0000000 --- a/dev/CompilerKit/Macros.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// @brief provide support for Macros.h header. - -#ifndef _NECTI_MACROS_H_ -#define _NECTI_MACROS_H_ - -#define NECTI_COPY_DELETE(KLASS) \ - KLASS& operator=(const KLASS&) = delete; \ - KLASS(const KLASS&) = delete; - -#define NECTI_COPY_DEFAULT(KLASS) \ - KLASS& operator=(const KLASS&) = default; \ - KLASS(const KLASS&) = default; - -#define NECTI_MOVE_DELETE(KLASS) \ - KLASS& operator=(KLASS&&) = delete; \ - KLASS(KLASS&&) = delete; - -#define NECTI_MOVE_DEFAULT(KLASS) \ - KLASS& operator=(KLASS&&) = default; \ - KLASS(KLASS&&) = default; - -#endif /* ifndef _NECTI_MACROS_H_ */ diff --git a/dev/CompilerKit/PEF.h b/dev/CompilerKit/PEF.h deleted file mode 100644 index edf8f5d..0000000 --- a/dev/CompilerKit/PEF.h +++ /dev/null @@ -1,137 +0,0 @@ -/* ========================================= - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include - -// @file PEF.h -// @brief Preferred Executable Format - -#define kPefMagic "Open" -#define kPefMagicFat "nepO" - -#define kPefExt ".exec" -#define kPefDylibExt ".dylib" -#define kPefLibExt ".lib" -#define kPefObjectExt ".obj" -#define kPefDebugExt ".dbg" -#define kPefDriverExt ".sys" - -#define kPefZero128 ".zero128" -#define kPefCode128 ".code128" -#define kPefData128 ".data128" - -#define kPefZero64 ".zero64" -#define kPefCode64 ".code64" -#define kPefData64 ".data64" - -/* @note counting the \0 at the end */ -#define kPefMagicLen (5) - -#define kPefVersion (0x0500) -#define kPefNameLen (255) - -#define kPefBaseOrigin (0x40000000) - -/* @note this doesn't have to be __ImageStart only, any C initialization stub will do. */ -#define kPefStart "__ImageStart" - -namespace CompilerKit { -/* @brief Architecture type. */ -enum { - kPefArchIntel86S, - kPefArchAMD64, - kPefArchRISCV, - kPefArch64000, /* Open64x0 RISC architecture. */ - kPefArch32000, - kPefArchPowerPC, /* 64-bit POWER architecture. */ - kPefArchARM64, - kPefArchCount = (kPefArchARM64 - kPefArchIntel86S) + 1, - kPefArchInvalid = 0xFF, -}; - -/* @brief Architecture vendor. */ -enum { - kPefSubArchGeneric = 0, - kPefSubArchAMD = 200, - kPefSubArchIntel, - kPefSubArchARM, - kPefSubArchIBM, -}; - -enum { - kPefKindInvalid = 0, - kPefKindExec = 1, /* .exec */ - kPefKindDylib = 2, /* .dylib */ - kPefKindObject = 4, /* .obj */ - kPefKindDebug = 5, /* .dbg */ - kPefKindDriver = 6, - kPefKindCount, -}; - -/* PEF container information */ -typedef struct PEFContainer final { - Char Magic[kPefMagicLen]; - UInt32 Linker; /* Linker used to link executable */ - UInt32 Version; - UInt32 Kind; - UInt32 Abi; - UInt32 Cpu; - UInt32 SubCpu; /* Cpu specific information */ - UIntPtr Start; /* Origin of code */ - SizeType HdrSz; /* Size of header */ - SizeType Count; /* container header count */ - UInt32 Checksum; /* Whole binary checksum */ -} PACKED PEFContainer, *PEFContainerPtr; - -/* First PEFCommandHeader starts after PEFContainer */ -/* Last container is __exec_end */ - -/* PEF executable section and commands. */ - -/* @brief Command Header, a la Mach-O, designed with FAT binaries and virtual memory in mind. */ -typedef struct PEFCommandHeader final { - Char Name[kPefNameLen]; /* container name */ - UInt32 Cpu; /* container cpu */ - UInt32 SubCpu; /* container sub-cpu */ - UInt32 Flags; /* container flags */ - UInt16 Kind; /* container kind */ - UIntPtr Offset; /* File offset */ - SizeType OffsetSize; - UIntPtr VirtualAddress; /* Virtual Address */ - SizeType VirtualSize; /* Virtual Size */ -} PACKED PEFCommandHeader, *PEFCommandHeaderPtr; - -enum { - kPefInvalid = 0x0, - kPefCode = 0xC, - kPefData = 0xD, - kPefZero = 0xE, - kPefLinkerID = 0x1, - kPefCount = 4, -}; -} // namespace CompilerKit - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFContainer& container) { - fp.write((char*) &container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFCommandHeader& container) { - fp.write((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFContainer& container) { - fp.read((char*) &container, sizeof(CompilerKit::PEFContainer)); - return fp; -} - -inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFCommandHeader& container) { - fp.read((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); - return fp; -} diff --git a/dev/CompilerKit/Ref.h b/dev/CompilerKit/Ref.h deleted file mode 100644 index 66ed60f..0000000 --- a/dev/CompilerKit/Ref.h +++ /dev/null @@ -1,77 +0,0 @@ - -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#pragma once - -#include - -namespace CompilerKit { -/// @author Amlal El Mahrouss -/// @brief Reference holder class, refers to a pointer of data in static memory. -template -class Ref final { - public: - explicit Ref() = default; - - ~Ref() { - if (m_Strong) { - MUST_PASS(m_Class); - if (m_Class) delete m_Class; - m_Class = nullptr; - } - } - - NECTI_COPY_DEFAULT(Ref); - - public: - explicit Ref(T* cls, const Bool& strong = false) : m_Class(cls), m_Strong(strong) {} - - Ref& operator=(T ref) { - *m_Class = ref; - return *this; - } - - public: - T* operator->() const { return m_Class; } - - T& Leak() { return *m_Class; } - - T operator*() { return *m_Class; } - - Bool IsStrong() const { return m_Strong; } - - explicit operator bool() { return *m_Class; } - - private: - T* m_Class{nullptr}; - Bool m_Strong{false}; -}; - -// @author Amlal El Mahrouss -// @brief Non null Reference holder class, refers to a pointer of data in static memory. -template -class NonNullRef final { - public: - explicit NonNullRef() = delete; - - explicit NonNullRef(T* ref) : m_Ref(ref, true) {} - - Ref& operator->() { - MUST_PASS(m_Ref); - return m_Ref; - } - - NonNullRef& operator=(const NonNullRef& ref) = delete; - NonNullRef(const NonNullRef& ref) = default; - - private: - Ref m_Ref{nullptr}; -}; -} // namespace CompilerKit diff --git a/dev/CompilerKit/StringKit.h b/dev/CompilerKit/StringKit.h deleted file mode 100644 index eb7ccc3..0000000 --- a/dev/CompilerKit/StringKit.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#ifndef __NECTI_STRINGKIT__ -#define __NECTI_STRINGKIT__ - -#include -#include - -/// =========================================================== /// -/// @file StringKit.h -/// @author Amlal El Mahrouss -/// @brief StringKit for CompilerKit. -/// =========================================================== /// - -namespace CompilerKit { -class StringBuilder; -class BasicString; - -/** - * @brief BasicString class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ - -class BasicString final { - public: - explicit BasicString() = delete; - - explicit BasicString(SizeType Sz) noexcept : m_Sz(Sz) { - m_Data = new Char[Sz]; - assert(m_Data); - } - - ~BasicString() noexcept { - if (m_Data) { - memset(m_Data, 0, m_Sz); - delete[] m_Data; - - m_Data = nullptr; - } - } - - NECTI_COPY_DEFAULT(BasicString); - - Char* Data(); - const Char* CData() const; - SizeType Length() const; - - bool operator==(const Char* rhs) const; - bool operator!=(const Char* rhs) const; - - bool operator==(const BasicString& rhs) const; - bool operator!=(const BasicString& rhs) const; - - BasicString& operator+=(const Char* rhs); - BasicString& operator+=(const Char rhs); - BasicString& operator+=(const BasicString& rhs); - - explicit operator bool() { return m_Data && m_Data[0] != 0; } - - bool operator!() { return !m_Data || m_Data[0] == 0; } - - private: - Char* m_Data{nullptr}; - SizeType m_Sz{0}; - SizeType m_Cur{0}; - - friend class StringBuilder; -}; - -/** - * @brief StringBuilder class - * @note These results shall call be delete[] after they're used. - */ -struct StringBuilder final { - static BasicString Construct(const Char* data); - static BasicString FromInt(const char* fmt, int n); - static BasicString FromBool(const char* fmt, bool n); - static BasicString Format(const char* fmt, const char* from); - static Bool Equals(const char* lhs, const char* rhs); -}; - -using BasicStringOr = ErrorOr; -using BasicStringPtr = BasicString*; -using BasicStringRef = Ref; -} // namespace CompilerKit - -#endif /* ifndef __NECTI_STRINGKIT__ */ diff --git a/dev/CompilerKit/UUID.h b/dev/CompilerKit/UUID.h deleted file mode 100644 index 98733fd..0000000 --- a/dev/CompilerKit/UUID.h +++ /dev/null @@ -1,826 +0,0 @@ -#ifndef STDUUID_H -#define STDUUID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus - -#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) -#define LIBUUID_CPP20_OR_GREATER -#endif - -#endif - -#ifdef LIBUUID_CPP20_OR_GREATER -#include -#else -#include -#endif - -#ifdef _WIN32 - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#ifdef UUID_TIME_GENERATOR -#include -#pragma comment(lib, "IPHLPAPI.lib") -#endif - -#elif defined(__linux__) || defined(__unix__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#elif defined(__APPLE__) - -#ifdef UUID_SYSTEM_GENERATOR -#include -#endif - -#endif - -namespace uuids { -#ifdef __cpp_lib_span -template -using span = std::span; -#else -template -using span = gsl::span; -#endif - -namespace Detail { - template - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept { - if (ch >= static_cast('0') && ch <= static_cast('9')) - return static_cast(ch - static_cast('0')); - if (ch >= static_cast('a') && ch <= static_cast('f')) - return static_cast(10 + ch - static_cast('a')); - if (ch >= static_cast('A') && ch <= static_cast('F')) - return static_cast(10 + ch - static_cast('A')); - return 0; - } - - template - [[nodiscard]] constexpr std::basic_string_view to_string_view(TChar const* str) noexcept { - return str; - } - - template - [[nodiscard]] constexpr std::basic_string_view - 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(start); - const uint8_t* finish = static_cast(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(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((bitCount >> 24) & 0xFF)); - process_byte(static_cast((bitCount >> 16) & 0xFF)); - process_byte(static_cast((bitCount >> 8) & 0xFF)); - process_byte(static_cast((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(d32[0] >> 24); - digest[di++] = static_cast(d32[0] >> 16); - digest[di++] = static_cast(d32[0] >> 8); - digest[di++] = static_cast(d32[0] >> 0); - - digest[di++] = static_cast(d32[1] >> 24); - digest[di++] = static_cast(d32[1] >> 16); - digest[di++] = static_cast(d32[1] >> 8); - digest[di++] = static_cast(d32[1] >> 0); - - digest[di++] = static_cast(d32[2] >> 24); - digest[di++] = static_cast(d32[2] >> 16); - digest[di++] = static_cast(d32[2] >> 8); - digest[di++] = static_cast(d32[2] >> 0); - - digest[di++] = static_cast(d32[3] >> 24); - digest[di++] = static_cast(d32[3] >> 16); - digest[di++] = static_cast(d32[3] >> 8); - digest[di++] = static_cast(d32[3] >> 0); - - digest[di++] = static_cast(d32[4] >> 24); - digest[di++] = static_cast(d32[4] >> 16); - digest[di++] = static_cast(d32[4] >> 8); - digest[di++] = static_cast(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(m_block[i * 4 + 0] << 24); - w[i] |= static_cast(m_block[i * 4 + 1] << 16); - w[i] |= static_cast(m_block[i * 4 + 2] << 8); - w[i] |= static_cast(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 - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid[37] = L"00000000-0000-0000-0000-000000000000"; - - template - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder[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 Allocator = std::allocator> -std::basic_string 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 const& arr) noexcept : data{arr} {} - - explicit uuid(span bytes) { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template - 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 as_bytes() const { - return span(reinterpret_cast(data.data()), 16); - } - - template - [[nodiscard]] constexpr static bool is_valid_uuid(StringType const& in_str) noexcept { - auto str = Detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) return false; - - if (str.front() == '{') hasBraces = 1; - if (hasBraces && str.back() != '}') return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { - if (str[i] == '-') continue; - - if (index >= 16 || !std::isxdigit(static_cast(str[i]))) { - return false; - } - - if (firstDigit) { - firstDigit = false; - } else { - index++; - firstDigit = true; - } - } - - if (index < 16) { - return false; - } - - return true; - } - - template - [[nodiscard]] constexpr static std::optional 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 data{{0}}; - - if (str.empty()) return {}; - - if (str.front() == '{') hasBraces = 1; - if (hasBraces && str.back() != '}') return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { - if (str[i] == '-') continue; - - if (index >= 16 || !std::isxdigit(static_cast(str[i]))) { - return {}; - } - - if (firstDigit) { - data[index] = static_cast(Detail::hex2char(str[i]) << 4); - firstDigit = false; - } else { - data[index] = static_cast(data[index] | Detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) { - return {}; - } - - return uuid{data}; - } - - private: - std::array data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template - friend std::basic_ostream& operator<<(std::basic_ostream& s, - uuid const& id); - - template - friend std::basic_string to_string(uuid const& id); - - friend std::hash; -}; - -// -------------------------------------------------------------------------------------------------------------------------- -// 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 -[[nodiscard]] inline std::basic_string to_string(uuid const& id) { - std::basic_string uustr{Detail::empty_guid}; - - 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[id.data[index] >> 4 & 0x0f]; - uustr[++i] = Detail::guid_encoder[id.data[index] & 0x0f]; - index++; - } - - return uustr; -} - -template -std::basic_ostream& operator<<(std::basic_ostream& s, uuid const& id) { - s << to_string(id); - return s; -} - -inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept { - lhs.swap(rhs); -} - -// -------------------------------------------------------------------------------------------------------------------------- -// namespace IDs that could be used for generating name-based uuids -// -------------------------------------------------------------------------------------------------------------------------- - -// Name string is a fully-qualified domain name -static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, - 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; - -// Name string is a URL -static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, - 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; - -// Name string is an ISO OID (See https://oidref.com/, -// https://en.wikipedia.org/wiki/Object_identifier) -static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, - 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; - -// Name string is an X.500 DN, in DER or a text output format (See -// https://en.wikipedia.org/wiki/X.500, -// https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) -static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, - 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; - -// -------------------------------------------------------------------------------------------------------------------------- -// uuid generators -// -------------------------------------------------------------------------------------------------------------------------- - -#ifdef UUID_SYSTEM_GENERATOR -class uuid_system_generator { - public: - using result_type = uuid; - - uuid operator()() { -#ifdef _WIN32 - GUID newId{}; /// AMLALE: Should be zero-initialized. - HRESULT hr = ::CoCreateGuid(&newId); - - if (FAILED(hr)) { - throw std::system_error(hr, std::system_category(), "CoCreateGuid failed"); - } - - std::array bytes = {{static_cast((newId.Data1 >> 24) & 0xFF), - static_cast((newId.Data1 >> 16) & 0xFF), - static_cast((newId.Data1 >> 8) & 0xFF), - static_cast((newId.Data1) & 0xFF), - static_cast((newId.Data2 >> 8) & 0xFF), - static_cast((newId.Data2) & 0xFF), - static_cast((newId.Data3 >> 8) & 0xFF), - static_cast((newId.Data3) & 0xFF), - newId.Data4[0], newId.Data4[1], newId.Data4[2], - newId.Data4[3], newId.Data4[4], newId.Data4[5], - newId.Data4[6], newId.Data4[7]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__linux__) || defined(__unix__) - - uuid_t id; - uuid_generate(id); - - std::array bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], - id[9], id[10], id[11], id[12], id[13], id[14], id[15]}}; - - return uuid{std::begin(bytes), std::end(bytes)}; - -#elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array arrbytes = {{bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, - bytes.byte4, bytes.byte5, bytes.byte6, bytes.byte7, - bytes.byte8, bytes.byte9, bytes.byte10, bytes.byte11, - bytes.byte12, bytes.byte13, bytes.byte14, bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; -#else - return uuid{}; -#endif - } -}; -#endif - -template -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(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 distribution; - std::shared_ptr generator; -}; - -using uuid_random_generator = basic_uuid_random_generator; - -class uuid_name_generator { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept : nsuuid(namespace_uuid) {} - - template - [[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 - void process_characters(std::basic_string_view const str) { - for (uint32_t c : str) { - hasher.process_byte(static_cast(c & 0xFF)); - if constexpr (!std::is_same_v) { - hasher.process_byte(static_cast((c >> 8) & 0xFF)); - hasher.process_byte(static_cast((c >> 16) & 0xFF)); - hasher.process_byte(static_cast((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; - - std::optional device_address; - - [[nodiscard]] bool get_mac_address() { - if (device_address.has_value()) { - return true; - } - -#ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) return false; - std::vector buf(len); - auto pips = reinterpret_cast(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; -#endif - - return device_address.has_value(); - } - - [[nodiscard]] long long get_time_intervals() { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = std::chrono::duration_cast(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 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 data; - - auto tm = get_time_intervals(); - - auto clock_seq = get_clock_sequence(); - - auto ptm = reinterpret_cast(&tm); - - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); - - memcpy(&data[8], &clock_seq, 2); - - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; - - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; - - memcpy(&data[10], &device_address.value()[0], 6); - - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } - - return {}; - } -}; -#endif -} // namespace uuids - -namespace std { -template <> -struct hash { - 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 hasher; - return static_cast(hasher(uuids::to_string(uuid))); -#else - uint64_t l = - static_cast(uuid.data[0]) << 56 | static_cast(uuid.data[1]) << 48 | - static_cast(uuid.data[2]) << 40 | static_cast(uuid.data[3]) << 32 | - static_cast(uuid.data[4]) << 24 | static_cast(uuid.data[5]) << 16 | - static_cast(uuid.data[6]) << 8 | static_cast(uuid.data[7]); - uint64_t h = - static_cast(uuid.data[8]) << 56 | static_cast(uuid.data[9]) << 48 | - static_cast(uuid.data[10]) << 40 | static_cast(uuid.data[11]) << 32 | - static_cast(uuid.data[12]) << 24 | static_cast(uuid.data[13]) << 16 | - static_cast(uuid.data[14]) << 8 | static_cast(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) { - return result_type(l ^ h); - } else { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } -#endif - } -}; -} // namespace std - -#endif /* STDUUID_H */ diff --git a/dev/CompilerKit/Version.h b/dev/CompilerKit/Version.h deleted file mode 100644 index efd174c..0000000 --- a/dev/CompilerKit/Version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#define kDistVersion "v0.0.7-compilerkit" -#define kDistVersionBCD 0x0002 - -#define ToString(X) Stringify(X) -#define Stringify(X) #X - -#define kDistRelease ToString(kDistReleaseBranch) diff --git a/dev/CompilerKit/XCOFF.h b/dev/CompilerKit/XCOFF.h deleted file mode 100644 index a61949a..0000000 --- a/dev/CompilerKit/XCOFF.h +++ /dev/null @@ -1,43 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - - File: XCOFF.h - Purpose: XCOFF for NeKernel. - - Revision History: - - 04/07/24: Added file (Amlal El Mahrouss) - -======================================== */ - -#ifndef _NECTI_XCOFF_H_ -#define _NECTI_XCOFF_H_ - -#include - -#define kXCOFF64Magic 0x01F7 - -#define kXCOFFRelFlg 0x0001 -#define kXCOFFExecutable 0x0002 -#define kXCOFFLnno 0x0004 -#define kXCOFFLSyms 0x0008 - -namespace CompilerKit { -struct XCoffFileHeader; - -/// @brief XCoff file header. -typedef struct XCoffFileHeader { - UInt16 fMagic; - UInt16 fTarget; - UInt16 fNumSecs; - UInt32 fTimeDat; - UIntPtr fSymPtr; - UInt32 fNumSyms; - UInt16 fOptHdr; // ?: Number of bytes in optional header -} XCoffFileHeader; - -typedef struct XCoffFileHeader* XCoffFileHeaderPtr; -} // namespace CompilerKit - -#endif // ifndef _NECTI_XCOFF_H_ diff --git a/dev/CompilerKit/ck-osx-san.json b/dev/CompilerKit/ck-osx-san.json deleted file mode 100644 index df1c36b..0000000 --- a/dev/CompilerKit/ck-osx-san.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl", - "/opt/homebrew/Cellar/boost/1.87.0/include" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared", - "-fstack-protector-all", - "-fno-omit-frame-pointer", - "-g", - "-fsanitize=address", - "-fsanitize=undefined" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} \ No newline at end of file diff --git a/dev/CompilerKit/ck-osx.json b/dev/CompilerKit/ck-osx.json deleted file mode 100644 index cab0221..0000000 --- a/dev/CompilerKit/ck-osx.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl", - "/opt/homebrew/Cellar/boost/1.87.0/include" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/local/lib/libCompilerKit.dylib", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} \ No newline at end of file diff --git a/dev/CompilerKit/ck-posix.json b/dev/CompilerKit/ck-posix.json deleted file mode 100644 index b748f7a..0000000 --- a/dev/CompilerKit/ck-posix.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compiler_path": "clang++", - "compiler_std": "c++20", - "headers_path": [ - "../CompilerKit", - "../", - "../CompilerKit/src/", - "../CompilerKit/src/impl" - ], - "sources_path": [ - "src/*.cc", - "src/*/*.cc" - ], - "output_name": "/usr/lib/libCompilerKit.so", - "compiler_flags": [ - "-fPIC", - "-shared" - ], - "cpp_macros": [ - "__NECTI__=202505", - "CK_USE_STRUCTS=1", - "kDistReleaseBranch=$(git rev-parse --abbrev-ref HEAD)-$(uuidgen)" - ] -} diff --git a/dev/CompilerKit/impl/32x0.h b/dev/CompilerKit/impl/32x0.h deleted file mode 100644 index 1ad13ee..0000000 --- a/dev/CompilerKit/impl/32x0.h +++ /dev/null @@ -1,93 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include - -// @brief Open32x0 support. -// @file impl/32x0.h - -#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmSyscall 0x02 -#define kAsmJump 0x03 -#define kAsmNoArgs 0x04 - -#define kAsmByte 0 -#define kAsmHWord 1 -#define kAsmWord 2 - -struct CpuCode32x0 { - const char fName[32]; - uint8_t fOpcode; - uint8_t fSize; - uint8_t fFunct3; - uint8_t fFunct7; -}; - -#define kAsmDWordStr ".dword" /* 64 bit */ -#define kAsmWordStr ".word" /* 32-bit */ -#define kAsmHWordStr ".half" /* 16-bit */ -#define kAsmByteStr ".byte" /* 8-bit */ - -inline std::vector kOpcodes32x0 = { - CK_ASM_OPCODE("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) - CK_ASM_OPCODE("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) - CK_ASM_OPCODE("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) - CK_ASM_OPCODE("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) - CK_ASM_OPCODE("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) - CK_ASM_OPCODE("lea", 0b0111011, 0b010, - kAsmImmediate) // setup stack and call, store address to CR (1C). - CK_ASM_OPCODE("ret", 0b0111011, 0b110, - kAsmImmediate) // return from procedure (2C). - CK_ASM_OPCODE("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) - CK_ASM_OPCODE("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) - CK_ASM_OPCODE("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) -}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 16 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: TODO: find one -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/dev/CompilerKit/impl/64x0.h b/dev/CompilerKit/impl/64x0.h deleted file mode 100644 index ce2ae89..0000000 --- a/dev/CompilerKit/impl/64x0.h +++ /dev/null @@ -1,100 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include - -// @brief Open64x0 support. -// @file impl/64x0.h - -#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ - {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, - -#define kAsmImmediate 0x01 -#define kAsmRegToReg 0x02 -#define kAsmSyscall 0x03 -#define kAsmJump 0x04 -#define kAsmNoArgs 0x00 - -typedef char e64k_character_t; -typedef uint8_t e64k_num_t; - -struct CpuOpcode64x0 { - const e64k_character_t fName[32]; - e64k_num_t fOpcode; - e64k_num_t fFunct3; - e64k_num_t fFunct7; -}; - -inline std::vector kOpcodes64x0 = { - CK_ASM_OPCODE("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - CK_ASM_OPCODE("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. - CK_ASM_OPCODE("jlr", 0b1110011, 0b0000111, - kAsmJump) // jump to linked return register - CK_ASM_OPCODE("jrl", 0b1110011, 0b0001111, - kAsmJump) // jump from return register. - CK_ASM_OPCODE("mv", 0b0100011, 0b101, kAsmRegToReg) CK_ASM_OPCODE( - "bg", 0b1100111, 0b111, kAsmRegToReg) CK_ASM_OPCODE("bl", 0b1100111, 0b011, kAsmRegToReg) - CK_ASM_OPCODE("beq", 0b1100111, 0b000, kAsmRegToReg) - CK_ASM_OPCODE("bne", 0b1100111, 0b001, kAsmRegToReg) - CK_ASM_OPCODE("bge", 0b1100111, 0b101, kAsmRegToReg) - CK_ASM_OPCODE("ble", 0b1100111, 0b100, kAsmRegToReg) - CK_ASM_OPCODE("stw", 0b0001111, 0b100, kAsmImmediate) - CK_ASM_OPCODE("ldw", 0b0001111, 0b100, kAsmImmediate) - CK_ASM_OPCODE("lda", 0b0001111, 0b101, kAsmImmediate) - CK_ASM_OPCODE("sta", 0b0001111, 0b001, kAsmImmediate) - // add/sub without carry flag - CK_ASM_OPCODE("add", 0b0101011, 0b100, kAsmImmediate) - CK_ASM_OPCODE("sub", 0b0101011, 0b101, kAsmImmediate) - // add/sub with carry flag - CK_ASM_OPCODE("addc", 0b0101011, 0b110, kAsmImmediate) CK_ASM_OPCODE( - "subc", 0b0101011, 0b111, kAsmImmediate) CK_ASM_OPCODE("sc", 0b1110011, 0b00, kAsmSyscall)}; - -// \brief 64x0 register prefix -// example: r32, r0 -// r32 -> sp -// r0 -> hw zero - -#define kAsmFloatZeroRegister 0 -#define kAsmZeroRegister 0 - -#define kAsmRegisterPrefix "r" -#define kAsmRegisterLimit 30 -#define kAsmPcRegister 17 -#define kAsmCrRegister 18 -#define kAsmSpRegister 5 - -/* return address register */ -#define kAsmRetRegister 19 - -///////////////////////////////////////////////////////////////////////////// - -// SYSTEM CALL/JUMP ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | OFF | - -// IMMEDIATE ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | -// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | - -// REG TO REG ADDRESSING - -// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | - -//////////////////////////////// - -// LOAD/CALL INTERRUPTS - -// SET A HANDLER IN ADDRESS: -// DISABLE INTERRUPTS -// PROCESS INTERRUPT -// ENABLE INTERRUPTS - -//////////////////////////////// diff --git a/dev/CompilerKit/impl/Aarch64.h b/dev/CompilerKit/impl/Aarch64.h deleted file mode 100644 index c1e9c77..0000000 --- a/dev/CompilerKit/impl/Aarch64.h +++ /dev/null @@ -1,41 +0,0 @@ -/* ======================================== - -Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include - -/// @brief ARM64 encoding support. -/// @file impl/Aarch64.h - -struct CpuOpcodeArm64; - -/// @brief ARM64 opcode header. -struct PACKED CpuOpcodeArm64_Data final { - uint32_t fOpcode : 10; // Bits 31–22: Opcode for operation - uint32_t fRm : 5; // Bits 21–16: Source register Rm - uint32_t fShamt : 6; // Bits 15–10: Shift amount - uint32_t fRn : 5; // Bits 9–5: Source register Rn - uint32_t fRd : 5; // Bits 4–0: Destination register Rd -}; - -typedef struct { - uint32_t opcode : 6; // Bits 31–26: Branch opcode - int32_t offset : 26; // Bits 25–0: Signed offset (branch target) -} PACKED CpuOpcodeArm64_Branch; - -typedef struct { - uint32_t size : 2; // Bits 31–30: Size of the data - uint32_t opcode : 7; // Bits 29–23: Opcode for load/store - uint32_t offset : 12; // Bits 22–10: Offset - uint32_t rn : 5; // Bits 9–5: Base address register Rn - uint32_t rt : 5; // Bits 4–0: Target/source register Rt -} PACKED CpuOpcodeArm64_LoadStore; - -#define kAsmRegisterLimit (30) -#define kAsmRegisterPrefix "x" -#define kOpcodeARM64Count (1000) diff --git a/dev/CompilerKit/impl/PowerPC.h b/dev/CompilerKit/impl/PowerPC.h deleted file mode 100644 index 7c7f67c..0000000 --- a/dev/CompilerKit/impl/PowerPC.h +++ /dev/null @@ -1,1557 +0,0 @@ -/* ======================================== - - Some modifications are copyrighted under: - Amlal El Mahrouss - - Original author: - Apple Inc - -======================================== */ - -#pragma once - -#include - -/// @note Based of: -/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html - -#define kOpcodePPCCount (1073U) - -/* - * These defines are use in the cpus field of the instructions. If the field - * is zero it can execute on all cpus. The defines are or'ed together. This - * information is used to set the cpusubtype in the resulting object file. - */ -#define CPU601 0x1 -#define IMPL64 0x2 -#define OPTIONAL 0x4 -#define VMX 0x8 -#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ -#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ - -enum OpcodeType { - NONE, /* no operand */ - JBSR, /* jbsr pseudo op */ - PCREL, /* PC relative (branch offset) */ - BADDR, /* Branch address (sign extended absolute address) */ - D, /* 16 bit displacement */ - DS, /* 14 bit displacement (double word) */ - SI, /* signed 16 bit immediate */ - UI, /* unsigned 16 bit immediate */ - HI, /* high 16 bit immediate (with truncation) */ - GREG, /* general register */ - G0REG, /* general register r1-r31 or 0 */ - FREG, /* float register */ - VREG, /* vector register */ - SGREG, /* segment register */ - SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ - BCND, /* branch condition opcode */ - CRF, /* condition register field */ - CRFONLY, /* condition register field only no expression allowed */ - sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ - mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ - NUM, /* number */ - SNUM, /* signed number */ - NUM0, /* number (where 1< - -// @brief AMD64 support. -// @file impl/X64.h - -#define CK_ASM_OPCODE(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, - -typedef char i64_character_t; -typedef uint8_t i64_byte_t; -typedef uint16_t i64_hword_t; -typedef uint32_t i64_word_t; - -#define kAsmRegisterPrefix "r" - -struct CpuOpcodeAMD64 { - std::string fName; - i64_byte_t fPrefixBytes[4]; - i64_hword_t fOpcode; - i64_hword_t fModReg; - i64_word_t fDisplacment; - i64_word_t fImmediate; -}; - -/// these two are edge cases -#define kAsmIntOpcode 0xCC -#define kasmIntOpcodeAlt 0xCD - -#define kAsmJumpOpcode 0x0F80 -#define kJumpLimit 30 -#define kJumpLimitStandard 0xE3 -#define kJumpLimitStandardLimit 0xEB - -inline std::vector kOpcodesAMD64 = { - CK_ASM_OPCODE("int", 0xCD) CK_ASM_OPCODE("into", 0xCE) CK_ASM_OPCODE("intd", 0xF1) - CK_ASM_OPCODE("int3", 0xC3) CK_ASM_OPCODE("iret", 0xCF) CK_ASM_OPCODE("retf", 0xCB) - CK_ASM_OPCODE("retn", 0xC3) CK_ASM_OPCODE("ret", 0xC3) CK_ASM_OPCODE("sti", 0xfb) - CK_ASM_OPCODE("cli", 0xfa) CK_ASM_OPCODE("hlt", 0xf4) CK_ASM_OPCODE("nop", 0x90) - CK_ASM_OPCODE("mov", 0x48) CK_ASM_OPCODE("call", 0xFF) - CK_ASM_OPCODE("syscall", 0x0F) CK_ASM_OPCODE("xor", 0x48)}; - -#define kAsmRegisterLimit 16 diff --git a/dev/CompilerKit/src/AssemblyFactory.cc b/dev/CompilerKit/src/AssemblyFactory.cc deleted file mode 100644 index 5c606e9..0000000 --- a/dev/CompilerKit/src/AssemblyFactory.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#include -#include - -/** - * @file AssemblyFactory.cc - * @author Amlal El Mahrouss (amlal@nekernel.org) - * @brief Assembly API of NeCTI - * @version 0.0.2 - * - * @copyright Copyright (c) 2024-2025 Amlal El Mahrouss - * - */ - -namespace CompilerKit { -///! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(STLString sourceFile, const Int32& arch) noexcept { - if (sourceFile.length() < 1) return NECTI_UNIMPLEMENTED; - - if (!fMounted) return NECTI_UNIMPLEMENTED; - if (arch != fMounted->Arch()) return NECTI_INVALID_ARCH; - - try { - return this->fMounted->CompileToFormat(sourceFile, arch); - } catch (std::exception& e) { - return NECTI_EXEC_ERROR; - } -} - -///! @brief mount assembly backend. -void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { - if (mountPtr) { - fMounted = mountPtr; - } -} - -///! @brief Unmount assembler. -AssemblyInterface* AssemblyFactory::Unmount() noexcept { - auto mount_prev = fMounted; - - if (fMounted) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit diff --git a/dev/CompilerKit/src/Backend/Assembler32x0.cc b/dev/CompilerKit/src/Backend/Assembler32x0.cc deleted file mode 100644 index 6ffaa6e..0000000 --- a/dev/CompilerKit/src/Backend/Assembler32x0.cc +++ /dev/null @@ -1,39 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file 32asm.cc -// @author Amlal El Mahrouss -// @brief 32x0 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_32x0__ -#define __ASM_NEED_32x0__ 1 -#endif - -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 32x0 Assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(NEAssemblerMain32000) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - return EXIT_SUCCESS; -} diff --git a/dev/CompilerKit/src/Backend/Assembler64x0.cc b/dev/CompilerKit/src/Backend/Assembler64x0.cc deleted file mode 100644 index f9052d2..0000000 --- a/dev/CompilerKit/src/Backend/Assembler64x0.cc +++ /dev/null @@ -1,874 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -/// bugs: 0 - -///////////////////////////////////////////////////////////////////////////////////////// - -// @file Assembler64x0.cc -// @author Amlal El Mahrouss -// @brief 64x000 Assembler. - -// REMINDER: when dealing with an undefined symbol use (string -// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_64x0__ -#define __ASM_NEED_64x0__ 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -static char kOutputArch = CompilerKit::kPefArch64000; - -constexpr auto k64x0IPAlignment = 0x1U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief 64x0 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMain64x0) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-64x0-ver") == 0 || strcmp(argv[i], "-64x0-v") == 0) { - kStdOut - << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: v1.10\nAssembler64x0: Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "-64x0-h") == 0) { - kStdOut << "Assembler64x0: 64x0 Assembler.\nAssembler64x0: Copyright (c) 2024 Mahrouss " - "Logic.\n"; - kStdOut << "--version: Print program version.\n"; - kStdOut << "--verbose: Print verbose output.\n"; - kStdOut << "--binary: Output as flat binary.\n"; - kStdOut << "--64xxx: Compile for a subset of the X64000.\n"; - - return 0; - } else if (strcmp(argv[i], "-64x0-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-64x0-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "Assembler64x0: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "Assembler64x0: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "Assembler64x0: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::Encoder64x0 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "Assembler64x0: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "Assembler64x0: At least one record is needed to write an object " - "file.\nAssembler64x0: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) { - if (kVerbose) kStdOut << "Assembler64x0: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) kStdOut << "Assembler64x0: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "Assembler64x0: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "Assembler64x0: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "Assembler64x0: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "Assembler64x0: Exit failed.\n"; - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment")); - - /// sanity check to avoid stupid linker errors. - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "power-as"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler64x0 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_64x0(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::Encoder64x0::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!Detail::algorithm::is_valid_64x0(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_64x0(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; - - // these don't. - std::vector filter_inst = {"jlr", "jrl", "int"}; - - for (auto& opcode64x0 : kOpcodes64x0) { - if (line.find(opcode64x0.fName) != std::string::npos) { - if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; - - for (auto& op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode64x0.fName); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) { - err_str += "\nMissing space between "; - err_str += opcode64x0.fName; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex_number"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 16 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "Assembler64x0: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::Encoder64x0::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment ")) return true; - - for (auto& opcode64x0 : kOpcodes64x0) { - // strict check here - if (CompilerKit::find_word(line, opcode64x0.fName) && Detail::algorithm::is_valid_64x0(line)) { - std::string name(opcode64x0.fName); - std::string jump_label, cpy_jump_label; - - kBytes.emplace_back(opcode64x0.fOpcode); - kBytes.emplace_back(opcode64x0.fFunct3); - kBytes.emplace_back(opcode64x0.fFunct7); - - // check funct7 type. - switch (opcode64x0.fFunct7) { - // reg to reg means register to register transfer operation. - case kAsmRegToReg: - case kAsmImmediate: { - // \brief how many registers we found. - std::size_t found_some = 0UL; - - for (size_t line_index = 0UL; line_index < line.size(); line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (kOutputArch == CompilerKit::kPefArch64000) { - if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - Detail::print_error("invalid register index, r" + reg_str + - "\nnote: The 64x0 accepts registers from r0 to r20.", - file); - throw std::runtime_error("invalid_register_index"); - } - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - Detail::print_error("invalid register index, r" + reg_str, file); - throw std::runtime_error("invalid_register_index"); - } - - kBytes.emplace_back(reg_index); - ++found_some; - - if (kVerbose) { - kStdOut << "Assembler64x0: Register found: " << register_syntax << "\n"; - kStdOut << "Assembler64x0: Register amount in instruction: " << found_some << "\n"; - } - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode64x0.fFunct7 != kAsmImmediate) { - // remember! register to register! - if (found_some == 1) { - Detail::print_error( - "Too few registers.\ntip: each Assembler64x0 register " - "starts with 'r'.\nline: " + - line, - file); - throw std::runtime_error("not_a_register"); - } - } - - if (found_some < 1 && name != "ldw" && name != "lda" && name != "stw") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "add") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "sub") { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - if (found_some > 0 && name == "pop") { - Detail::print_error( - "invalid combination for opcode 'pop'.\ntip: it expects " - "nothing.\nline: " + - line, - file); - throw std::runtime_error("invalid_comb_op_pop"); - } - } - default: - break; - } - - // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { - auto where_string = name; - - // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || name == "sta") - where_string = ","; - - jump_label = line; - - auto found_sym = false; - - while (jump_label.find(where_string) != std::string::npos) { - jump_label = jump_label.substr(jump_label.find(where_string) + where_string.size()); - - while (jump_label.find(" ") != std::string::npos) { - jump_label.erase(jump_label.find(" "), 1); - } - - if (jump_label[0] != kAsmRegisterPrefix[0] && !isdigit(jump_label[1])) { - if (found_sym) { - Detail::print_error( - "invalid combination of opcode and operands.\nhere -> " + jump_label, file); - throw std::runtime_error("invalid_comb_op_ops"); - } else { - // death trap installed. - found_sym = true; - } - } - } - - cpy_jump_label = jump_label; - - // replace any spaces with $ - if (jump_label[0] == ' ') { - while (jump_label.find(' ') != std::string::npos) { - if (isalnum(jump_label[0]) || isdigit(jump_label[0])) break; - - jump_label.erase(jump_label.find(' '), 1); - } - } - - if (!this->WriteNumber(0, jump_label)) { - // sta expects this: sta 0x000000, r0 - if (name == "sta") { - Detail::print_error("invalid combination of opcode and operands.\nHere ->" + line, - file); - throw std::runtime_error("invalid_comb_op_ops"); - } - } else { - if (name == "sta" && cpy_jump_label.find("extern_segment ") != std::string::npos) { - Detail::print_error("invalid usage extern_segment on 'sta', here: " + line, file); - throw std::runtime_error("invalid_sta_usage"); - } - } - - goto asm_write_label; - } - - // This is the case where we jump to a label, it is also used as a goto. - if (name == "lda" || name == "sta") { - asm_write_label: - if (cpy_jump_label.find('\n') != std::string::npos) - cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); - - if (cpy_jump_label.find("extern_segment") != std::string::npos) { - cpy_jump_label.erase(cpy_jump_label.find("extern_segment"), strlen("extern_segment")); - - if (name == "sta") { - Detail::print_error("extern_segment is not allowed on a sta operation.", file); - throw std::runtime_error("extern_segment_sta_op"); - } else { - goto asm_end_label_cpy; - } - } - - if (name == "lda" || name == "sta") { - for (auto& label : kOriginLabel) { - if (cpy_jump_label == label.first) { - if (kVerbose) { - kStdOut << "Assembler64x0: Replace label " << cpy_jump_label - << " to address: " << label.second << std::endl; - } - - CompilerKit::NumberCast64 num(label.second); - - for (auto& num : num.number) { - kBytes.push_back(num); - } - - goto asm_end_label_cpy; - } - } - - if (cpy_jump_label[0] == '0') { - switch (cpy_jump_label[1]) { - case 'x': - case 'o': - case 'b': - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - default: - break; - } - - if (isdigit(cpy_jump_label[0])) { - if (this->WriteNumber(0, cpy_jump_label)) goto asm_end_label_cpy; - - break; - } - } - } - - if (cpy_jump_label.size() < 1) { - Detail::print_error("label is empty, can't jump on it.", file); - throw std::runtime_error("label_empty"); - } - - /// don't go any further if: - /// load word (ldw) or store word. (stw) - - if (name == "ldw" || name == "stw") break; - - auto mld_reloc_str = std::to_string(cpy_jump_label.size()); - mld_reloc_str += kUndefinedSymbol; - mld_reloc_str += cpy_jump_label; - - bool ignore_back_slash = false; - - for (auto& reloc_chr : mld_reloc_str) { - if (reloc_chr == '\\') { - ignore_back_slash = true; - continue; - } - - if (ignore_back_slash) { - ignore_back_slash = false; - continue; - } - - kBytes.push_back(reloc_chr); - } - - kBytes.push_back('\0'); - goto asm_end_label_cpy; - } - - asm_end_label_cpy: - kOrigin += k64x0IPAlignment; - - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc b/dev/CompilerKit/src/Backend/AssemblerAMD64.cc deleted file mode 100644 index 8c7e21c..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerAMD64.cc +++ /dev/null @@ -1,1204 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerAMD64.cc -/// @author Amlal El Mahrouss -/// @brief AMD64 Assembler. -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -/// bugs: 0 - -/// feature request: 1 -/// Encode registers in mov, add, xor... - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_AMD64__ -#define __ASM_NEED_AMD64__ 1 -#endif - -#define kAssemblerPragmaSymStr "%%" -#define kAssemblerPragmaSym '%' - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -static char kOutputArch = CompilerKit::kPefArchAMD64; - -static constexpr auto kIPAlignement = 0x1U; -static auto kCounter = 0x1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -/// @brief keep it simple by default. -static std::int32_t kRegisterBitWidth = 16U; - -static std::vector kAppBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kDefinedSymbols; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -#include - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainAMD64) { - //////////////// CPU OPCODES BEGIN //////////////// - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - std::string opcodes_jump[kJumpLimit] = {"ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", - "jl", "jle", "jna", "jnae", "jnb", "jnbe", "jnc", "jne", - "jng", "jnge", "jnl", "jnle", "jno", "jnp", "jns", "jnz", - "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuOpcodeAMD64 code{.fName = opcodes_jump[i], - .fOpcode = static_cast(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--amd64:ver") == 0 || strcmp(argv[i], "--amd64:v") == 0) { - kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: " - "v1.10\nAssemblerAMD64: Copyright " - "(c) Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--amd64:h") == 0) { - kStdOut << "AssemblerAMD64: AMD64 Assembler Driver.\nAssemblerAMD64: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version: Print program version.\n"; - kStdOut << "--verbose: Print verbose output.\n"; - kStdOut << "--binary: Output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--amd64:binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--amd64:verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerAMD64: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerAMD64: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - std::string asm_input(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.ends_with(ext)) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - break; - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - kStdOut << "AssemblerAMD64: Assembling: " << argv[i] << "\n"; - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerAMD64: error: " << strerror(errno) << "\n"; - } - - return 1; - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderAMD64 asm64; - - if (kVerbose) { - kStdOut << "Compiling: " + asm_input << "\n"; - kStdOut << "From: " + line << "\n"; - } - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - try { - std::filesystem::remove(object_output); - } catch (...) { - } - - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerAMD64: At least one record is needed to write an object " - "file.\nAssemblerAMD64: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& rec : kRecords) { - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAENullType; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAENullType, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kAppBytes) { - if (byte == 0) continue; - - if (byte == 0xFF) { - byte = 0; - } - - file_ptr_out << reinterpret_cast(&byte)[0]; - } - - if (kVerbose) kStdOut << "AssemblerAMD64: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerAMD64: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerAMD64: Exit failed.\n"; - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the ld - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "power-as"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(kPefCode64) != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(kPefData64) != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(kPefZero64) != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerAMD64 to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment") + 1); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != kDefinedSymbols.end()) { - Detail::print_error("Symbol already defined.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_valid(char c) { - if ((isalpha(c) || isdigit(c)) || - ((c == ' ') || (c == '\t') || (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '*') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || (c == '_') || - (c == ':') || (c == '@') || (c == '.') || (c == '#') || (c == ';'))) - return false; - - return true; -} - -bool is_valid_amd64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_valid) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderAMD64::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || - CompilerKit::find_word(line, kAssemblerPragmaSymStr) || CompilerKit::find_word(line, ";") || - line[0] == kAssemblerPragmaSym) { - if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!Detail::algorithm::is_valid_amd64(line)) { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto& opcodeAMD64 : kOpcodesAMD64) { - if (CompilerKit::find_word(line, opcodeAMD64.fName)) { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num = - CompilerKit::NumberCast64(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast16 num = - CompilerKit::NumberCast16(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast8 num = - CompilerKit::NumberCast8(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "AssemblerAMD64: Found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderAMD64::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment ")) return true; - - struct RegMapAMD64 { - CompilerKit::STLString fName; - i64_byte_t fModRM; - }; - - std::vector kRegisterList{ - {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, - }; - - Bool foundInstruction = false; - - for (auto& opcodeAMD64 : kOpcodesAMD64) { - // strict check here - if (CompilerKit::find_word(line, opcodeAMD64.fName) && - Detail::algorithm::is_valid_amd64(line)) { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (line.find(name) != std::string::npos) { - if (name == "mov" || name == "xor") { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) { - Detail::print_error("Syntax error: missing right operand.", "CompilerKit"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector currentRegList; - - for (auto& reg : kRegisterList) { - std::vector regExt = {'e', 'r'}; - - for (auto& ext : regExt) { - std::string registerName; - - if (bits > 16) registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) { - if (registerName[0] == 'r') { - Detail::print_error("invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back({.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) { - /// very tricky to understand. - /// but this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || currentRegList[1].fName[0] == 'r') { - if (isdigit(currentRegList[0].fName[1]) && isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (name == "mov") { - if (bits == 64 || bits == 32) { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - if (!onlyOneReg) kAppBytes.emplace_back(0x89); - } else if (bits == 16) { - if (hasRBasedRegs) { - Detail::print_error("Invalid combination of operands and registers.", - "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } else { - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - } - } else { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x31); - } - - if (onlyOneReg) { - auto num = GetNumber32(line, ","); - - for (auto& num_idx : num.number) { - if (num_idx == 0) num_idx = 0xFF; - } - - auto modrm = (0x3 << 6 | currentRegList[0].fModRM); - - kAppBytes.emplace_back(0xC7); // prefixed before placing the modrm and then the number. - kAppBytes.emplace_back(modrm); - - if (name != "xor") { - kAppBytes.emplace_back(num.number[0]); - kAppBytes.emplace_back(num.number[1]); - kAppBytes.emplace_back(num.number[2]); - kAppBytes.emplace_back(num.number[3]); - } - - break; - } - - if (currentRegList[1].fName[0] == 'r' && currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) { - if (currentRegList[0].fName[0] == 'r' || currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - } else { - if (currentRegList[0].fName[0] != 'r' || currentRegList[0].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || currentRegList[1].fName[0] == 'e') { - Detail::print_error("Invalid combination of operands and registers.", "CompilerKit"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } - } - - if (name == "int" || name == "into" || name == "intd") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } else if (name == "jmp" || name == "call") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } else if (name == "syscall") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - kAppBytes.emplace_back(0x05); - - break; - } else { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) { - if (foundInstruction) { - Detail::print_error("Syntax error: " + line, file); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) { - kRegisterBitWidth = 64U; - } else if (line.find("bits 32") != std::string::npos) { - kRegisterBitWidth = 32U; - } else if (line.find("bits 16") != std::string::npos) { - kRegisterBitWidth = 16U; - } else if (line.find("org") != std::string::npos) { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) { - if (kOrigin = strtol((line.substr(line.find("org") + strlen("org") + 1)).c_str(), nullptr, - base[i]); - kOrigin) { - if (errno != 0) { - continue; - } else { - if (kVerbose) { - kStdOut << "AssemblerAMD64: Origin Set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += kIPAlignement; - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerARM64.cc b/dev/CompilerKit/src/Backend/AssemblerARM64.cc deleted file mode 100644 index 4961e61..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerARM64.cc +++ /dev/null @@ -1,587 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerARM64.cc -/// @author Amlal El Mahrouss -/// @brief 'ACORN' Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_ARM64__ -#define __ASM_NEED_ARM64__ 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -constexpr auto cPowerIPAlignment = 0x1U; - -static Char kOutputArch = CompilerKit::kPefArchARM64; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainARM64) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { - kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: " << kDistVersion - << "\nAssemblerPower: " - "Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--h") == 0) { - kStdOut << "AssemblerPower: AARCH64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version,/v: print program version.\n"; - kStdOut << "--verbose: print verbose output.\n"; - kStdOut << "--binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerPower: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerPower: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerPower: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderARM64 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerARM64: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerARM64: At least one record is needed to write an object " - "file.\nAssemblerARM64: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerARM64: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "AssemblerARM64: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerARM64: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerARM64: Exit failed.\n"; - - return NECTI_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by Assembler to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_arm64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderARM64::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!Detail::algorithm::is_valid_arm64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_arm64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - return err_str; -} - -bool CompilerKit::EncoderARM64::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerARM64: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderARM64::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment")) return false; - - if (!Detail::algorithm::is_valid_arm64(line)) return false; - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc b/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc deleted file mode 100644 index b4f14ea..0000000 --- a/dev/CompilerKit/src/Backend/AssemblerPowerPC.cc +++ /dev/null @@ -1,911 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file AssemblerPower.cc -/// @author Amlal El Mahrouss -/// @brief POWER Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that li will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -#ifndef __ASM_NEED_PPC__ -#define __ASM_NEED_PPC__ 1 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -constexpr auto cPowerIPAlignment = 0x4U; - -static Char kOutputArch = CompilerKit::kPefArchPowerPC; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginLabel; - -static std::vector kBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector kRecords; -static std::vector kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string line); - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief POWER assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(AssemblerMainPower64) { - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "--ver") == 0 || strcmp(argv[i], "--v") == 0) { - kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: " << kDistVersion - << "\nAssemblerPower: " - "Copyright (c) " - "Amlal El Mahrouss\n"; - return 0; - } else if (strcmp(argv[i], "--h") == 0) { - kStdOut << "AssemblerPower: POWER64 Assembler Driver.\nAssemblerPower: Copyright (c) 2024 " - "Amlal El Mahrouss\n"; - kStdOut << "--version,/v: print program version.\n"; - kStdOut << "--verbose: print verbose output.\n"; - kStdOut << "--binary: output as flat binary.\n"; - - return 0; - } else if (strcmp(argv[i], "--binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "--verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "AssemblerPower: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "AssemblerPower: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto& ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "AssemblerPower: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAENullType, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderPowerPC asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - Detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception& e) { - if (kVerbose) { - std::string what = e.what(); - Detail::print_warning("exit because of: " + what, "CompilerKit"); - } - - std::filesystem::remove(object_output); - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "AssemblerPower: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "AssemblerPower: At least one record is needed to write an object " - "file.\nAssemblerPower: Make one using `public_segment .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return 1; - } - - kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - std::size_t record_count = 0UL; - - for (auto& record_hdr : kRecords) { - record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; - record_hdr.fOffset = record_count; - ++record_count; - - file_ptr_out << record_hdr; - - if (kVerbose) kStdOut << "AssemblerPower: Wrote record " << record_hdr.fName << "...\n"; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto& sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader undefined_sym{0}; - - if (kVerbose) kStdOut << "AssemblerPower: Wrote symbol " << sym << " to file...\n"; - - undefined_sym.fKind = kAENullType; - undefined_sym.fSize = sym.size(); - undefined_sym.fOffset = record_count; - - ++record_count; - - memset(undefined_sym.fPad, kAENullType, kAEPad); - memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - - file_ptr_out << undefined_sym; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "AssemblerPower: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto& byte : kBytes) { - file_ptr_out.write(reinterpret_cast(&byte), sizeof(byte)); - } - - if (kVerbose) kStdOut << "AssemblerPower: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "AssemblerPower: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "AssemblerPower: Exit failed.\n"; - - return NECTI_EXEC_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string line) { - // extern_segment is the opposite of public_segment, it signals to the li - // that we need this symbol. - if (CompilerKit::find_word(line, "extern_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid extern_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment_bin"); - } - - auto name = line.substr(line.find("extern_segment") + strlen("extern_segment") + 1); - - if (name.size() == 0) { - Detail::print_error("Invalid extern_segment", "CompilerKit"); - throw std::runtime_error("invalid_extern_segment"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char& j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // public_segment is a special keyword used by AssemblerPower to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64., - // .zero64 - else if (CompilerKit::find_word(line, "public_segment")) { - if (kOutputAsBinary) { - Detail::print_error("Invalid public_segment directive in flat binary mode.", "CompilerKit"); - throw std::runtime_error("invalid_public_segment_bin"); - } - - auto name = line.substr(line.find("public_segment") + strlen("public_segment")); - - std::string name_copy = name; - - for (char& j : name) { - if (j == ' ') j = '$'; - } - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that li can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) kRecords[kRecords.size() - 1].fSize = kBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAENullType, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace Detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || (c == ',') || (c == '(') || - (c == ')') || (c == '"') || (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.')); -} - -bool is_valid_power64(std::string str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace Detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderPowerPC::CheckLine(std::string line, std::string file) { - std::string err_str; - - if (line.empty() || CompilerKit::find_word(line, "extern_segment") || - CompilerKit::find_word(line, "public_segment") || line.find('#') != std::string::npos || - CompilerKit::find_word(line, ";")) { - if (line.find('#') != std::string::npos) { - line.erase(line.find('#')); - } else if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - /// does the line contains valid input? - if (!Detail::algorithm::is_valid_power64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!Detail::algorithm::is_valid_power64(line)) { - err_str = "Line contains non alphanumeric characters.\nhere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto& ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - - // these do take an argument. - std::vector operands_inst = {"stw", "li"}; - - // these don't. - std::vector filter_inst = {"blr", "bl", "sc"}; - - for (auto& opcode_risc : kOpcodesPowerPC) { - if (CompilerKit::find_word(line, opcode_risc.name)) { - for (auto& op : operands_inst) { - // if only the instruction was found. - if (line == op) { - err_str += "\nMalformed "; - err_str += op; - err_str += " instruction, here -> "; - err_str += line; - } - } - - // if it is like that -> addr1, 0x0 - if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode_risc.name); - it == filter_inst.cend()) { - if (CompilerKit::find_word(line, opcode_risc.name)) { - if (!isspace(line[line.find(opcode_risc.name) + strlen(opcode_risc.name)])) { - err_str += "\nMissing space between "; - err_str += opcode_risc.name; - err_str += " and operands.\nhere -> "; - err_str += line; - } - } - } - - return err_str; - } - } - - err_str += "Unrecognized instruction: " + line; - - return err_str; -} - -bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t& pos, std::string& jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 16 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 2 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + jump_label, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 8 number here: " << jump_label.substr(pos) << "\n"; - } - - for (char& i : num.number) { - kBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num(strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char& i : num.number) { - kBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: found a base 10 number here: " << jump_label.substr(pos) << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderPowerPC::WriteLine(std::string line, std::string file) { - if (CompilerKit::find_word(line, "public_segment")) return false; - if (!Detail::algorithm::is_valid_power64(line)) return false; - - for (auto& opcode_risc : kOpcodesPowerPC) { - // strict check here - if (CompilerKit::find_word(line, opcode_risc.name)) { - std::string name(opcode_risc.name); - std::string jump_label, cpy_jump_label; - std::vector found_registers_index; - - // check funct7 type. - switch (opcode_risc.ops->type) { - default: { - NumberCast32 num(opcode_risc.opcode); - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - break; - } - case BADDR: - case PCREL: { - auto num = GetNumber32(line, name); - - kBytes.emplace_back(num.number[0]); - kBytes.emplace_back(num.number[1]); - kBytes.emplace_back(num.number[2]); - kBytes.emplace_back(0x48); - - break; - } - /// General purpose, float, vector operations. Everything that involve - /// registers. - case G0REG: - case FREG: - case VREG: - case GREG: { - // \brief how many registers we found. - std::size_t found_some_count = 0UL; - std::size_t register_count = 0UL; - std::string opcodeName = opcode_risc.name; - std::size_t register_sum = 0; - - NumberCast64 num(opcode_risc.opcode); - - for (size_t line_index = 0UL; line_index < line.size(); line_index++) { - if (line[line_index] == kAsmRegisterPrefix[0] && isdigit(line[line_index + 1])) { - std::string register_syntax = kAsmRegisterPrefix; - register_syntax += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) register_syntax += line[line_index + 2]; - - std::string reg_str; - reg_str += line[line_index + 1]; - - if (isdigit(line[line_index + 2])) reg_str += line[line_index + 2]; - - // it ranges from r0 to r19 - // something like r190 doesn't exist in the instruction set. - if (isdigit(line[line_index + 3]) && isdigit(line[line_index + 2])) { - reg_str += line[line_index + 3]; - Detail::print_error("invalid register index, r" + reg_str + - "\nnote: The POWER accepts registers from r0 to r32.", - file); - throw std::runtime_error("invalid_register_index"); - } - - // finally cast to a size_t - std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); - - if (reg_index > kAsmRegisterLimit) { - Detail::print_error("invalid register index, r" + reg_str, file); - throw std::runtime_error("invalid_register_index"); - } - - if (opcodeName == "li") { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - auto num = GetNumber32(line, reg_str); - - kBytes.push_back(num.number[0]); - kBytes.push_back(num.number[1]); - kBytes.push_back(numIndex); - kBytes.push_back(0x38); - - // check if bigger than two. - for (size_t i = 2; i < 4; i++) { - if (num.number[i] > 0) { - Detail::print_warning("number overflow on li operation.", file); - break; - } - } - - break; - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - if (register_sum == 0) { - for (size_t indexReg = 0UL; indexReg < reg_index; ++indexReg) { - register_sum += 0x20; - } - } else { - register_sum += reg_index; - } - } - - if (opcodeName == "mr") { - switch (register_count) { - case 0: { - kBytes.push_back(0x78); - - char numIndex = 0x3; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x8; - } - - kBytes.push_back(numIndex); - - break; - } - case 1: { - char numIndex = 0x1; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - for (size_t i = 0; i != reg_index; i++) { - kBytes[kBytes.size() - 1] += 0x8; - } - - kBytes[kBytes.size() - 1] -= 0x8; - - kBytes.push_back(numIndex); - - if (reg_index >= 10 && reg_index < 20) - kBytes.push_back(0x7d); - else if (reg_index >= 20 && reg_index < 30) - kBytes.push_back(0x7e); - else if (reg_index >= 30) - kBytes.push_back(0x7f); - else - kBytes.push_back(0x7c); - - break; - } - default: - break; - } - - ++register_count; - ++found_some_count; - } - - if (opcodeName == "addi") { - if (found_some_count == 2 || found_some_count == 0) - kBytes.emplace_back(reg_index); - else if (found_some_count == 1) - kBytes.emplace_back(0x00); - - ++found_some_count; - - if (found_some_count > 3) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("cmp") != std::string::npos) { - ++found_some_count; - - if (found_some_count > 3) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - } - - if (opcodeName.find("mf") != std::string::npos || - opcodeName.find("mt") != std::string::npos) { - char numIndex = 0; - - for (size_t i = 0; i != reg_index; i++) { - numIndex += 0x20; - } - - num.number[2] += numIndex; - - ++found_some_count; - - if (found_some_count > 1) { - Detail::print_error("Too much registers. -> " + line, file); - throw std::runtime_error("too_much_regs"); - } - - if (kVerbose) { - kStdOut << "AssemblerPower: Found register: " << register_syntax << "\n"; - kStdOut << "AssemblerPower: Amount of registers in instruction: " - << found_some_count << "\n"; - } - - if (reg_index >= 10 && reg_index < 20) - num.number[3] = 0x7d; - else if (reg_index >= 20 && reg_index < 30) - num.number[3] = 0x7e; - else if (reg_index >= 30) - num.number[3] = 0x7f; - else - num.number[3] = 0x7c; - - for (auto ch : num.number) { - kBytes.emplace_back(ch); - } - } - - found_registers_index.push_back(reg_index); - } - } - - if (opcodeName == "addi") { - kBytes.emplace_back(0x38); - } - - if (opcodeName.find("cmp") != std::string::npos) { - char rightReg = 0x0; - - for (size_t i = 0; i != found_registers_index[1]; i++) { - rightReg += 0x08; - } - - kBytes.emplace_back(0x00); - kBytes.emplace_back(rightReg); - kBytes.emplace_back(found_registers_index[0]); - kBytes.emplace_back(0x7c); - } - - if ((opcodeName[0] == 's' && opcodeName[1] == 't')) { - size_t offset = 0UL; - - if (line.find('+') != std::string::npos) { - auto number = GetNumber32(line.substr(line.find("+")), "+"); - offset = number.raw; - } - - kBytes.push_back(offset); - kBytes.push_back(0x00); - kBytes.push_back(register_sum); - - kBytes.emplace_back(0x90); - } - - if (opcodeName == "mr") { - if (register_count == 1) { - Detail::print_error("Too few registers. -> " + line, file); - throw std::runtime_error("too_few_registers"); - } - } - - // we're not in immediate addressing, reg to reg. - if (opcode_risc.ops->type != GREG) { - // remember! register to register! - if (found_some_count == 1) { - Detail::print_error( - "Unrecognized register found.\ntip: each AssemblerPower register " - "starts with 'r'.\nline: " + - line, - file); - - throw std::runtime_error("not_a_register"); - } - } - - if (found_some_count < 1 && name[0] != 'l' && name[0] != 's') { - Detail::print_error("invalid combination of opcode and registers.\nline: " + line, - file); - throw std::runtime_error("invalid_comb_op_reg"); - } - - break; - } - } - - kOrigin += cPowerIPAlignment; - break; - } - } - - return true; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Frontend.cc b/dev/CompilerKit/src/Frontend.cc deleted file mode 100644 index baac34e..0000000 --- a/dev/CompilerKit/src/Frontend.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#include - -/** - * @file Frontend.cc - * @author Amlal El Mahrouss (amlal@nekernel.org) - * @brief Frontend API of NeCTI - * @version 0.0.2 - * - * @copyright Copyright (c) 2025 Amlal El Mahrouss and NeKernel.org Contributors - * - */ - -namespace CompilerKit { -/// find the perfect matching word in a haystack. -/// \param haystack base string -/// \param needle the string we search for. -/// \return if we found it or not. -Bool find_word(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::npos) return false; - - // declare lambda - auto not_part_of_word = [&](int index) { - if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) return true; - - if (index <= 0 || index >= haystack.size()) return true; - - return false; - }; - - return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); -} - -/// find a word within strict conditions and returns a range of it. -/// \param haystack -/// \param needle -/// \return position of needle. -SizeType find_word_range(STLString haystack, STLString needle) noexcept { - auto index = haystack.find(needle); - - // check for needle validity. - if (index == STLString::npos) return false; - - if (!isalnum((haystack[index + needle.size() + 1])) && - !isdigit(haystack[index + needle.size() + 1]) && - !isalnum((haystack[index - needle.size() - 1])) && - !isdigit(haystack[index - needle.size() - 1])) { - return index; - } - - return STLString::npos; -} -} // namespace CompilerKit \ No newline at end of file diff --git a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc b/dev/CompilerKit/src/Frontend/CCompiler64x0.cc deleted file mode 100644 index f07fcb0..0000000 --- a/dev/CompilerKit/src/Frontend/CCompiler64x0.cc +++ /dev/null @@ -1,1287 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 -/// TODO: none - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* C driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file 64x0-cc.cc -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kExitOK (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief Register map structure, used to keep track of each variable's registers. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontend64x0 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontend64x0() = default; - ~CompilerFrontend64x0() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontend64x0); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "64k C"; } -}; - -static CompilerFrontend64x0* kCompilerFrontend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontend64x0::Compile(std::string text_, - std::string file) { - std::string text = text_; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value in struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "public_segment .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return syntaxLeaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontend64x0::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector 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 variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - NECTI_COPY_DEFAULT(AssemblyCCInterface); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArch64x0; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), - range.size(), needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NECTI_MODULE(CompilerCLang64x0) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerFrontend = new CompilerFrontend64x0(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "--v") == 0 || strcmp(argv[index], "--version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "--verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "--dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "--fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc b/dev/CompilerKit/src/Frontend/CCompilerARM64.cc deleted file mode 100644 index c5b1fb8..0000000 --- a/dev/CompilerKit/src/Frontend/CCompilerARM64.cc +++ /dev/null @@ -1,1286 +0,0 @@ -/* - * ======================================================== - * - * CCompilerARM64 - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 -/// TODO: none - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* C driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file ARM64-cc.cc -/// @brief ARM64 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kExitOK (0) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief Register map structure, used to keep track of each variable's registers. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontendARM64 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontendARM64() = default; - ~CompilerFrontendARM64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendARM64); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "64k C"; } -}; - -static CompilerFrontendARM64* kCompilerFrontend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendARM64::Compile(std::string text, - std::string file) { - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, extern_segment "; - syntaxLeaf.fUserValue += kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword public_segment .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value in struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (text[text_index] == '=') break; - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "public_segment .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "sub "; - syntaxLeaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return syntaxLeaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontendARM64::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector 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 variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCCInterface final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCCInterface() = default; - ~AssemblyCCInterface() override = default; - - NECTI_COPY_DEFAULT(AssemblyCCInterface); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAARCH64; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: ARM64 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector keywords = {"ldw", "stw", "lda", "sta", "add", "sub", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment " + needle) != std::string::npos) { - std::string range = "extern_segment " + needle; - leaf.fUserValue.replace(leaf.fUserValue.find("extern_segment " + needle), - range.size(), needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && keyword != "sub") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mv"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "NE C Driver, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kCExtension ".c" - -NECTI_MODULE(CompilerCLangARM64) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyCCInterface()); - kMachine = CompilerKit::AssemblyFactory::kArchAARCH64; - kCompilerFrontend = new CompilerFrontendARM64(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "--v") == 0 || strcmp(argv[index], "--version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "--verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "--h") == 0 || strcmp(argv[index], "--help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "--dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "--fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kCExtension) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc b/dev/CompilerKit/src/Frontend/CCompilerPower64.cc deleted file mode 100644 index ccc5cf8..0000000 --- a/dev/CompilerKit/src/Frontend/CCompilerPower64.cc +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * ======================================================== - * - * CompilerPower64 - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define kExitOK 0 - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file cc.cc -/// @brief POWER64 C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCTURES OF THE C COMPILER - -///////////////////////////////////// - -namespace Detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlal@nekernel.org -struct CompilerStructMap final { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector> fOffsets; -}; - -struct CompilerState final { - std::vector fSyntaxTreeList; - std::vector kStackFrame; - std::vector kStructMap; - CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace Detail - -static Detail::CompilerState kState; -static std::string kIfFunction = ""; - -namespace Detail { -/// @brief prints an error into stdout. -/// @param reason the reason of the error. -/// @param file where does it originate from? -void print_error(std::string reason, std::string file) noexcept; - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerFrontendPower64 final : public CompilerKit::CompilerFrontendInterface { - public: - explicit CompilerFrontendPower64() = default; - ~CompilerFrontendPower64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendPower64); - - std::string Check(const char* text, const char* file); - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) override; - - const char* Language() override { return "POWER C"; } -}; - -static CompilerFrontendPower64* kCompilerFrontend = nullptr; -static std::vector kCompilerVariables; -static std::vector kCompilerFunctions; -static std::vector kCompilerTypes; - -namespace Detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace Detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendPower64::Compile(std::string text_, - std::string file) { - std::string text = text_; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < text.size(); ++text_index) { - auto syntax_leaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - Detail::number_cast time_off = (UInt64) out.as_bytes().data(); - - if (!typeFound) { - auto substr = text.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto& clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (text.find('(') != std::string::npos) { - syntax_leaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (text[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - // return keyword handler - if (text[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < text.size(); ++return_index) { - if (text[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; value_index < text.size(); ++value_index) { - if (text[value_index] == ';') break; - - value += text[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " extern_segment"; - value += tmp; - } - - syntax_leaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) value.erase(value.find(' '), 1); - - while (value.find("extern_segment") != std::string::npos) - value.erase(value.find("extern_segment"), strlen("extern_segment")); - - bool found = false; - - for (auto& reg : kState.kStackFrame) { - if (value.find(reg.fName) != std::string::npos) { - found = true; - syntax_leaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) syntax_leaf.fUserValue += "r0"; - } - - syntax_leaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - break; - } - } - - if (text[text_index] == 'i' && text[text_index + 1] == 'f') { - auto expr = text.substr(text_index + 2); - text.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__NECTI_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntax_leaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntax_leaf.fUserValue += "\n\tbeq extern_segment " + kIfFunction + - " \ndword public_segment .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (text[text_index] == '=' || text[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (text[text_index] == ';' && kInStruct) continue; - - if (text.find("typedef ") != std::string::npos) continue; - - if (text[text_index] == '=' && kInStruct) { - Detail::print_error("assignement of value inside a struct " + text, file); - continue; - } - - if (text[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto& ch : text) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair(kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (text[text_index] == '=' && kInStruct) { - continue; - } - - if (text[text_index + 1] == '=' || text[text_index - 1] == '!' || - text[text_index - 1] == '<' || text[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (text.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (text.find("*") != std::string::npos) { - if (text.find("=") > text.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } else { - substr += "\tli "; - } - } else if (text.find('=') != std::string::npos && !kInBraces) { - substr += "stw public_segment .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < text.size(); ++text_index_2) { - if (text[text_index_2] == '\"') break; - - substr += text[text_index_2]; - } - } - - if (text[text_index_2] == '{' || text[text_index_2] == '}') continue; - - if (text[text_index_2] == ';') { - break; - } - - if (text[text_index_2] == ' ' || text[text_index_2] == '\t') { - if (first_encountered != 2) { - if (text[text_index] != '=' && - substr.find("public_segment .data64") == std::string::npos && !kInStruct) - substr += "public_segment .data64 "; - } - - ++first_encountered; - - continue; - } - - if (text[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("public_segment .data64"), strlen("public_segment .data64"), - "public_segment .zero64 "); - } - - substr += ","; - continue; - } - - substr += text[text_index_2]; - } - - for (auto& clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "extern_segment "); - - if (substr.find("public_segment .data64") != std::string::npos) - substr.erase(substr.find("public_segment .data64"), strlen("public_segment .data64")); - } - - auto var_to_find = std::find_if( - kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](Detail::CompilerType type) { return type.fName.find(substr) != std::string::npos; }); - - kCompilerVariables.push_back({.fName = substr}); - - if (text[text_index] == ';') break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) { - if (newSubstr[start] == ',') break; - - if (newSubstr[start] == ' ') continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntax_leaf.fUserValue += "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - // function handler. - - if (text[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = text.find('(') + 1; idx < text.size(); ++idx) { - if (text[idx] == ',') continue; - - if (text[idx] == ' ') continue; - - if (text[idx] == ')') break; - } - - for (char substr_first_index : text) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : text) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntax_leaf.fUserValue = args; - syntax_leaf.fUserValue += substr; - - syntax_leaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - fnFound = true; - } else { - syntax_leaf.fUserValue.clear(); - - syntax_leaf.fUserValue += "public_segment .code64 "; - - syntax_leaf.fUserValue += substr; - syntax_leaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(text); - } - - if (text[text_index] == '-' && text[text_index + 1] == '-') { - text = text.replace(text.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < text.size(); ++_text_i) { - if (text[_text_i] == '\t' || text[_text_i] == ' ') text.erase(_text_i, 1); - } - - syntax_leaf.fUserValue += "dec "; - syntax_leaf.fUserValue += text; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - break; - } - - if (text[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - } - - syntax_leaf.fUserValue.clear(); - } - - auto syntax_leaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); - syntax_leaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntax_leaf); - - return syntax_leaf; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerFrontendPower64::Check(const char* text, const char* file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && ln.find('\'') == std::string::npos) { - std::vector 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 variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto& variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); ln[index_keyword] != variable.fBegin[0]; - ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) keyword.erase(keyword.find(' '), 1); - - for (auto& var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto& fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it extern_segments a variable. - // so that's why it's not declare upper. - if (CompilerKit::find_word(ln, "extern")) { - auto substr = ln.substr(ln.find("extern") + strlen("extern")); - kCompilerVariables.push_back({.fValue = substr}); - } - - if (kShouldHaveBraces && ln.find('{') == std::string::npos) { - err_str += "Missing '{' for function "; - err_str += kFnName; - err_str += "\n"; - - kShouldHaveBraces = false; - kFnName.clear(); - } else if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - kFnName.clear(); - } - - bool type_not_found = true; - - if (ln.find('\'') != std::string::npos) { - ln.replace(ln.find('\''), 3, "0"); - } - - auto first = ln.find('"'); - if (first != std::string::npos) { - auto second = 0UL; - bool found_second_quote = false; - - for (size_t i = first + 1; i < ln.size(); ++i) { - if (ln[i] == '\"') { - found_second_quote = true; - second = i; - - break; - } - } - - if (!found_second_quote) { - err_str += "Missing terminating \"."; - err_str += " here -> " + ln.substr(ln.find('"'), second); - } - } - - if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) { - if (ln.find('{') == std::string::npos) { - kFnName = ln; - kShouldHaveBraces = true; - - goto skip_braces_check; - } else if (ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - } - -skip_braces_check: - - for (auto& key : kCompilerTypes) { - if (CompilerKit::find_word(ln, key.fName)) { - if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) { - err_str += "\nNumber cannot be set for "; - err_str += key.fName; - err_str += "'s name. here -> "; - err_str += ln; - } - - if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || - ln[ln.find(key.fName) - 1] == '\t') { - type_not_found = false; - - if (ln[ln.find(key.fName) + key.fName.size()] != ' ') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == '\t') type_not_found = false; - - goto next; - } else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') { - type_not_found = true; - - if (ln[ln.find(key.fName) + key.fName.size()] == ' ') type_not_found = false; - } - } - - next: - - if (ln.find(';') == std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find('=') == std::string::npos) continue; - } - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } else { - continue; - } - - if (ln.find('=') != std::string::npos) { - if (ln.find('(') != std::string::npos) { - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } - } - } - } - - if (kInBraces && ln.find("struct") != std::string::npos && - ln.find("union") != std::string::npos && ln.find("enum") != std::string::npos && - ln.find('=') != std::string::npos) { - if (ln.find(';') == std::string::npos) { - err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; - err_str += ln; - } - } - - if (ln.find(';') != std::string::npos && ln.find("for") == std::string::npos) { - if (ln.find(';') + 1 != ln.size()) { - for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) { - if ((ln.substr(ln.find(';') + 1)[i] != ' ') || (ln.substr(ln.find(';') + 1)[i] != '\t')) { - if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); !err.empty()) { - err_str += "\nUnexpected text after ';' -> "; - err_str += ln.substr(ln.find(';')); - err_str += err; - } - } - } - } - } - - if (ln.find('(') != std::string::npos) { - if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && - !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && - !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector opens; - std::vector closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - NECTI_COPY_DEFAULT(AssemblyMountpointCLang); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchPowerPC; } - - Int32 CompileToFormat(std::string src, Int32 arch) override { - if (kCompilerFrontend == nullptr) return 1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - CompilerKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerFrontend->Check(line_src.c_str(), src.data()); err.empty()) { - kCompilerFrontend->Compile(line_src, src.data()); - } else { - Detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return 1; - - std::vector keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - std::vector access_keywords = {"->", "."}; - - for (auto& access_ident : access_keywords) { - if (CompilerKit::find_word(leaf.fUserValue, access_ident)) { - for (auto& struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto& keyword : keywords) { - if (CompilerKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto& reg : kState.kStackFrame) { - std::string needle; - - for (size_t i = 0; i < reg.fName.size(); i++) { - if (reg.fName[i] == ' ') { - ++i; - - for (; i < reg.fName.size(); i++) { - if (reg.fName[i] == ',') { - break; - } - - if (reg.fName[i] == ' ') continue; - - needle += reg.fName[i]; - } - - break; - } - } - - if (CompilerKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("extern_segment ") != std::string::npos) { - std::string range = "extern_segment "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = - std::count(leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), keyword.size(), "mr"); - } - } - } - } - - for (auto& leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include - -#define kPrintF printf -#define kSplashCxx() kPrintF(kWhite "cc, %s, (c) Amlal El Mahrouss\n", kDistVersion) - -static void cc_print_help() { - kSplashCxx(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -NECTI_MODULE(CompilerCLangPowerPC) { - ::signal(SIGSEGV, Detail::drvi_crash_handler); - - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerFrontend = new CompilerFrontendPower64(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kExitOK; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kExitOK; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerFrontend) std::cout << kCompilerFrontend->Language() << "\n"; - - return kExitOK; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - Detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - Detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kExitOK) return 1; - } - - return kExitOK; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc b/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc deleted file mode 100644 index d715a3a..0000000 --- a/dev/CompilerKit/src/Frontend/CPlusPlusCompilerAMD64.cc +++ /dev/null @@ -1,906 +0,0 @@ -/* - * ======================================================== - * - * C++ Compiler Driver - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 - -/////////////////////// - -// ANSI ESCAPE CODES // - -/////////////////////// - -/////////////////////// - -// MACROS // - -/////////////////////// - -#define kPrintF printf -#define kPrintErr std::cerr - -#define kExitOK (EXIT_SUCCESS) -#define kExitNO (EXIT_FAILURE) - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -#include -#include -#include -#include -#include -#include -#include - -/* NeKernel C++ Compiler Driver */ -/* This is part of the CompilerKit. */ -/* (c) Amlal El Mahrouss 2024-2025 */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file CPlusPlusCompilerAMD64.cxx -/// @brief Optimized C++ Compiler Driver. - -///////////////////////////////////// - -// INTERNALS OF THE C++ COMPILER - -///////////////////////////////////// - -/// @internal -// Avoids relative_path which could discard parts of the original. -std::filesystem::path necti_expand_home(const std::filesystem::path& input) { - const std::string& raw = input.string(); - - if (!raw.empty() && raw[0] == '~') { - const char* home = std::getenv("HOME"); - if (!home) home = std::getenv("USERPROFILE"); - - if (!home) throw std::runtime_error("Home directory not found in environment variables"); - - return std::filesystem::path(home) / raw.substr(1); - } - - return input; -} - -struct CompilerRegisterMap final { - CompilerKit::STLString fName{}; - CompilerKit::STLString fReg{}; -}; - -/// \brief Offset based struct/class -struct CompilerStructMap final { - CompilerKit::STLString fName{}; - CompilerKit::STLString fReg{}; - std::vector> fOffsets; -}; - -/// \brief Compiler state structure. -struct CompilerState final { - std::vector fStackMapVector; - std::vector fStructMapVector; - CompilerKit::STLString fLastFile{}; - CompilerKit::STLString fLastError{}; -}; - -static CompilerState kState; - -static Int32 kOnClassScope = 0; - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static Int32 kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static std::vector kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static CompilerKit::AssemblyFactory kAssembler; -static Boolean kInStruct = false; -static Boolean kOnWhileLoop = false; -static Boolean kOnForLoop = false; -static Boolean kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for the NeKernel C++ driver */ -class CompilerFrontendCPlusPlusAMD64 final CK_COMPILER_FRONTEND { - public: - explicit CompilerFrontendCPlusPlusAMD64() = default; - ~CompilerFrontendCPlusPlusAMD64() override = default; - - NECTI_COPY_DEFAULT(CompilerFrontendCPlusPlusAMD64); - - CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(const CompilerKit::STLString text, - CompilerKit::STLString file) override; - - const char* Language() override; -}; - -/// @internal compiler variables - -static CompilerFrontendCPlusPlusAMD64* kFrontend = nullptr; - -static std::vector kRegisterMap; - -static std::vector kRegisterList = { - "rbx", "rsi", "r10", "r11", "r12", "r13", "r14", "r15", "xmm12", "xmm13", "xmm14", "xmm15", -}; - -/// @brief The PEF calling convention (caller must save rax, rbp) -/// @note callee must return via **rax**. -static std::vector kRegisterConventionCallList = { - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", -}; - -static std::size_t kFunctionEmbedLevel = 0UL; - -/// detail namespaces - -const char* CompilerFrontendCPlusPlusAMD64::Language() { - return "AMD64 C++"; -} - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector> kOriginMap; - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @name Compile -/// @brief Generate assembly from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendCPlusPlusAMD64::Compile( - CompilerKit::STLString text, CompilerKit::STLString file) { - CompilerKit::SyntaxLeafList::SyntaxLeaf syntax_tree; - - if (text.empty()) return syntax_tree; - - std::size_t index = 0UL; - std::vector> keywords_list; - - for (auto& keyword : kKeywords) { - if (text.find(keyword.keyword_name) != std::string::npos) { - switch (keyword.keyword_kind) { - case CompilerKit::kKeywordKindCommentInline: { - break; - } - default: - break; - } - - std::size_t pos = text.find(keyword.keyword_name); - if (pos == std::string::npos) continue; - - // can't go before start of string - if (pos > 0 && text[pos - 1] == '+' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - if (pos > 0 && text[pos - 1] == '-' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - // don't go out of range - if ((pos + keyword.keyword_name.size()) < text.size() && - text[pos + keyword.keyword_name.size()] == '=' && - keyword.keyword_kind == CompilerKit::kKeywordKindVariableAssign) - continue; - - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - } - } - - for (auto& keyword : keywords_list) { - if (text.find(keyword.first.keyword_name) == CompilerKit::STLString::npos) continue; - - switch (keyword.first.keyword_kind) { - case CompilerKit::KeywordKind::kKeywordKindClass: { - ++kOnClassScope; - break; - } - case CompilerKit::KeywordKind::kKeywordKindIf: { - std::size_t keywordPos = text.find(keyword.first.keyword_name); - std::size_t openParen = text.find("(", keywordPos); - std::size_t closeParen = text.find(")", openParen); - - if (keywordPos == CompilerKit::STLString::npos || - openParen == CompilerKit::STLString::npos || - closeParen == CompilerKit::STLString::npos || closeParen <= openParen) { - Detail::print_error("Malformed if expression: " + text, file); - break; - } - - auto expr = text.substr(openParen + 1, closeParen - openParen - 1); - - if (expr.find(">=") != CompilerKit::STLString::npos) { - auto left = text.substr( - text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, - expr.find("<=") + strlen("<=")); - auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); - - // Trim whitespace - while (!right.empty() && (right.back() == ' ' || right.back() == '\t')) { - right.pop_back(); - } - while (!right.empty() && (right.front() == ' ' || right.front() == '\t')) { - right.erase(0, 1); - } - - while (!left.empty() && (left.back() == ' ' || left.back() == '\t')) { - left.pop_back(); - } - while (!left.empty() && (left.front() == ' ' || left.front() == '\t')) { - left.erase(0, 1); - } - - if ((!left.empty() && !isdigit(left[0])) || (!right.empty() && !isdigit(right[0]))) { - auto indexRight = 0UL; - - auto& valueOfVar = (!left.empty() && !isdigit(left[0])) ? left : right; - - if (!valueOfVar.empty()) { - for (auto pairRight : kRegisterMap) { - ++indexRight; - - CompilerKit::STLString instr = "mov "; - - if (pairRight != valueOfVar) { - auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; - - syntax_tree.fUserValue += - instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + "," + - kRegisterList[indexRight + 1] + "\n"; - - goto lc_done_iterarting_on_if; - } - - auto& valueOfVarOpposite = (!left.empty() && isdigit(left[0])) ? left : right; - - syntax_tree.fUserValue += - instr + kRegisterList[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; - syntax_tree.fUserValue += "cmp " + kRegisterList[kRegisterMap.size() - 1] + ", " + - kRegisterList[indexRight + 1] + "\n"; - - break; - } - } - } - - lc_done_iterarting_on_if: - - CompilerKit::STLString symbol_name_fn = text; - - symbol_name_fn.erase(symbol_name_fn.find(keyword.first.keyword_name)); - - for (auto& ch : symbol_name_fn) { - if (ch == ' ') ch = '_'; - } - - syntax_tree.fUserValue += - "jge __OFFSET_ON_TRUE_LC\nsegment .code64 __OFFSET_ON_TRUE_LC:\n"; - } - - break; - } - case CompilerKit::KeywordKind::kKeywordKindFunctionStart: { - for (auto& ch : text) { - if (isdigit(ch)) { - goto dont_accept; - } - } - - goto accept; - - dont_accept: - break; - - accept: - CompilerKit::STLString symbol_name_fn = text; - size_t indexFnName = 0; - - // this one is for the type. - for (auto& ch : text) { - ++indexFnName; - - if (ch == '\t') break; - if (ch == ' ') break; - } - - symbol_name_fn = text.substr(indexFnName); - - if (text.find("return ") != CompilerKit::STLString::npos) { - text.erase(0, text.find("return ")); - break; - } - - if (text.ends_with(";") && text.find("return") == CompilerKit::STLString::npos) - goto lc_write_assembly; - else if (text.size() <= indexFnName) - Detail::print_error("Invalid function name: " + symbol_name_fn, file); - - indexFnName = 0; - - for (auto& ch : symbol_name_fn) { - if (ch == ' ' || ch == '\t') { - if (symbol_name_fn[indexFnName - 1] != ')') - Detail::print_error("Invalid function name: " + symbol_name_fn, file); - } - - ++indexFnName; - } - - if (symbol_name_fn.find("(") != CompilerKit::STLString::npos) { - symbol_name_fn.erase(symbol_name_fn.find("(")); - } - - syntax_tree.fUserValue = "public_segment .code64 __NECTI_" + symbol_name_fn + "\n"; - ++kFunctionEmbedLevel; - - kOriginMap.push_back({"__NECTI_" + symbol_name_fn, kOrigin}); - - break; - - lc_write_assembly: - auto it = std::find_if( - kOriginMap.begin(), kOriginMap.end(), - [&symbol_name_fn](std::pair pair) -> bool { - return symbol_name_fn == pair.first; - }); - - if (it != kOriginMap.end()) { - std::stringstream ss; - ss << std::hex << it->second; - - syntax_tree.fUserValue = "jmp " + ss.str() + "\n"; - kOrigin += 1UL; - } - } - case CompilerKit::KeywordKind::kKeywordKindFunctionEnd: { - if (kOnClassScope) --kOnClassScope; - - if (text.ends_with(";")) break; - - --kFunctionEmbedLevel; - - if (kRegisterMap.size() > kRegisterList.size()) { - --kFunctionEmbedLevel; - } - - if (kFunctionEmbedLevel < 1) kRegisterMap.clear(); - - break; - } - case CompilerKit::KeywordKind::kKeywordKindEndInstr: - case CompilerKit::KeywordKind::kKeywordKindVariableInc: - case CompilerKit::KeywordKind::kKeywordKindVariableDec: - case CompilerKit::KeywordKind::kKeywordKindVariableAssign: { - CompilerKit::STLString valueOfVar = ""; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - valueOfVar = text.substr(text.find("+=") + 2); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - valueOfVar = text.substr(text.find("-=") + 2); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableAssign) { - valueOfVar = text.substr(text.find("=") + 1); - } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - break; - } - - while (valueOfVar.find(";") != CompilerKit::STLString::npos && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindEndInstr) { - valueOfVar.erase(valueOfVar.find(";")); - } - - CompilerKit::STLString varName = text; - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - varName.erase(varName.find("+=")); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - varName.erase(varName.find("-=")); - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableAssign) { - varName.erase(varName.find("=")); - } else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - varName.erase(varName.find(";")); - } - - static Boolean typeFound = false; - - for (auto& keyword : kKeywords) { - if (keyword.keyword_kind == CompilerKit::kKeywordKindType) { - if (text.find(keyword.keyword_name) != CompilerKit::STLString::npos) { - if (text[text.find(keyword.keyword_name)] == ' ') { - typeFound = false; - continue; - } - - typeFound = true; - } - } - } - - CompilerKit::STLString instr = "mov "; - - std::vector newVars; - - if (typeFound && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableInc && - keyword.first.keyword_kind != CompilerKit::KeywordKind::kKeywordKindVariableDec) { - if (kRegisterMap.size() > kRegisterList.size()) { - ++kFunctionEmbedLevel; - } - - while (varName.find(" ") != CompilerKit::STLString::npos) { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != CompilerKit::STLString::npos) { - varName.erase(varName.find("\t"), 1); - } - - // Remove whitespace only (keep operators and quotes) - while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { - valueOfVar.erase(0, 1); - } - - constexpr auto kTrueVal = "true"; - constexpr auto kFalseVal = "false"; - - if (valueOfVar == kTrueVal) { - valueOfVar = "1"; - } else if (valueOfVar == kFalseVal) { - valueOfVar = "0"; - } - - std::size_t indexRight = 0UL; - - for (auto pairRight : kRegisterMap) { - ++indexRight; - - if (pairRight != valueOfVar) { - if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + - valueOfVar + ", 0\n\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size() - 1] + ", " + - "__NECTI_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } else { - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - } - - goto done; - } - } - - if (((int) indexRight - 1) < 0) { - if (valueOfVar[0] == '\"') { - syntax_tree.fUserValue = - "segment .data64 __NECTI_LOCAL_VAR_" + varName + ": db " + valueOfVar + ", 0\n"; - syntax_tree.fUserValue += instr + kRegisterList[kRegisterMap.size()] + ", " + - "__NECTI_LOCAL_VAR_" + varName + "\n"; - kOrigin += 1UL; - } else { - auto mangled = valueOfVar; - - if (mangled.find("(") != std::string::npos) { - auto ret = mangled.erase(mangled.find("(")); - mangled = "__NECTI_"; - mangled += ret; - - syntax_tree.fUserValue = "jmp " + mangled + "\n"; - syntax_tree.fUserValue += - instr + " rax, " + kRegisterList[kRegisterMap.size()] + "\n"; - - goto done; - } - - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size()] + ", " + mangled + "\n"; - kOrigin += 1UL; - } - - goto done; - } - - if (!valueOfVar.empty() && valueOfVar[0] != '\"' && valueOfVar[0] != '\'' && - !isdigit(valueOfVar[0])) { - for (auto pair : kRegisterMap) { - if (pair == valueOfVar) goto done; - } - - Detail::print_error("Variable not declared: " + varName, file); - break; - } - - done: - for (auto& keyword : kKeywords) { - if (keyword.keyword_kind == CompilerKit::kKeywordKindType && - varName.find(keyword.keyword_name) != CompilerKit::STLString::npos) { - varName.erase(varName.find(keyword.keyword_name), keyword.keyword_name.size()); - break; - } - } - - newVars.push_back(varName); - - break; - } - - kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); - - if (keyword.second > 0 && - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindType || - kKeywords[keyword.second - 1].keyword_kind == CompilerKit::kKeywordKindTypePtr) { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindEndInstr) { - syntax_tree.fUserValue = "\n"; - continue; - } - - if (keyword.first.keyword_kind == CompilerKit::KeywordKind::kKeywordKindVariableInc) { - instr = "add "; - } else if (keyword.first.keyword_kind == - CompilerKit::KeywordKind::kKeywordKindVariableDec) { - instr = "sub "; - } - - CompilerKit::STLString varErrCpy = varName; - - while (varName.find(" ") != CompilerKit::STLString::npos) { - varName.erase(varName.find(" "), 1); - } - - while (varName.find("\t") != CompilerKit::STLString::npos) { - varName.erase(varName.find("\t"), 1); - } - - std::size_t indxReg = 0UL; - - while (!valueOfVar.empty() && (valueOfVar[0] == ' ' || valueOfVar[0] == '\t')) { - valueOfVar.erase(0, 1); - } - - while (valueOfVar.find(" ") != CompilerKit::STLString::npos) { - valueOfVar.erase(valueOfVar.find(" "), 1); - } - - while (valueOfVar.find("\t") != CompilerKit::STLString::npos) { - valueOfVar.erase(valueOfVar.find("\t"), 1); - } - - constexpr auto kTrueVal = "true"; - constexpr auto kFalseVal = "false"; - - /// interpet boolean values, since we're on C++ - - if (valueOfVar == kTrueVal) { - valueOfVar = "1"; - } else if (valueOfVar == kFalseVal) { - valueOfVar = "0"; - } - - for (auto pair : kRegisterMap) { - ++indxReg; - - if (pair != varName) continue; - - std::size_t indexRight = 0ul; - - for (auto pairRight : kRegisterMap) { - ++indexRight; - - if (pairRight != varName) { - syntax_tree.fUserValue = - instr + kRegisterList[kRegisterMap.size()] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - continue; - } - - syntax_tree.fUserValue = - instr + kRegisterList[indexRight - 1] + ", " + valueOfVar + "\n"; - kOrigin += 1UL; - break; - } - - newVars.push_back(varName); - break; - } - - if (syntax_tree.fUserValue.empty()) { - Detail::print_error("Variable not declared: " + varName, file); - } - - kRegisterMap.insert(kRegisterMap.end(), newVars.begin(), newVars.end()); - - break; - } - case CompilerKit::KeywordKind::kKeywordKindReturn: { - try { - auto pos = text.find("return") + strlen("return") + 1; - CompilerKit::STLString subText = text.substr(pos); - if (subText.find(";") == CompilerKit::STLString::npos) break; - - subText = subText.erase(subText.find(";")); - size_t indxReg = 0UL; - - if (!subText.empty() && subText[0] != '\"' && subText[0] != '\'') { - if (!isdigit(subText[0])) { - for (auto pair : kRegisterMap) { - ++indxReg; - - syntax_tree.fUserValue = "mov rax, " + kRegisterList[indxReg - 1] + "\nret\n"; - kOrigin += 1UL; - - break; - } - } else { - syntax_tree.fUserValue = "mov rax, " + subText + "\nret\n"; - kOrigin += 1UL; - - break; - } - } else { - syntax_tree.fUserValue = "__NECTI_LOCAL_RETURN_STRING: db " + subText + - ", 0\nmov rcx, __NECTI_LOCAL_RETURN_STRING\n"; - syntax_tree.fUserValue += "mov rax, rcx\nret\n"; - kOrigin += 1UL; - - break; - } - - if (syntax_tree.fUserValue.empty()) { - if (subText.find("(") != CompilerKit::STLString::npos) { - subText.erase(subText.find("(")); - - auto it = std::find_if( - kOriginMap.begin(), kOriginMap.end(), - [&subText](std::pair pair) -> bool { - return pair.first.find(subText) != CompilerKit::STLString::npos; - }); - - if (it == kOriginMap.end()) - Detail::print_error("Invalid return value: " + subText, file); - - std::stringstream ss; - ss << it->second; - - syntax_tree.fUserValue = "jmp " + ss.str() + "\nret\n"; - kOrigin += 1UL; - break; - } - } - - syntax_tree.fUserValue = "ret\n"; - kOrigin += 1UL; - - break; - } catch (...) { - syntax_tree.fUserValue = "ret\n"; - kOrigin += 1UL; - - break; - } - } - default: { - continue; - } - } - } - - return syntax_tree; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C++ assembler class. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyCPlusPlusInterfaceAMD64 final CK_ASSEMBLY_INTERFACE { - public: - explicit AssemblyCPlusPlusInterfaceAMD64() = default; - ~AssemblyCPlusPlusInterfaceAMD64() override = default; - - NECTI_COPY_DEFAULT(AssemblyCPlusPlusInterfaceAMD64); - - UInt32 Arch() noexcept override { return CompilerKit::AssemblyFactory::kArchAMD64; } - - Int32 CompileToFormat(CompilerKit::STLString src, Int32 arch) override { - if (kFrontend == nullptr) return kExitNO; - - CompilerKit::STLString dest = src; - dest += ".pp.masm"; - - std::ofstream out_fp(dest); - std::ifstream src_fp = std::ifstream(src + ".pp"); - - CompilerKit::STLString line_source; - - out_fp << "%bits 64\n"; - out_fp << "%org " << kOrigin << "\n\n"; - - while (std::getline(src_fp, line_source)) { - out_fp << kFrontend->Compile(line_source, src).fUserValue; - } - - return kExitOK; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { ".cpp", ".cxx", ".cc", ".c++", ".cp" } - -NECTI_MODULE(CompilerCPlusPlusAMD64) { - Boolean skip = false; - - kKeywords.emplace_back("if", CompilerKit::kKeywordKindIf); - kKeywords.emplace_back("else", CompilerKit::kKeywordKindElse); - kKeywords.emplace_back("else if", CompilerKit::kKeywordKindElseIf); - - kKeywords.emplace_back("class", CompilerKit::kKeywordKindClass); - kKeywords.emplace_back("struct", CompilerKit::kKeywordKindClass); - kKeywords.emplace_back("namespace", CompilerKit::kKeywordKindNamespace); - kKeywords.emplace_back("typedef", CompilerKit::kKeywordKindTypedef); - kKeywords.emplace_back("using", CompilerKit::kKeywordKindTypedef); - kKeywords.emplace_back("{", CompilerKit::kKeywordKindBodyStart); - kKeywords.emplace_back("}", CompilerKit::kKeywordKindBodyEnd); - kKeywords.emplace_back("auto", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("int", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("bool", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("unsigned", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("short", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("char", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("long", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("float", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("double", CompilerKit::kKeywordKindType); - kKeywords.emplace_back("void", CompilerKit::kKeywordKindType); - - kKeywords.emplace_back("auto*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("int*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("bool*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("unsigned*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("short*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("char*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("long*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("float*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("double*", CompilerKit::kKeywordKindTypePtr); - kKeywords.emplace_back("void*", CompilerKit::kKeywordKindTypePtr); - - kKeywords.emplace_back("(", CompilerKit::kKeywordKindFunctionStart); - kKeywords.emplace_back(")", CompilerKit::kKeywordKindFunctionEnd); - kKeywords.emplace_back("=", CompilerKit::kKeywordKindVariableAssign); - kKeywords.emplace_back("+=", CompilerKit::kKeywordKindVariableInc); - kKeywords.emplace_back("-=", CompilerKit::kKeywordKindVariableDec); - kKeywords.emplace_back("const", CompilerKit::kKeywordKindConstant); - kKeywords.emplace_back("*", CompilerKit::kKeywordKindPtr); - kKeywords.emplace_back("->", CompilerKit::kKeywordKindPtrAccess); - kKeywords.emplace_back(".", CompilerKit::kKeywordKindAccess); - kKeywords.emplace_back(",", CompilerKit::kKeywordKindArgSeparator); - kKeywords.emplace_back(";", CompilerKit::kKeywordKindEndInstr); - kKeywords.emplace_back(":", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("public:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("private:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("protected:", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("final", CompilerKit::kKeywordKindSpecifier); - kKeywords.emplace_back("return", CompilerKit::kKeywordKindReturn); - kKeywords.emplace_back("/*", CompilerKit::kKeywordKindCommentMultiLineStart); - kKeywords.emplace_back("*/", CompilerKit::kKeywordKindCommentMultiLineEnd); - kKeywords.emplace_back("//", CompilerKit::kKeywordKindCommentInline); - kKeywords.emplace_back("==", CompilerKit::kKeywordKindEq); - kKeywords.emplace_back("!=", CompilerKit::kKeywordKindNotEq); - kKeywords.emplace_back(">=", CompilerKit::kKeywordKindGreaterEq); - kKeywords.emplace_back("<=", CompilerKit::kKeywordKindLessEq); - - kErrorLimit = 0; - - kFrontend = new CompilerFrontendCPlusPlusAMD64(); - kAssembler.Mount(new AssemblyCPlusPlusInterfaceAMD64()); - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - // Ensure cleanup on exit - std::atexit([]() { - delete kFrontend; - kFrontend = nullptr; - }); - - for (auto index = 1UL; index < argc; ++index) { - if (!argv[index]) break; - - if (argv[index][0] == '-') { - if (skip) { - skip = false; - continue; - } - - if (strcmp(argv[index], "-cxx-verbose") == 0) { - kVerbose = true; - continue; - } - - if (strcmp(argv[index], "-cxx-dialect") == 0) { - if (kFrontend) std::cout << kFrontend->Language() << "\n"; - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cxx-max-err") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - CompilerKit::STLString err = "Unknown option: "; - err += argv[index]; - - Detail::print_error(err, "cxxdrv"); - - continue; - } - - CompilerKit::STLString argv_i = argv[index]; - - std::vector exts = kExtListCxx; - - for (CompilerKit::STLString ext : exts) { - if (argv_i.ends_with(ext)) { - if (kAssembler.Compile(argv_i, kMachine) != kExitOK) { - return NECTI_INVALID_DATA; - } - - break; - } - } - } - - kAssembler.Unmount(); - - return NECTI_SUCCESS; -} - -// -// Last rev 25-8-7 -// diff --git a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc b/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc deleted file mode 100644 index 8a503ed..0000000 --- a/dev/CompilerKit/src/Linker/DynamicLinker64PEF.cc +++ /dev/null @@ -1,678 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - - @file DynamicLinker64PEF.cc - @brief: C++ 64-Bit PEF Linker for NeKernel.org's NeKernel - -======================================== */ - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @brief NeKernel.org 64-bit PEF Linker. -/// Last Rev: Sat Apr 19 CET 2025 -/// @note Do not look up for anything with .code64/.data64/.zero64! -/// It will be loaded when the program loader will start the image. - -#include -#include -#include -#include -#include -#include -#include -#include - -#define kLinkerVersionStr "NeCTI 64-Bit Linker (Preferred Executable Format)" - -#define kPefNoCpu (0U) -#define kPefNoSubCpu (0U) - -#define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId (0x5046FF) -#define kLinkerAbiContainer "__PEFContainer:ABI:" - -#define kPrintF printf -#define kLinkerSplash() kConsoleOut << kLinkerVersionStr << std::endl - -/// @brief PEF stack size symbol. -#define kLinkerStackSizeSymbol "__PEFSizeOfReserveStack" - -#define kConsoleOut \ - (std::cout << "\e[0;31m" \ - << "ld64: " \ - << "\e[0;97m") - -enum { - kABITypeNull = 0, - kABITypeStart = 0x1010, /* The start of ABI list. */ - kABITypeNE = 0x5046, /* PF (NeKernel.org's PEF ABI) */ - kABITypeInvalid = 0xFFFF, -}; - -static CompilerKit::STLString kOutput = "a" kPefExt; -static Int32 kAbi = kABITypeNE; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArchInvalid; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; - -/* ld64 is to be found, mld is to be found at runtime. */ -static const Char* kLdDefineSymbol = ":UndefinedSymbol:"; -static const Char* kLdDynamicSym = ":RuntimeSymbol:"; - -static CompilerKit::STLString kLinkerStart = kPefStart; - -/* object code and list. */ -static std::vector kObjectList; -static std::vector kObjectBytes; - -/// @brief NE 64-bit Linker. -/// @note This linker is made for PEF executable, thus NE based OSes. -NECTI_MODULE(DynamicLinker64PEF) { - bool is_executable = true; - - CompilerKit::install_signal(SIGSEGV, Detail::drvi_crash_handler); - - /** - * @brief parse flags and trigger options. - */ - for (size_t linker_arg = 1; linker_arg < argc; ++linker_arg) { - if (std::strcmp(argv[linker_arg], "-help") == 0) { - kLinkerSplash(); - - kConsoleOut << "-version: Show linker version.\n"; - kConsoleOut << "-help: Show linker help.\n"; - kConsoleOut << "-verbose: Enable linker trace.\n"; - kConsoleOut << "-dylib: Output as a Dynamic PEF.\n"; - kConsoleOut << "-fat: Output as a FAT PEF.\n"; - kConsoleOut << "-32k: Output as a 32x0 PEF.\n"; - kConsoleOut << "-64k: Output as a 64x0 PEF.\n"; - kConsoleOut << "-amd64: Output as a AMD64 PEF.\n"; - kConsoleOut << "-rv64: Output as a RISC-V PEF.\n"; - kConsoleOut << "-power64: Output as a POWER PEF.\n"; - kConsoleOut << "-arm64: Output as a ARM64 PEF.\n"; - kConsoleOut << "-output: Select the output file name.\n"; - - return NECTI_SUCCESS; - } else if (std::strcmp(argv[linker_arg], "-version") == 0) { - kLinkerSplash(); - - return NECTI_SUCCESS; - } else if (std::strcmp(argv[linker_arg], "-fat") == 0) { - kFatBinaryEnable = true; - - continue; - } else if (std::strcmp(argv[linker_arg], "-64k") == 0) { - kArch = CompilerKit::kPefArch64000; - - continue; - } else if (std::strcmp(argv[linker_arg], "-amd64") == 0) { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } else if (std::strcmp(argv[linker_arg], "-start") == 0) { - if (argv[linker_arg + 1] == nullptr || argv[linker_arg + 1][0] == '-') continue; - - kLinkerStart = argv[linker_arg + 1]; - linker_arg += 1; - - continue; - } else if (std::strcmp(argv[linker_arg], "-32k") == 0) { - kArch = CompilerKit::kPefArch32000; - - continue; - } else if (std::strcmp(argv[linker_arg], "-power64") == 0) { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } else if (std::strcmp(argv[linker_arg], "-riscv64") == 0) { - kArch = CompilerKit::kPefArchRISCV; - - continue; - } else if (std::strcmp(argv[linker_arg], "-arm64") == 0) { - kArch = CompilerKit::kPefArchARM64; - - continue; - } else if (std::strcmp(argv[linker_arg], "-verbose") == 0) { - kVerbose = true; - - continue; - } else if (std::strcmp(argv[linker_arg], "-dylib") == 0) { - if (kOutput.empty()) { - continue; - } - - if (kOutput.find(kPefExt) != CompilerKit::STLString::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } else if (std::strcmp(argv[linker_arg], "-output") == 0) { - if ((linker_arg + 1) > argc) continue; - - kOutput = argv[linker_arg + 1]; - ++linker_arg; - - continue; - } else { - if (argv[linker_arg][0] == '-') { - kConsoleOut << "unknown flag: " << argv[linker_arg] << "\n"; - return EXIT_FAILURE; - } - - kObjectList.emplace_back(argv[linker_arg]); - - continue; - } - } - - if (kOutput.empty()) { - kConsoleOut << "no output filename set." << std::endl; - return NECTI_EXEC_ERROR; - } else if (kObjectList.empty()) { - kConsoleOut << "no input files." << std::endl; - return NECTI_EXEC_ERROR; - } else { - namespace FS = std::filesystem; - - // check for existing files, if they don't throw an error. - for (auto& obj : kObjectList) { - if (!FS::exists(obj)) { - // if filesystem doesn't find file - // -> throw error. - kConsoleOut << "no such file: " << obj << std::endl; - return NECTI_EXEC_ERROR; - } - } - } - - // PEF expects a valid target architecture when outputing a binary. - if (kArch == CompilerKit::kPefArchInvalid) { - kConsoleOut << "no target architecture set, can't continue." << std::endl; - return NECTI_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = is_executable ? CompilerKit::kPefKindExec : CompilerKit::kPefKindDylib; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Amlal El Mahrouss Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - pef_container.Checksum = 0UL; - - std::ofstream output_fc(kOutput, std::ofstream::binary); - - if (output_fc.bad()) { - if (kVerbose) { - kConsoleOut << "error: " << strerror(errno) << "\n"; - } - - return NECTI_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector command_headers; - CompilerKit::Utils::AEReadableProtocol reader_protocol{}; - - for (const auto& objectFile : kObjectList) { - if (!std::filesystem::exists(objectFile)) continue; - - CompilerKit::AEHeader hdr{}; - - reader_protocol.file_pointer_ = std::ifstream(objectFile, std::ifstream::binary); - reader_protocol.file_pointer_ >> hdr; - - if (hdr.fMagic[0] == kAEMag0 && hdr.fMagic[1] == kAEMag1 && - hdr.fSize == sizeof(CompilerKit::AEHeader)) { - if (hdr.fArch != kArch) { - if (kVerbose) kConsoleOut << "is this a FAT binary? : "; - - if (!kFatBinaryEnable) { - if (kVerbose) kConsoleOut << "not a FAT binary.\n"; - - kConsoleOut << "object " << objectFile - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - return NECTI_FAT_ERROR; - } else { - if (kVerbose) { - kConsoleOut << "Architecture matches what we expect.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= hdr.fArch; - std::size_t cnt = hdr.fCount; - - if (kVerbose) kConsoleOut << "header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - Char* raw_ae_records = new Char[cnt * sizeof(CompilerKit::AERecordHeader)]; - - if (!raw_ae_records) { - if (kVerbose) kConsoleOut << "allocation failed for records of count: " << cnt << "\n"; - } - - std::memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto* ae_records = reader_protocol.Read(raw_ae_records, cnt); - - size_t org = kLinkerDefaultOrigin; - - for (size_t ae_record_index = 0; ae_record_index < cnt; ++ae_record_index) { - CompilerKit::PEFCommandHeader command_header{0}; - std::size_t offset_of_obj = ae_records[ae_record_index].fOffset; - - std::memcpy(command_header.Name, ae_records[ae_record_index].fName, kPefNameLen); - - CompilerKit::STLString cmd_hdr_name(command_header.Name); - - // check this header if it's any valid. - if (cmd_hdr_name.find(kPefCode64) == CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefData64) == CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefZero64) == CompilerKit::STLString::npos) { - if (cmd_hdr_name.find(kLinkerStart) == CompilerKit::STLString::npos && - *command_header.Name == 0) { - if (cmd_hdr_name.find(kLdDefineSymbol) != CompilerKit::STLString::npos) { - goto ld_mark_header; - } else { - continue; - } - } - } - - if (cmd_hdr_name.find(kLinkerStart) != CompilerKit::STLString::npos && - cmd_hdr_name.find(kPefCode64) != CompilerKit::STLString::npos) { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offset_of_obj; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.VirtualSize = ae_records[ae_record_index].fSize; - command_header.Cpu = hdr.fArch; - command_header.VirtualAddress = org; - command_header.SubCpu = hdr.fSubArch; - command_header.OffsetSize = ae_records[ae_record_index].fSize; - - org += command_header.VirtualSize; - - if (kVerbose) { - kConsoleOut << "Record: " << ae_records[ae_record_index].fName << " is marked.\n"; - kConsoleOut << "Offset: " << command_header.Offset << "\n"; - } - - command_headers.emplace_back(command_header); - } - - delete[] raw_ae_records; - raw_ae_records = nullptr; - - std::vector bytes; - bytes.resize(hdr.fCodeSize); - - reader_protocol.file_pointer_.seekg(std::streamsize(hdr.fStartCode)); - reader_protocol.file_pointer_.read(bytes.data(), std::streamsize(hdr.fCodeSize)); - - kObjectBytes.push_back({.mBlob = bytes, .mOffset = hdr.fStartCode}); - - // Blob was written, close fp. - - reader_protocol.file_pointer_.close(); - - continue; - } - - kConsoleOut << "not an object container: " << objectFile << std::endl; - - // don't continue, it is a fatal error. - return NECTI_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - output_fc << pef_container; - - if (kVerbose) { - kConsoleOut << "wrote container to: " << output_fc.tellp() << ".\n"; - } - - output_fc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector not_found; - std::vector symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - CompilerKit::STLString cmd_hdr_name; - - for (auto& command_hdr : command_headers) { - // check if this symbol needs to be resolved. - if (CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_hdr.Name).find(kLdDynamicSym) == - CompilerKit::STLString::npos) { - if (kVerbose) kConsoleOut << "Found undefined symbol: " << command_hdr.Name << "\n"; - - cmd_hdr_name = command_hdr.Name; - - if (auto it = std::find(not_found.begin(), not_found.end(), cmd_hdr_name); - it == not_found.end()) { - not_found.emplace_back(cmd_hdr_name); - } - } - - symbols.emplace_back(command_hdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < command_headers.size(); ++not_found_idx) { - if (const auto it = std::find(not_found.begin(), not_found.end(), - CompilerKit::STLString(command_headers[not_found_idx].Name)); - it != not_found.end()) { - CompilerKit::STLString symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == CompilerKit::STLString::npos) continue; - - // erase the lookup prefix. - symbol_imp.erase(0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != CompilerKit::STLString::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto& command_hdr : command_headers) { - if (CompilerKit::STLString(command_hdr.Name).find(symbol_imp) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_hdr.Name).find(kLdDefineSymbol) == - CompilerKit::STLString::npos) { - CompilerKit::STLString undefined_symbol = command_hdr.Name; - auto result_of_sym = undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) { - if (result_of_sym[i] != symbol_imp[i]) goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) kConsoleOut << "Found symbol: " << command_hdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) { - if (kVerbose) - kConsoleOut << "Undefined entrypoint: " << kLinkerStart - << ", you may have forget to link " - "against the C++ runtime library.\n"; - - kConsoleOut << "Undefined entrypoint " << kLinkerStart << " for executable: " << kOutput - << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader date_cmd_hdr{}; - - time_t timestamp = time(nullptr); - - CompilerKit::STLString timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strncpy(date_cmd_hdr.Name, timeStampStr.c_str(), timeStampStr.size()); - - date_cmd_hdr.Flags = 0; - date_cmd_hdr.Kind = CompilerKit::kPefZero; - date_cmd_hdr.Offset = output_fc.tellp(); - date_cmd_hdr.VirtualSize = timeStampStr.size(); - - command_headers.push_back(date_cmd_hdr); - - CompilerKit::PEFCommandHeader abi_cmd_hdr{}; - - CompilerKit::STLString abi = kLinkerAbiContainer; - - switch (kArch) { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "_NEP"; - break; - } - default: { - abi += "_IDK"; - break; - } - } - - std::memcpy(abi_cmd_hdr.Name, abi.c_str(), abi.size()); - - abi_cmd_hdr.VirtualSize = abi.size(); - abi_cmd_hdr.Offset = output_fc.tellp(); - abi_cmd_hdr.Flags = 0; - abi_cmd_hdr.Kind = CompilerKit::kPefLinkerID; - - command_headers.push_back(abi_cmd_hdr); - - CompilerKit::PEFCommandHeader stack_cmd_hdr{0}; - - stack_cmd_hdr.Cpu = kArch; - stack_cmd_hdr.Flags = 0; - stack_cmd_hdr.VirtualSize = sizeof(uintptr_t); - stack_cmd_hdr.Offset = 0; - - std::memcpy(stack_cmd_hdr.Name, kLinkerStackSizeSymbol, strlen(kLinkerStackSizeSymbol)); - - command_headers.push_back(stack_cmd_hdr); - - CompilerKit::PEFCommandHeader uuid_cmd_hdr{}; - - std::random_device rd; - - auto seedData = std::array{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - std::memcpy(uuid_cmd_hdr.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - std::memcpy(uuid_cmd_hdr.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), uuidStr.size()); - - uuid_cmd_hdr.VirtualSize = strlen(uuid_cmd_hdr.Name); - uuid_cmd_hdr.Offset = output_fc.tellp(); - uuid_cmd_hdr.Flags = CompilerKit::kPefLinkerID; - uuid_cmd_hdr.Kind = CompilerKit::kPefZero; - - command_headers.push_back(uuid_cmd_hdr); - - // prepare a symbol vector. - std::vector undef_symbols; - std::vector dupl_symbols; - std::vector resolve_symbols; - - constexpr Int32 kPaddingOffset = 16; - - size_t previous_offset = - (command_headers.size() * sizeof(CompilerKit::PEFCommandHeader)) + kPaddingOffset; - - CompilerKit::PEFCommandHeader end_exec_hdr; - - end_exec_hdr.Offset = output_fc.tellp(); - end_exec_hdr.Flags = CompilerKit::kPefLinkerID; - end_exec_hdr.Kind = CompilerKit::kPefZero; - - std::memcpy(end_exec_hdr.Name, "Container:Exec:END", strlen("Container:Exec:END")); - - end_exec_hdr.VirtualSize = strlen(end_exec_hdr.Name); - - command_headers.push_back(end_exec_hdr); - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; commandHeaderIndex < command_headers.size(); - ++commandHeaderIndex) { - if (CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDefineSymbol) != - CompilerKit::STLString::npos && - CompilerKit::STLString(command_headers[commandHeaderIndex].Name).find(kLdDynamicSym) == - CompilerKit::STLString::npos) { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - CompilerKit::STLString symbol_name = command_headers[commandHeaderIndex].Name; - - if (!symbol_name.empty()) { - undef_symbols.emplace_back(symbol_name); - } - - command_headers[commandHeaderIndex].Offset += previous_offset; - previous_offset += command_headers[commandHeaderIndex].VirtualSize; - - CompilerKit::STLString name = command_headers[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kLinkerStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kLinkerStart) != CompilerKit::STLString::npos && - name.find(kPefCode64) != CompilerKit::STLString::npos) { - pef_container.Start = command_headers[commandHeaderIndex].Offset; - auto tellCurPos = output_fc.tellp(); - - output_fc.seekp(0); - output_fc << pef_container; - - output_fc.seekp(tellCurPos); - } - - if (kVerbose) { - kConsoleOut << "Command name: " << name << "\n"; - kConsoleOut << "VirtualAddress of command content: " - << command_headers[commandHeaderIndex].Offset << "\n"; - } - - output_fc << command_headers[commandHeaderIndex]; - - for (size_t sub_command_header_index = 0UL; sub_command_header_index < command_headers.size(); - ++sub_command_header_index) { - if (sub_command_header_index == commandHeaderIndex) continue; - - if (CompilerKit::STLString(command_headers[sub_command_header_index].Name) - .find(kLdDefineSymbol) != CompilerKit::STLString::npos && - CompilerKit::STLString(command_headers[sub_command_header_index].Name) - .find(kLdDynamicSym) == CompilerKit::STLString::npos) { - if (kVerbose) { - kConsoleOut << "Ignoring :UndefinedSymbol: headers...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto& command_hdr = command_headers[sub_command_header_index]; - - if (command_hdr.Name == CompilerKit::STLString(command_headers[commandHeaderIndex].Name)) { - if (std::find(dupl_symbols.cbegin(), dupl_symbols.cend(), command_hdr.Name) == - dupl_symbols.cend()) { - dupl_symbols.emplace_back(command_hdr.Name); - } - - if (kVerbose) kConsoleOut << "Found duplicate symbols of: " << command_hdr.Name << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!dupl_symbols.empty()) { - for (auto& symbol : dupl_symbols) { - kConsoleOut << "Multiple symbols of: " << symbol << " detected, cannot continue.\n"; - } - - return NECTI_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto& struct_of_blob : kObjectBytes) { - output_fc.write(struct_of_blob.mBlob.data(), struct_of_blob.mBlob.size()); - } - - if (kVerbose) { - kConsoleOut << "Wrote contents of: " << kOutput << "\n"; - } - - // step 3: check if we have those symbols - - std::vector unreferenced_symbols; - - for (auto& command_hdr : command_headers) { - if (auto it = - std::find(not_found.begin(), not_found.end(), CompilerKit::STLString(command_hdr.Name)); - it != not_found.end()) { - unreferenced_symbols.emplace_back(command_hdr.Name); - } - } - - if (!unreferenced_symbols.empty()) { - for (auto& unreferenced_symbol : unreferenced_symbols) { - kConsoleOut << "Undefined symbol " << unreferenced_symbol << "\n"; - } - - return NECTI_EXEC_ERROR; - } - - if ((!kStartFound || kDuplicateSymbols) && - (std::filesystem::exists(kOutput) || !unreferenced_symbols.empty())) { - if (kVerbose) { - kConsoleOut << "File: " << kOutput << " is corrupt now...\n"; - } - - return NECTI_EXEC_ERROR; - } - - return NECTI_SUCCESS; -} - -// Last rev 13-1-24 diff --git a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc b/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc deleted file mode 100644 index ed53782..0000000 --- a/dev/CompilerKit/src/Macro/CPlusPlusPreprocessor.cc +++ /dev/null @@ -1,893 +0,0 @@ -/* - * ======================================================== - * - * C++ Preprocessor Driver - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/// BUGS: 0 - -#include -#include -#include -#include -#include -#include -#include -#include - -#define kMacroPrefix '#' - -/// @author Amlal El Mahrouss (amlal@nekernel.org) -/// @file CPlusPlusPreprocessor.cc -/// @brief Preprocessor. - -typedef Int32 (*bpp_parser_fn_t)(CompilerKit::STLString& line, std::ifstream& hdr_file, - std::ofstream& pp_out); - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Preprocessor internal types. - -///////////////////////////////////////////////////////////////////////////////////////// - -namespace Detail { -enum { - kInvalid = 0, - kEqual = 100, - kGreaterEqThan, - kLesserEqThan, - kGreaterThan, - kLesserThan, - kNotEqual, - kCount = 6, -}; - -struct bpp_macro_condition final { - int32_t fType; - CompilerKit::STLString fTypeName; - - void Print() { - std::cout << "type: " << fType << "\n"; - std::cout << "type_name: " << fTypeName << "\n"; - } -}; - -struct bpp_macro final { - std::vector fArgs; - CompilerKit::STLString fName; - CompilerKit::STLString fValue; - - void Print() { - std::cout << "name: " << fName << "\n"; - std::cout << "value: " << fValue << "\n"; - - for (auto& arg : fArgs) { - std::cout << "arg: " << arg << "\n"; - } - } -}; -} // namespace Detail - -static std::vector kFiles; -static std::vector kMacros; -static std::vector kIncludes; - -static CompilerKit::STLString kWorkingDir = ""; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_if_condition -// @brief parse #if condition - -///////////////////////////////////////////////////////////////////////////////////////// - -int32_t bpp_parse_if_condition(Detail::bpp_macro_condition& cond, Detail::bpp_macro& macro, - bool& inactive_code, bool& defined, - CompilerKit::STLString& macro_str) { - if (cond.fType == Detail::kEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { - if (macro.fValue == "0") { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - } else if (cond.fType == Detail::kNotEqual) { - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - if (substr_macro.find(macro.fName) != CompilerKit::STLString::npos) { - if (substr_macro.find(macro.fValue) != CompilerKit::STLString::npos) { - defined = false; - inactive_code = true; - - return 1; - } - - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - auto substr_macro = macro_str.substr(macro_str.find(macro.fName) + macro.fName.size()); - - CompilerKit::STLString number; - - for (auto& macro_num : kMacros) { - if (substr_macro.find(macro_num.fName) != CompilerKit::STLString::npos) { - for (size_t i = 0; i < macro_num.fName.size(); ++i) { - if (isdigit(macro_num.fValue[i])) { - number += macro_num.fValue[i]; - } else { - number.clear(); - break; - } - } - - break; - } - } - - size_t y = 2; - - /* last try */ - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - size_t rhs = atol(macro.fValue.c_str()); - size_t lhs = atol(number.c_str()); - - if (lhs == 0) { - number.clear(); - ++y; - - for (; y < macro_str.size(); y++) { - if (isdigit(macro_str[y])) { - for (size_t x = y; x < macro_str.size(); x++) { - if (macro_str[x] == ' ') break; - - number += macro_str[x]; - } - - break; - } - } - - lhs = atol(number.c_str()); - } - - if (cond.fType == Detail::kGreaterThan) { - if (lhs < rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kGreaterEqThan) { - if (lhs <= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kLesserEqThan) { - if (lhs >= rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - if (cond.fType == Detail::kLesserThan) { - if (lhs > rhs) { - defined = true; - inactive_code = false; - - return 1; - } - - return 0; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief stores every included file here. - -///////////////////////////////////////////////////////////////////////////////////////// - -std::vector kAllIncludes; - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name bpp_parse_file -// @brief parse file to preprocess it. - -///////////////////////////////////////////////////////////////////////////////////////// - -void bpp_parse_file(std::ifstream& hdr_file, std::ofstream& pp_out) { - CompilerKit::STLString hdr_line; - CompilerKit::STLString line_after_include; - - bool inactive_code = false; - bool defined = false; - - try { - while (std::getline(hdr_file, hdr_line)) { - if (inactive_code) { - if (hdr_line.find("#endif") == CompilerKit::STLString::npos) { - continue; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("#endif") != CompilerKit::STLString::npos) { - inactive_code = false; - } - } - - if (hdr_line.find("*/") != CompilerKit::STLString::npos) { - hdr_line.erase(hdr_line.find("*/"), strlen("*/")); - } - - if (hdr_line.find("/*") != CompilerKit::STLString::npos) { - inactive_code = true; - - // get rid of comment. - hdr_line.erase(hdr_line.find("/*")); - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("endif") != CompilerKit::STLString::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = false; - - continue; - } - - continue; - } - - if (!defined && inactive_code) { - continue; - } - - if (defined && inactive_code) { - continue; - } - - for (auto macro : kMacros) { - if (CompilerKit::find_word(hdr_line, macro.fName)) { - if (hdr_line.substr(hdr_line.find(macro.fName)).find(macro.fName + '(') != - CompilerKit::STLString::npos) { - if (!macro.fArgs.empty()) { - CompilerKit::STLString symbol_val = macro.fValue; - std::vector args; - - size_t x_arg_indx = 0; - - CompilerKit::STLString line_after_define = hdr_line; - CompilerKit::STLString str_arg; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ' ' || subc == '\t') continue; - - if (subc == ',' || subc == ')') { - if (str_arg.empty()) continue; - - args.push_back(str_arg); - - str_arg.clear(); - - continue; - } - - str_arg.push_back(subc); - } - } - - for (auto arg : macro.fArgs) { - if (symbol_val.find(macro.fArgs[x_arg_indx]) != CompilerKit::STLString::npos) { - symbol_val.replace(symbol_val.find(macro.fArgs[x_arg_indx]), - macro.fArgs[x_arg_indx].size(), args[x_arg_indx]); - ++x_arg_indx; - } else { - throw std::runtime_error("cppdrv: Internal error."); - } - } - - auto len = macro.fName.size(); - len += symbol_val.size(); - len += 2; // ( and ) - - hdr_line.erase(hdr_line.find(")"), 1); - - hdr_line.replace(hdr_line.find(hdr_line.substr(hdr_line.find(macro.fName + '('))), - len, symbol_val); - } else { - auto value = macro.fValue; - - hdr_line.replace(hdr_line.find(macro.fName), macro.fName.size(), value); - } - } - } - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("define ") != CompilerKit::STLString::npos) { - auto line_after_define = hdr_line.substr(hdr_line.find("define ") + strlen("define ")); - - CompilerKit::STLString macro_value; - CompilerKit::STLString macro_key; - - std::size_t pos = 0UL; - - std::vector args; - bool on_args = false; - - for (auto& ch : line_after_define) { - ++pos; - - if (ch == '(') { - on_args = true; - continue; - } - - if (ch == ')') { - on_args = false; - continue; - } - - if (ch == '\\') continue; - - if (on_args) continue; - - if (ch == ' ') { - for (size_t i = pos; i < line_after_define.size(); i++) { - macro_value += line_after_define[i]; - } - - break; - } - - macro_key += ch; - } - - CompilerKit::STLString str; - - if (line_after_define.find("(") != CompilerKit::STLString::npos) { - line_after_define.erase(0, line_after_define.find("(") + 1); - - for (auto& subc : line_after_define) { - if (subc == ',' || subc == ')') { - if (str.empty()) continue; - - args.push_back(str); - - str.clear(); - - continue; - } - - str.push_back(subc); - } - } - - Detail::bpp_macro macro; - - macro.fArgs = args; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.emplace_back(macro); - - continue; - } - - if (hdr_line[0] != kMacroPrefix) { - if (inactive_code) { - continue; - } - - pp_out << hdr_line << std::endl; - - continue; - } - - if (hdr_line[0] == kMacroPrefix && hdr_line.find("ifndef") != CompilerKit::STLString::npos) { - auto line_after_ifndef = hdr_line.substr(hdr_line.find("ifndef") + strlen("ifndef") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_ifndef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = true; - inactive_code = false; - continue; - } - - if (macro == "1") { - defined = false; - inactive_code = true; - - continue; - } - - bool found = false; - - defined = true; - inactive_code = false; - - for (auto& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - found = true; - break; - } - } - - if (found) { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("else") != CompilerKit::STLString::npos) { - if (!defined && inactive_code) { - inactive_code = false; - defined = true; - - continue; - } else { - defined = false; - inactive_code = true; - - continue; - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("ifdef") != CompilerKit::STLString::npos) { - auto line_after_ifdef = hdr_line.substr(hdr_line.find("ifdef") + strlen("ifdef") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_ifdef) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - defined = false; - inactive_code = true; - - for (auto& macro_ref : kMacros) { - if (hdr_line.find(macro_ref.fName) != CompilerKit::STLString::npos) { - defined = true; - inactive_code = false; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("if") != CompilerKit::STLString::npos) { - inactive_code = true; - - std::vector bpp_macro_condition_list = { - { - .fType = Detail::kEqual, - .fTypeName = "==", - }, - { - .fType = Detail::kNotEqual, - .fTypeName = "!=", - }, - { - .fType = Detail::kLesserThan, - .fTypeName = "<", - }, - { - .fType = Detail::kGreaterThan, - .fTypeName = ">", - }, - { - .fType = Detail::kLesserEqThan, - .fTypeName = "<=", - }, - { - .fType = Detail::kGreaterEqThan, - .fTypeName = ">=", - }, - }; - - int32_t good_to_go = 0; - - for (auto& macro_condition : bpp_macro_condition_list) { - if (hdr_line.find(macro_condition.fTypeName) != CompilerKit::STLString::npos) { - for (auto& found_macro : kMacros) { - if (hdr_line.find(found_macro.fName) != CompilerKit::STLString::npos) { - good_to_go = bpp_parse_if_condition(macro_condition, found_macro, inactive_code, - defined, hdr_line); - - break; - } - } - } - } - - if (good_to_go) continue; - - auto line_after_if = hdr_line.substr(hdr_line.find("if") + strlen("if") + 1); - CompilerKit::STLString macro; - - for (auto& ch : line_after_if) { - if (ch == ' ') { - break; - } - - macro += ch; - } - - if (macro == "0") { - defined = false; - inactive_code = true; - continue; - } - - if (macro == "1") { - defined = true; - inactive_code = false; - - continue; - } - - // last try, is it defined to be one? - for (auto& macro_ref : kMacros) { - if (macro_ref.fName.find(macro) != CompilerKit::STLString::npos && - macro_ref.fValue == "1") { - inactive_code = false; - defined = true; - - break; - } - } - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("warning") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("warning") + strlen("warning") + 1); - CompilerKit::STLString message; - - for (auto& ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - std::cout << "warn: " << message << std::endl; - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("error") != CompilerKit::STLString::npos) { - auto line_after_warning = hdr_line.substr(hdr_line.find("error") + strlen("error") + 1); - CompilerKit::STLString message; - - for (auto& ch : line_after_warning) { - if (ch == '\r' || ch == '\n') { - break; - } - - message += ch; - } - - throw std::runtime_error("error: " + message); - } else if (hdr_line[0] == kMacroPrefix && - hdr_line.find("include ") != CompilerKit::STLString::npos) { - line_after_include = hdr_line.substr(hdr_line.find("include ") + strlen("include ")); - - kIncludeFile: - auto it = std::find(kAllIncludes.cbegin(), kAllIncludes.cend(), line_after_include); - - if (it != kAllIncludes.cend()) { - continue; - } - - CompilerKit::STLString path; - - kAllIncludes.push_back(line_after_include); - - bool enable = false; - bool not_local = false; - - for (auto& ch : line_after_include) { - if (ch == ' ') continue; - - if (ch == '<') { - not_local = true; - enable = true; - - continue; - } - - if (ch == '\"') { - not_local = false; - enable = true; - continue; - } - - if (enable) { - path += ch; - } - } - - if (not_local) { - bool open = false; - - if (path.ends_with('>')) { - path.erase(path.find('>')); - } - - if (path.ends_with('"')) { - path.erase(path.find('"')); - } - - for (auto& include : kIncludes) { - CompilerKit::STLString header_path = include; - header_path.push_back('/'); - header_path += path; - - std::ifstream header(header_path); - - if (!header.is_open()) continue; - - open = true; - - bpp_parse_file(header, pp_out); - - break; - } - - if (!open) { - throw std::runtime_error("cppdrv: no such include file: " + path); - } - } else { - std::ifstream header(path); - - if (!header.is_open()) throw std::runtime_error("cppdrv: no such include file: " + path); - - bpp_parse_file(header, pp_out); - } - } else { - std::cerr << ("cppdrv: unknown pre-processor directive, " + hdr_line) << "\n"; - continue; - } - } - } catch (std::out_of_range& oor) { - return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief main entrypoint of app. - -///////////////////////////////////////////////////////////////////////////////////////// - -NECTI_MODULE(CPlusPlusPreprocessorMain) { - try { - bool skip = false; - bool double_skip = false; - - Detail::bpp_macro macro_1; - - macro_1.fName = "__true"; - macro_1.fValue = "1"; - - kMacros.push_back(macro_1); - - Detail::bpp_macro macro_unreachable; - - macro_unreachable.fName = "__unreachable"; - macro_unreachable.fValue = "__compilerkit_unreachable"; - - kMacros.push_back(macro_unreachable); - - Detail::bpp_macro macro_unused; - - macro_unreachable.fName = "__unused"; - macro_unreachable.fValue = "__compilerkit_unused"; - - kMacros.push_back(macro_unused); - - Detail::bpp_macro macro_0; - - macro_0.fName = "__false"; - macro_0.fValue = "0"; - - kMacros.push_back(macro_0); - - Detail::bpp_macro macro_zka; - - macro_zka.fName = "__NECTI__"; - macro_zka.fValue = "1"; - - kMacros.push_back(macro_zka); - - Detail::bpp_macro macro_cxx; - - macro_cxx.fName = "__cplusplus"; - macro_cxx.fValue = "202302L"; - - kMacros.push_back(macro_cxx); - - Detail::bpp_macro macro_size_t; - macro_size_t.fName = "__SIZE_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINT32_TYPE__"; - macro_size_t.fValue = "unsigned int"; - - kMacros.push_back(macro_size_t); - - macro_size_t.fName = "__UINTPTR_TYPE__"; - macro_size_t.fValue = "unsigned long long int"; - - kMacros.push_back(macro_size_t); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (double_skip) { - ++index; - double_skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-cpp-ver") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-help") == 0) { - printf("%s\n", - "NeKernel Preprocessor Driver v1.11, (c) Amlal El Mahrouss 2024-2025 all rights " - "reserved."); - printf("%s\n", "-cpp-working-dir : set directory to working path."); - printf("%s\n", "-cpp-include-dir : add directory to include path."); - printf("%s\n", "-cpp-def : define a macro."); - printf("%s\n", "-cpp-ver: print the version."); - printf("%s\n", "-cpp-help: show help (this current command)."); - - return NECTI_SUCCESS; - } - - if (strcmp(argv[index], "-cpp-include-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - - skip = true; - - kIncludes.push_back(inc); - } - - if (strcmp(argv[index], "-cpp-working-dir") == 0) { - CompilerKit::STLString inc = argv[index + 1]; - skip = true; - kWorkingDir = inc; - } - - if (strcmp(argv[index], "-cpp-def") == 0 && argv[index + 1] != nullptr && - argv[index + 2] != nullptr) { - CompilerKit::STLString macro_key = argv[index + 1]; - - CompilerKit::STLString macro_value; - bool is_string = false; - - for (int argv_find_len = 0; argv_find_len < strlen(argv[index]); ++argv_find_len) { - if (!isdigit(argv[index][argv_find_len])) { - is_string = true; - macro_value += "\""; - - break; - } - } - - macro_value += argv[index + 2]; - - if (is_string) macro_value += "\""; - - Detail::bpp_macro macro; - macro.fName = macro_key; - macro.fValue = macro_value; - - kMacros.push_back(macro); - - double_skip = true; - } - - continue; - } - - kFiles.emplace_back(argv[index]); - } - - if (kFiles.empty()) return NECTI_EXEC_ERROR; - - for (auto& file : kFiles) { - if (!std::filesystem::exists(file)) continue; - - std::ifstream file_descriptor(file); - std::ofstream file_descriptor_pp(file + ".pp"); - - bpp_parse_file(file_descriptor, file_descriptor_pp); - } - - return NECTI_SUCCESS; - } catch (const std::runtime_error& e) { - std::cout << e.what() << '\n'; - } - - return NECTI_EXEC_ERROR; -} - -// Last rev 8-1-24 diff --git a/dev/CompilerKit/src/StringKit.cc b/dev/CompilerKit/src/StringKit.cc deleted file mode 100644 index d612947..0000000 --- a/dev/CompilerKit/src/StringKit.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * ======================================================== - * - * CompilerKit - * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. - * - * ======================================================== - */ - -/** - * @file StringKit.cc - * @author Amlal (amlal@nekernel.org) - * @brief C++ string manipulation API. - * @version 0.2 - * @date 2024-01-23 - * - * @copyright Copyright (c) Amlal El Mahrouss - * - */ - -#include - -namespace CompilerKit { - -Char* BasicString::Data() { - return m_Data; -} - -const Char* BasicString::CData() const { - return m_Data; -} - -SizeType BasicString::Length() const { - return strlen(m_Data); -} - -bool BasicString::operator==(const BasicString& rhs) const { - const SizeType len = Length(); - if (rhs.Length() != len) return false; - return memcmp(m_Data, rhs.m_Data, len) == 0; -} - -bool BasicString::operator==(const Char* rhs) const { - const SizeType rhs_len = string_length(rhs); - const SizeType len = Length(); - if (rhs_len != len) return false; - return memcmp(m_Data, rhs, len) == 0; -} - -bool BasicString::operator!=(const BasicString& rhs) const { - return !(*this == rhs); -} - -bool BasicString::operator!=(const Char* rhs) const { - return !(*this == rhs); -} - -BasicString StringBuilder::Construct(const Char* data) { - if (!data || *data == 0) return BasicString(0); - - BasicString view(strlen(data)); - view += data; - - return view; -} - -BasicString StringBuilder::FromInt(const char* fmt, int i) { - if (!fmt) return BasicString(0); - - Char result[sizeof(int64_t)] = {0}; - if (!to_str(result, sizeof(int64_t), i)) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(result); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += result; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString StringBuilder::FromBool(const char* fmt, bool val) { - if (!fmt) return BasicString(0); - - const Char* boolean_expr = val ? "true" : "false"; - const SizeType fmt_len = string_length(fmt); - const SizeType res_len = string_length(boolean_expr); - - BasicString output(fmt_len + res_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += boolean_expr; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -bool StringBuilder::Equals(const char* lhs, const char* rhs) { - const SizeType lhs_len = string_length(lhs); - const SizeType rhs_len = string_length(rhs); - - if (lhs_len != rhs_len) return false; - return memcmp(lhs, rhs, lhs_len) == 0; -} - -BasicString StringBuilder::Format(const char* fmt, const char* fmtRight) { - if (!fmt || !fmtRight) return BasicString(0); - - const SizeType fmt_len = string_length(fmt); - const SizeType rhs_len = string_length(fmtRight); - - BasicString output(fmt_len + rhs_len); - bool inserted = false; - - for (SizeType idx = 0; idx < fmt_len; ++idx) { - if (!inserted && fmt[idx] == '%') { - output += fmtRight; - inserted = true; - continue; - } - output += Char{fmt[idx]}; - } - - return output; -} - -BasicString& BasicString::operator+=(const Char* rhs) { - const SizeType rhs_len = strlen(rhs); - if (this->m_Cur + rhs_len >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs, rhs_len); - - this->m_Cur += rhs_len; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(const BasicString& rhs) { - if (this->m_Cur + rhs.m_Cur >= this->m_Sz) { - throw std::runtime_error("out_of_bounds: BasicString"); - } - - memcpy(this->m_Data + this->m_Cur, rhs.CData(), rhs.m_Cur); - this->m_Cur += rhs.m_Cur; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -BasicString& BasicString::operator+=(const Char ch) { - if (this->m_Cur + 1 >= this->m_Sz) { - throw std::runtime_error("out_of_bounds.."); - } - - this->m_Data[this->m_Cur++] = ch; - this->m_Data[this->m_Cur] = '\0'; - - return *this; -} - -} // namespace CompilerKit diff --git a/dev/CompilerKit/utils/AsmUtils.h b/dev/CompilerKit/utils/AsmUtils.h deleted file mode 100644 index 897fcbe..0000000 --- a/dev/CompilerKit/utils/AsmUtils.h +++ /dev/null @@ -1,92 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include -#include - -using namespace CompilerKit; - -/// @brief Get Number from lineBuffer. -/// @param lineBuffer the lineBuffer to fetch from. -/// @param numberKey where to seek that number. -/// @return -static NumberCast32 GetNumber32(STLString lineBuffer, STLString numberKey) { - auto pos = lineBuffer.find(numberKey) + numberKey.size(); - - while (lineBuffer[pos] == ' ') { - ++pos; - } - - switch (lineBuffer[pos + 1]) { - case 'x': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); - - if (kVerbose) { - kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - case 'b': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) { - if (errno != 0) { - Detail::print_error("invalid binary number:" + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_bin"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - case 'o': { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) { - if (errno != 0) { - Detail::print_error("invalid octal number: " + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_octal"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - default: { - if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); - throw std::runtime_error("invalid_hex"); - } - } - - NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); - - if (kVerbose) { - kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) << "\n"; - } - - return numOffset; - } - } -} diff --git a/dev/CompilerKit/utils/CompilerUtils.h b/dev/CompilerKit/utils/CompilerUtils.h deleted file mode 100644 index 1b086ee..0000000 --- a/dev/CompilerKit/utils/CompilerUtils.h +++ /dev/null @@ -1,116 +0,0 @@ -/* ======================================== - - Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#define kZero64Section ".zero64" -#define kCode64Section ".code64" -#define kData64Section ".data64" - -#define kZero128Section ".zero128" -#define kCode128Section ".code128" -#define kData128Section ".data128" - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kRed << "drv: " << kWhite) -#define kStdErr (std::cout << kYellow << "drv: " << kWhite) - -inline static UInt32 kErrorLimit = 10; -inline static UInt32 kAcceptableErrors = 0; -inline static bool kVerbose = false; -inline static bool kOutputAsBinary = false; - -namespace Detail { -/// @brief Linker specific blob metadata structure -struct DynamicLinkerBlob final { - std::vector mBlob{}; // PEF code/bss/data blob. - UIntPtr mOffset{0UL}; // the offset of the PEF container header... -}; - -inline void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(NECTI_EXEC_ERROR); - - ++kAcceptableErrors; -} - -inline void print_warning(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdOut << kYellow << reason << kBlank << std::endl; -} - -/// @internal -/// @brief Handler for SIGSEGV signal. -inline void drvi_crash_handler(std::int32_t id) { - CompilerKit::STLString verbose_header = "LIBCOMPILER CRASH REPORT - "; - verbose_header += kDistVersion; - verbose_header += " - "; - verbose_header += CompilerKit::current_date(); - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::cout << verbose_header << std::endl; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - kStdOut << "DATE: " << CompilerKit::current_date() << std::endl; - kStdOut << "VERSION: " << kDistVersion << std::endl; - kStdOut << "ERRNO: " << errno << std::endl; - kStdOut << "ERRNO(STRING): " << strerror(errno) << std::endl; - - switch (id) { - case SIGSEGV: { - kStdOut << "SIGNAL: Segmentation Fault." << kBlank << std::endl; - break; - } - case SIGABRT: { - kStdOut << "SIGNAL: Aborted." << kBlank << std::endl; - break; - } - } - - std::cout << kWhite; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::cout << verbose_header << std::endl; - - for (auto& ch : verbose_header) { - std::cout << '='; - } - - std::cout << std::endl; - - std::exit(NECTI_EXEC_ERROR); -} -} // namespace Detail diff --git a/dev/CompilerKit/utils/DylibHelpers.h b/dev/CompilerKit/utils/DylibHelpers.h deleted file mode 100644 index ab58fc7..0000000 --- a/dev/CompilerKit/utils/DylibHelpers.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ======================================== - - Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license - -======================================== */ - -#pragma once - -#include -#include -#include - -struct CompilerKitDylibTraits; - -typedef Int32 (*CompilerKitEntrypoint)(Int32 argc, Char const* argv[]); -typedef VoidPtr CompilerKitDylib; - -struct CompilerKitDylibTraits final { - CompilerKitDylib fDylib{nullptr}; - CompilerKitEntrypoint fEntrypoint{nullptr}; - std::mutex fMutex; - - CompilerKitDylibTraits& operator()(const Char* path, const Char* fEntrypoint) { - std::lock_guard lock(this->fMutex); - - if (!path || !fEntrypoint) return *this; - - if (this->fDylib) { - dlclose(this->fDylib); - this->fDylib = nullptr; - } - - this->fDylib = dlopen(path, RTLD_LAZY); - - if (!this->fDylib) { - return *this; - } - - this->fEntrypoint = (CompilerKitEntrypoint) dlsym(this->fDylib, fEntrypoint); - - if (!this->fEntrypoint) { - dlclose(this->fDylib); - this->fDylib = nullptr; - - return *this; - } - - return *this; - } - - NECTI_COPY_DELETE(CompilerKitDylibTraits); - - CompilerKitDylibTraits() = default; - - ~CompilerKitDylibTraits() { - if (this->fDylib) { - dlclose(this->fDylib); - this->fDylib = nullptr; - } - - this->fEntrypoint = nullptr; - } -}; -- cgit v1.2.3