diff options
| author | Amlal <amlalelmahrouss@icloud.com> | 2024-07-28 16:12:39 +0000 |
|---|---|---|
| committer | Amlal <amlalelmahrouss@icloud.com> | 2024-07-28 16:12:39 +0000 |
| commit | 6f54c8fb68063ffac8ff88bb146914df28cb8134 (patch) | |
| tree | b1fa96a4211a1563b3ebc7724aa3c281ea8fa56f | |
| parent | 7a6ac1d9cd3128a9ef96bf675a06963a617b5673 (diff) | |
| parent | 231899b44a7294bb968c2a930c97f76990376f41 (diff) | |
Merged in MHR-36 (pull request #6)
MHR-36
| -rw-r--r-- | .gitignore | 24 | ||||
| -rw-r--r-- | .vscode/c_cpp_properties.json | 60 | ||||
| -rw-r--r-- | 64asm.rsrc | 27 | ||||
| -rw-r--r-- | 64x0-cc.rsrc | 27 | ||||
| -rw-r--r-- | Doxyfile | 8 | ||||
| -rw-r--r-- | Examples/Example64k.s | 3 | ||||
| -rw-r--r-- | Examples/ExampleAMD64.asm | 6 | ||||
| -rw-r--r-- | Examples/ExampleAMD64_Return.asm | 6 | ||||
| -rw-r--r-- | Examples/ExampleCDialect.S | 28 | ||||
| -rw-r--r-- | Examples/ExampleCDialect.c | 20 | ||||
| -rw-r--r-- | Examples/ExamplePowerPC.S | 8 | ||||
| -rw-r--r-- | Examples/ExamplePowerPC.S.pp | 11 | ||||
| -rw-r--r-- | Examples/ExamplePowerPC.dmp | 5 | ||||
| -rw-r--r-- | Headers/Version.hxx | 3 | ||||
| -rw-r--r-- | Icons/app-logo.ico | bin | 108478 -> 0 bytes | |||
| -rw-r--r-- | NDKKit/AsmKit/AsmKit.hpp (renamed from Headers/AsmKit/AsmKit.hpp) | 8 | ||||
| -rw-r--r-- | NDKKit/AsmKit/CPU/32x0.hpp (renamed from Headers/AsmKit/CPU/32x0.hpp) | 4 | ||||
| -rw-r--r-- | NDKKit/AsmKit/CPU/64x0.hpp (renamed from Headers/AsmKit/CPU/64x0.hpp) | 26 | ||||
| -rw-r--r-- | NDKKit/AsmKit/CPU/amd64.hpp (renamed from Headers/AsmKit/CPU/amd64.hpp) | 26 | ||||
| -rw-r--r-- | NDKKit/AsmKit/CPU/arm64.hpp | 26 | ||||
| -rw-r--r-- | NDKKit/AsmKit/CPU/ppc.hpp (renamed from Headers/AsmKit/CPU/ppc.hpp) | 20 | ||||
| -rw-r--r-- | NDKKit/Defines.hpp (renamed from Headers/Defines.hpp) | 12 | ||||
| -rw-r--r-- | NDKKit/Macros.hpp (renamed from Headers/CompilerKit.hpp) | 4 | ||||
| -rw-r--r-- | NDKKit/NFC/AE.hpp (renamed from Headers/StdKit/AE.hpp) | 38 | ||||
| -rw-r--r-- | NDKKit/NFC/ELF.hpp (renamed from Headers/StdKit/ELF.hpp) | 0 | ||||
| -rw-r--r-- | NDKKit/NFC/ErrorID.hpp (renamed from Headers/StdKit/ErrorID.hpp) | 6 | ||||
| -rw-r--r-- | NDKKit/NFC/ErrorOr.hpp (renamed from Headers/StdKit/ErrorOr.hpp) | 6 | ||||
| -rw-r--r-- | NDKKit/NFC/PEF.hpp (renamed from Headers/StdKit/PEF.hpp) | 8 | ||||
| -rw-r--r-- | NDKKit/NFC/Ref.hpp (renamed from Headers/StdKit/Ref.hpp) | 28 | ||||
| -rw-r--r-- | NDKKit/NFC/String.hpp (renamed from Headers/StdKit/String.hpp) | 18 | ||||
| -rw-r--r-- | NDKKit/NFC/XCOFF.hxx (renamed from Headers/StdKit/XCOFF.hxx) | 14 | ||||
| -rw-r--r-- | NDKKit/Parser.hpp (renamed from Headers/ParserKit.hpp) | 63 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx (renamed from SDK/__mpcc_alloca.hxx) | 2 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_defines.hxx (renamed from SDK/__mpcc_defines.hxx) | 32 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_exception.hxx | 27 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_hint.hxx | 20 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx | 30 | ||||
| -rw-r--r-- | NDKKit/Public/SDK/CRT/__mpcc_power.inc (renamed from SDK/__mpcc_power.inc) | 2 | ||||
| -rw-r--r-- | NDKKit/Sources/32asm.cxx (renamed from Sources/32asm.cc) | 14 | ||||
| -rw-r--r-- | NDKKit/Sources/64asm.cxx (renamed from Sources/64asm.cc) | 56 | ||||
| -rw-r--r-- | NDKKit/Sources/64x0-cc.cxx | 1627 | ||||
| -rw-r--r-- | NDKKit/Sources/AssemblyFactory.cxx | 59 | ||||
| -rw-r--r-- | NDKKit/Sources/Detail/ReadMe.md (renamed from Sources/Detail/ReadMe.md) | 0 | ||||
| -rw-r--r-- | NDKKit/Sources/Detail/asmutils.hxx (renamed from Sources/Detail/asmutils.h) | 22 | ||||
| -rw-r--r-- | NDKKit/Sources/Detail/compilerutils.hxx (renamed from Sources/Detail/compilerutils.h) | 6 | ||||
| -rw-r--r-- | NDKKit/Sources/String.cxx (renamed from Sources/String.cc) | 24 | ||||
| -rw-r--r-- | NDKKit/Sources/bpp.cxx (renamed from Sources/bpp.cc) | 43 | ||||
| -rw-r--r-- | NDKKit/Sources/coff2ae.cxx (renamed from Sources/coff2ae.cc) | 13 | ||||
| -rw-r--r-- | NDKKit/Sources/compile_flags.txt (renamed from Sources/compile_flags.txt) | 2 | ||||
| -rw-r--r-- | NDKKit/Sources/cplusplus.cxx | 1025 | ||||
| -rw-r--r-- | NDKKit/Sources/elf2ae.cxx (renamed from Sources/elf2ae.cc) | 10 | ||||
| -rw-r--r-- | NDKKit/Sources/i64asm.cxx | 1484 | ||||
| -rw-r--r-- | NDKKit/Sources/link.cxx | 741 | ||||
| -rw-r--r-- | NDKKit/Sources/power-as.cxx (renamed from Sources/ppcasm.cc) | 163 | ||||
| -rw-r--r-- | NDKKit/Sources/power-cc.cxx | 1645 | ||||
| -rw-r--r-- | NDKKit/UUID.hpp (renamed from Headers/UUID.hpp) | 0 | ||||
| -rw-r--r-- | NDKKit/Version.hpp | 4 | ||||
| -rw-r--r-- | Notes/ASM specs.txt (renamed from Documentation/ASM_SPECS.TXT) | 0 | ||||
| -rw-r--r-- | Notes/HAVP DSP.txt (renamed from Documentation/HAVP.TXT) | 0 | ||||
| -rw-r--r-- | Notes/Inside 64x0.pdf (renamed from Documentation/Inside 64x0.pdf) | bin | 64675 -> 64675 bytes | |||
| -rw-r--r-- | Notes/Notice.txt (renamed from Documentation/NOTICE.TXT) | 0 | ||||
| -rw-r--r-- | Notes/RISC CPU.txt (renamed from Documentation/VNRP.TXT) | 0 | ||||
| -rw-r--r-- | ReadMe.md | 16 | ||||
| -rw-r--r-- | SDK/__mpcc_exception.hxx | 27 | ||||
| -rw-r--r-- | SDK/__mpcc_malloc.hxx | 29 | ||||
| -rw-r--r-- | Sources/64x0-cc.cc | 1354 | ||||
| -rw-r--r-- | Sources/AsmKit.cc | 51 | ||||
| -rw-r--r-- | Sources/amd64-cplusplus.cc | 397 | ||||
| -rw-r--r-- | Sources/i64asm.cc | 1247 | ||||
| -rw-r--r-- | Sources/link.cc | 641 | ||||
| -rw-r--r-- | Sources/ppc-cc.cc | 1368 | ||||
| -rw-r--r-- | bpp.rsrc | 27 | ||||
| -rw-r--r-- | i64asm.rsrc | 27 | ||||
| -rw-r--r-- | link.rsrc | 27 | ||||
| -rw-r--r-- | posix.make | 59 | ||||
| -rw-r--r-- | ppc-cc.rsrc | 27 | ||||
| -rw-r--r-- | ppcasm.rsrc | 27 | ||||
| -rw-r--r-- | win64.make | 60 |
78 files changed, 7173 insertions, 5805 deletions
@@ -8,12 +8,14 @@ local.properties .loadpath .recommenders +*.creator.user + +Examples/ + # NewOS/MP-UX executable *.exec *.bin -docs/ - # Compiled class file *.class @@ -64,8 +66,24 @@ replay_pid* Drivers/Output/Tests/*.masm +Output/32link +Output/64asm +Output/64link +Output/64x0-cc +Output/bpp +Output/cplusplus +Output/i64asm +Output/i64link +Output/link +Output/power-cc +Output/ppc-cc +Output/power-as +Output/ppclink + .vs +docs/html +docs/latex docs/doxygen *.pc @@ -129,7 +147,7 @@ Cloud9.creator.user .cproject .settings/org.eclipse.cdt.codan.core.prefs .settings/org.eclipse.core.resources.prefs -.settings/org.eclipse.core.runtime.prefs +.settings/org.eclipse.core.runtime.prefs # HDD *.hdd diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 8059633..cd1cb3d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,31 +1,31 @@ { - "configurations": [ - { - "name": "Macintosh (CLang)", - "includePath": [ - "${workspaceFolder}/Headers/**", - "${workspaceFolder}/Sources/Detail/**", - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "/usr/bin/clang", - "cStandard": "c17", - "cppStandard": "c++20", - "intelliSenseMode": "macos-clang-arm64" - }, - { - "name": "Windows (Cygwin)", - "includePath": [ - "${workspaceFolder}/Headers/**", - "${workspaceFolder}/Sources/Detail/**", - "${workspaceFolder}/**" - ], - "defines": [], - "compilerPath": "C:/cygwin64/bin/g++.exe", - "cStandard": "c17", - "cppStandard": "c++20", - "intelliSenseMode": "windows-gcc-x64" - } - ], - "version": 4 -}
\ No newline at end of file + "configurations": [ + { + "name": "Macintosh (CLang)", + "includePath": [ + "${workspaceFolder}/NDKKit/**", + "${workspaceFolder}/Sources/Detail/**", + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "macos-clang-arm64" + }, + { + "name": "Windows (Cygwin)", + "includePath": [ + "${workspaceFolder}/NDKKit/**", + "${workspaceFolder}/Sources/Detail/**", + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "C:/cygwin64/bin/g++.exe", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "windows-gcc-x64" + } + ], + "version": 4 +} diff --git a/64asm.rsrc b/64asm.rsrc deleted file mode 100644 index 44ae486..0000000 --- a/64asm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS 64x0 assembler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "64asm.exe" - VALUE "ProductName", "NewAssembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/64x0-cc.rsrc b/64x0-cc.rsrc deleted file mode 100644 index afa07df..0000000 --- a/64x0-cc.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS 64x0 C compiler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewC" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "64x0-cc.exe" - VALUE "ProductName", "NewC" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END @@ -42,7 +42,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = NewOS Programmer Workshop +PROJECT_NAME = NDK # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -54,7 +54,7 @@ PROJECT_NUMBER = 2.0.0 # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "CodeTools" +PROJECT_BRIEF = "NewOS Developer Kit" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -1017,7 +1017,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = Meta # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -1693,7 +1693,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview diff --git a/Examples/Example64k.s b/Examples/Example64k.s deleted file mode 100644 index b56003a..0000000 --- a/Examples/Example64k.s +++ /dev/null @@ -1,3 +0,0 @@ -mv r0, r3 -lda r19, 0x10000 -jlr diff --git a/Examples/ExampleAMD64.asm b/Examples/ExampleAMD64.asm deleted file mode 100644 index cc649be..0000000 --- a/Examples/ExampleAMD64.asm +++ /dev/null @@ -1,6 +0,0 @@ -#bits 64 - -export .code64 __ImageStart - -mov rax, rdx -ret diff --git a/Examples/ExampleAMD64_Return.asm b/Examples/ExampleAMD64_Return.asm deleted file mode 100644 index 0ecbaf7..0000000 --- a/Examples/ExampleAMD64_Return.asm +++ /dev/null @@ -1,6 +0,0 @@ -#bits 64 - -export .code64 __RaiseInterrupt - -int 13 -ret diff --git a/Examples/ExampleCDialect.S b/Examples/ExampleCDialect.S deleted file mode 100644 index d937aed..0000000 --- a/Examples/ExampleCDialect.S +++ /dev/null @@ -1,28 +0,0 @@ -# Path: Examples/ExampleCDialect.c -# Language: POWER Assembly (Generated from C) -# Build Date: 2024-4-28 - - - - - - - -dword export .code64 __ImageStart - - - li r3,0x1000 - - cmpw r10, r11 - beq import __MPCC_IF_PROC_6099380296 -dword export .code64 __MPCC_IF_PROC_6099380296 - - - - mr r31, r3 - blr - - - mr r31, r0 - blr - diff --git a/Examples/ExampleCDialect.c b/Examples/ExampleCDialect.c deleted file mode 100644 index e6d92fb..0000000 --- a/Examples/ExampleCDialect.c +++ /dev/null @@ -1,20 +0,0 @@ -struct -{ - int a; - int b; - int c; -}; - -int __ImageStart(int argc, char const* argv[]) -{ - int* foo = 0x1000; - - if (foo == 57) - { - foo = 0x2000; - *foo = 5; - return foo; - } - - return 57; -} diff --git a/Examples/ExamplePowerPC.S b/Examples/ExamplePowerPC.S deleted file mode 100644 index b9de796..0000000 --- a/Examples/ExamplePowerPC.S +++ /dev/null @@ -1,8 +0,0 @@ -; you you can never say! - -b 0x1000 -mflr r21 -mtlr r21 -li r3, 0 -cmpw r10, r11 -stw r7, r5+36 diff --git a/Examples/ExamplePowerPC.S.pp b/Examples/ExamplePowerPC.S.pp deleted file mode 100644 index 5eeb07f..0000000 --- a/Examples/ExamplePowerPC.S.pp +++ /dev/null @@ -1,11 +0,0 @@ -# Path: Examples/ExamplePowerPC.S.pp -# Language: POWER Assembly -# Build Date: 2024-6-4 - -bl 0x1000 - - -li r1, 0x500 -mr r2, r1 -sc -blr diff --git a/Examples/ExamplePowerPC.dmp b/Examples/ExamplePowerPC.dmp deleted file mode 100644 index 5986d03..0000000 --- a/Examples/ExamplePowerPC.dmp +++ /dev/null @@ -1,5 +0,0 @@ -0x0000000000000000: 00 10 00 48 b 0x1000 -0x0000000000000004: 00 05 20 38 li r1, 0x500 -0x0000000000000008: 78 13 21 7C or r1, r1, r2 -0x000000000000000c: 02 00 00 44 sc -0x0000000000000010: 20 00 80 4E blr
\ No newline at end of file diff --git a/Headers/Version.hxx b/Headers/Version.hxx deleted file mode 100644 index 377a688..0000000 --- a/Headers/Version.hxx +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#define kDistVersion "v1.20" diff --git a/Icons/app-logo.ico b/Icons/app-logo.ico Binary files differdeleted file mode 100644 index dbdcdee..0000000 --- a/Icons/app-logo.ico +++ /dev/null diff --git a/Headers/AsmKit/AsmKit.hpp b/NDKKit/AsmKit/AsmKit.hpp index 2ea4796..6074efc 100644 --- a/Headers/AsmKit/AsmKit.hpp +++ b/NDKKit/AsmKit/AsmKit.hpp @@ -1,14 +1,14 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/CompilerKit.hpp> -#include <Headers/Defines.hpp> -#include <Headers/StdKit/String.hpp> +#include <NDKKit/Macros.hpp> +#include <NDKKit/Defines.hpp> +#include <NDKKit/NFC/String.hpp> namespace CompilerKit { diff --git a/Headers/AsmKit/CPU/32x0.hpp b/NDKKit/AsmKit/CPU/32x0.hpp index a78a04b..7fa02ad 100644 --- a/Headers/AsmKit/CPU/32x0.hpp +++ b/NDKKit/AsmKit/CPU/32x0.hpp @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> // @brief 32x0 support. // @file CPU/32x0.hpp diff --git a/Headers/AsmKit/CPU/64x0.hpp b/NDKKit/AsmKit/CPU/64x0.hpp index a72f72f..3bd1f80 100644 --- a/Headers/AsmKit/CPU/64x0.hpp +++ b/NDKKit/AsmKit/CPU/64x0.hpp @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> #include <vector> // @brief 64x0 support. @@ -42,18 +42,20 @@ inline std::vector<CpuOpcode64x0> kOpcodes64x0 = { kAsmJump) // jump to linked return register kAsmOpcodeDecl("jrl", 0b1110011, 0b0001111, kAsmJump) // jump from return register. - kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) kAsmOpcodeDecl( - "bg", 0b1100111, 0b111, kAsmRegToReg) kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) - kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) kAsmOpcodeDecl( - "bne", 0b1100111, 0b001, kAsmRegToReg) kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) - kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) - kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) - kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) - kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) + kAsmOpcodeDecl("mv", 0b0100011, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("bg", 0b1100111, 0b111, kAsmRegToReg) + kAsmOpcodeDecl("bl", 0b1100111, 0b011, kAsmRegToReg) + kAsmOpcodeDecl("beq", 0b1100111, 0b000, kAsmRegToReg) + kAsmOpcodeDecl("bne", 0b1100111, 0b001, kAsmRegToReg) + kAsmOpcodeDecl("bge", 0b1100111, 0b101, kAsmRegToReg) + kAsmOpcodeDecl("ble", 0b1100111, 0b100, kAsmRegToReg) + kAsmOpcodeDecl("stw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("ldw", 0b0001111, 0b100, kAsmImmediate) + kAsmOpcodeDecl("lda", 0b0001111, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sta", 0b0001111, 0b001, kAsmImmediate) // add/sub without carry flag kAsmOpcodeDecl("add", 0b0101011, 0b100, kAsmImmediate) - kAsmOpcodeDecl("dec", 0b0101011, 0b101, kAsmImmediate) + kAsmOpcodeDecl("sub", 0b0101011, 0b101, kAsmImmediate) // add/sub with carry flag kAsmOpcodeDecl("addc", 0b0101011, 0b110, kAsmImmediate) kAsmOpcodeDecl("decc", 0b0101011, 0b111, kAsmImmediate) diff --git a/Headers/AsmKit/CPU/amd64.hpp b/NDKKit/AsmKit/CPU/amd64.hpp index 5a8f72a..3edd5ca 100644 --- a/Headers/AsmKit/CPU/amd64.hpp +++ b/NDKKit/AsmKit/CPU/amd64.hpp @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> // @brief AMD64 support. // @file CPU/amd64.hpp @@ -38,12 +38,20 @@ struct CpuOpcodeAMD64 #define kJumpLimitStandardLimit 0xEB inline std::vector<CpuOpcodeAMD64> kOpcodesAMD64 = { - kAsmOpcodeDecl("int", 0xCD) kAsmOpcodeDecl("into", 0xCE) kAsmOpcodeDecl( - "intd", 0xF1) kAsmOpcodeDecl("int3", 0xC3) kAsmOpcodeDecl("iret", 0xCF) - kAsmOpcodeDecl("retf", 0xCB) kAsmOpcodeDecl("retn", 0xC3) - kAsmOpcodeDecl("ret", 0xC3) kAsmOpcodeDecl("sti", 0xfb) - kAsmOpcodeDecl("cli", 0xfa) kAsmOpcodeDecl("hlt", 0xf4) - kAsmOpcodeDecl("nop", 0x90) kAsmOpcodeDecl("mov", 0x48) - kAsmOpcodeDecl("call", 0xFF)}; + kAsmOpcodeDecl("int", 0xCD) + kAsmOpcodeDecl("into", 0xCE) + kAsmOpcodeDecl("intd", 0xF1) + kAsmOpcodeDecl("int3", 0xC3) + kAsmOpcodeDecl("iret", 0xCF) + kAsmOpcodeDecl("retf", 0xCB) + kAsmOpcodeDecl("retn", 0xC3) + kAsmOpcodeDecl("ret", 0xC3) + kAsmOpcodeDecl("sti", 0xfb) + kAsmOpcodeDecl("cli", 0xfa) + kAsmOpcodeDecl("hlt", 0xf4) + kAsmOpcodeDecl("nop", 0x90) + kAsmOpcodeDecl("mov", 0x48) + kAsmOpcodeDecl("call", 0xFF) +}; #define kAsmRegisterLimit 15 diff --git a/NDKKit/AsmKit/CPU/arm64.hpp b/NDKKit/AsmKit/CPU/arm64.hpp new file mode 100644 index 0000000..a63ddfb --- /dev/null +++ b/NDKKit/AsmKit/CPU/arm64.hpp @@ -0,0 +1,26 @@ +/* ------------------------------------------- + +Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include <NDKKit/Defines.hpp> + +/// @brief ARM64 encoding support. +/// @file CPU/arm64.hpp + +struct CpuOpcodeArm64; + +/// @brief ARM64 opcode header. +struct CpuOpcodeArm64 final +{ + uint8_t fOpcode; // opcode + uint8_t fRegisterLeft; // left register index + uint8_t fRegisterRight; // right register index + bool fRegisterLeftHooked; + bool fRegisterRightHooked; + uint32_t fImmediateValue; // immediate 32-bit value + bool fImmediateValueHooked; +}; diff --git a/Headers/AsmKit/CPU/ppc.hpp b/NDKKit/AsmKit/CPU/ppc.hpp index c29286d..e3ea6c5 100644 --- a/Headers/AsmKit/CPU/ppc.hpp +++ b/NDKKit/AsmKit/CPU/ppc.hpp @@ -1,3 +1,13 @@ +/* ------------------------------------------- + + Some modifications are copyrighted under: + ZKA Technologies + + Original author: + Apple Inc + +------------------------------------------- */ + #pragma once #include <cstdint> @@ -242,7 +252,7 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x4c800421, "bfctrl", {{16, 5, BCND}, {11, 2, NUM}}}, /* branch mnemonics incorporating conditions (assember extended mnemonics) - */ + */ {0x41800000, "blt", {{16, 5, CRF}, {2, 14, PCREL}}}, {0x41800000, "blt", {{2, 14, PCREL}}}, {0x41800001, "bltl", {{16, 5, CRF}, {2, 14, PCREL}}}, @@ -1548,10 +1558,10 @@ inline CpuOpcodePPC kOpcodesPowerPC[] = { {0x7c000426, "clcs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, /* Added from the POWER 603 book. - * These are really 603 specific instructions but we mark them as OPTIONAL - * so that the -force_cpusubtype_ALL flag as to be used. This makes it so - * only 601 instructions will cause the cputype to be set to other an ALL. - */ + * These are really 603 specific instructions but we mark them as OPTIONAL + * so that the -force_cpusubtype_ALL flag as to be used. This makes it so + * only 601 instructions will cause the cputype to be set to other an ALL. + */ {0x7c0007a4, "tlbld", {{11, 5, GREG}}, OPTIONAL}, {0x7c0007e4, "tlbli", {{11, 5, GREG}}, OPTIONAL}, diff --git a/Headers/Defines.hpp b/NDKKit/Defines.hpp index 01230e6..31c1998 100644 --- a/Headers/Defines.hpp +++ b/NDKKit/Defines.hpp @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ @@ -136,12 +136,12 @@ typedef char char_type; ".64x", ".32x", ".masm", ".s", ".S", ".asm" \ } -#ifdef __MODULE_NEED__ -#define MPCC_MODULE(name) int name(int argc, char** argv) +#ifdef __NDK_MODULE__ +#define NDK_MODULE(name) int name(int argc, char** argv) #else -#define MPCC_MODULE(name) int main(int argc, char** argv) -#endif /* ifdef __MODULE_NEED__ */ +#define NDK_MODULE(name) int main(int argc, char** argv) +#endif /* ifdef __NDK_MODULE__ */ -#pragma scalar_storage_order big - endian +#pragma scalar_storage_order big-endian #endif /* ifndef __MPCC_DEFINES_HPP__ */ diff --git a/Headers/CompilerKit.hpp b/NDKKit/Macros.hpp index 9e37666..c190cda 100644 --- a/Headers/CompilerKit.hpp +++ b/NDKKit/Macros.hpp @@ -1,10 +1,10 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ -//! provide support for CompilerKit.hpp header. +/// @brief provide support for Macros.hpp header. #ifndef _CK_CL_HPP #define _CK_CL_HPP diff --git a/Headers/StdKit/AE.hpp b/NDKKit/NFC/AE.hpp index ca54671..1c929f9 100644 --- a/Headers/StdKit/AE.hpp +++ b/NDKKit/NFC/AE.hpp @@ -1,15 +1,15 @@ /* * ======================================================== * - * MPCC - * Copyright Mahrouss Logic, all rights reserved. + * NDK + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ #pragma once -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> #define kAEMag0 'A' #define kAEMag1 'E' @@ -95,9 +95,9 @@ std::ifstream& operator>>(std::ifstream& fp, namespace CompilerKit::Utils { /** - * @brief AE Reader protocol - * - */ + * @brief AE Reader protocol + * + */ class AEReadableProtocol final { public: @@ -110,12 +110,12 @@ namespace CompilerKit::Utils MPCC_COPY_DELETE(AEReadableProtocol); /** - * @brief Read AE record - * - * @param raw the containing buffer - * @param sz it's size (without sizeof(AERecordHeader) added to it.) - * @return AERecordHeaderPtr - */ + * @brief Read AE record + * + * @param raw the containing buffer + * @param sz it's size (without sizeof(AERecordHeader) added to it.) + * @return AERecordHeaderPtr + */ AERecordHeaderPtr Read(char* raw, std::size_t sz) { if (!raw) @@ -126,13 +126,13 @@ namespace CompilerKit::Utils 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. - */ + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ template <typename TypeClass> TypeClass* _Read(char* raw, std::size_t sz) { diff --git a/Headers/StdKit/ELF.hpp b/NDKKit/NFC/ELF.hpp index 4f0d0ae..4f0d0ae 100644 --- a/Headers/StdKit/ELF.hpp +++ b/NDKKit/NFC/ELF.hpp diff --git a/Headers/StdKit/ErrorID.hpp b/NDKKit/NFC/ErrorID.hpp index 363f4d5..c45b4b0 100644 --- a/Headers/StdKit/ErrorID.hpp +++ b/NDKKit/NFC/ErrorID.hpp @@ -2,15 +2,15 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ #pragma once -#include <Headers/Defines.hpp> -#include <Headers/StdKit/ErrorOr.hpp> +#include <NDKKit/Defines.hpp> +#include <NDKKit/NFC/ErrorOr.hpp> #define MPCC_EXEC_ERROR -30 #define MPCC_FILE_NOT_FOUND -31 diff --git a/Headers/StdKit/ErrorOr.hpp b/NDKKit/NFC/ErrorOr.hpp index dbd83ce..ed134a7 100644 --- a/Headers/StdKit/ErrorOr.hpp +++ b/NDKKit/NFC/ErrorOr.hpp @@ -2,15 +2,15 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ #pragma once -#include <Headers/Defines.hpp> -#include <Headers/StdKit/Ref.hpp> +#include <NDKKit/Defines.hpp> +#include <NDKKit/NFC/Ref.hpp> namespace CompilerKit { diff --git a/Headers/StdKit/PEF.hpp b/NDKKit/NFC/PEF.hpp index 6f0602c..2f460b7 100644 --- a/Headers/StdKit/PEF.hpp +++ b/NDKKit/NFC/PEF.hpp @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> // @file PEF.hpp // @brief Preferred Executable Format @@ -33,12 +33,14 @@ namespace CompilerKit { enum { + kPefArchStart = 99, kPefArchIntel86S = 100, kPefArchAMD64, kPefArchRISCV, kPefArch64000, /* 64x0 RISC architecture. */ kPefArch32000, kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, kPefArchCount = (kPefArchPowerPC - kPefArchIntel86S) + 1, kPefArchInvalid = 0xFF, }; @@ -47,7 +49,7 @@ namespace CompilerKit { kPefSubArchAMD, kPefSubArchIntel, - kPefSubArchARM, + kPefSubArchGeneric, kPefSubArchIBM, }; diff --git a/Headers/StdKit/Ref.hpp b/NDKKit/NFC/Ref.hpp index c4aa2d3..0f9c0e3 100644 --- a/Headers/StdKit/Ref.hpp +++ b/NDKKit/NFC/Ref.hpp @@ -3,7 +3,7 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ @@ -12,18 +12,25 @@ namespace CompilerKit { - // @author Amlal EL Mahrouss - // @brief Reference class, refers to a pointer of data in static memory. + // @author Amlal + // @brief Reference holder class, refers to a pointer of data in static memory. template <typename T> class Ref final { public: explicit Ref() = default; - ~Ref() = default; + + ~Ref() + { + if (m_Strong) + { + (*m_Class).~T(); + } + } public: explicit Ref(T cls, const bool& strong = false) - : m_Class(cls), m_Strong(strong) + : m_Class(&cls), m_Strong(strong) { } @@ -41,12 +48,12 @@ namespace CompilerKit T& Leak() { - return m_Class; + return *m_Class; } T operator*() { - return m_Class; + return *m_Class; } bool IsStrong() const @@ -56,11 +63,11 @@ namespace CompilerKit operator bool() { - return m_Class; + return *m_Class; } private: - T m_Class; + T* m_Class; bool m_Strong{false}; }; @@ -68,8 +75,7 @@ namespace CompilerKit class NonNullRef final { public: - NonNullRef() = delete; - NonNullRef(nullPtr) = delete; + explicit NonNullRef() = delete; explicit NonNullRef(T* ref) : m_Ref(ref, true) diff --git a/Headers/StdKit/String.hpp b/NDKKit/NFC/String.hpp index adc6a9d..200bf2c 100644 --- a/Headers/StdKit/String.hpp +++ b/NDKKit/NFC/String.hpp @@ -2,22 +2,22 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ #pragma once -#include <Headers/Defines.hpp> -#include <Headers/StdKit/ErrorOr.hpp> +#include <NDKKit/Defines.hpp> +#include <NDKKit/NFC/ErrorOr.hpp> namespace CompilerKit { /** - * @brief StringView class, contains a C string and manages it. - * @note No need to manage it it's getting deleted by default. - */ + * @brief StringView class, contains a C string and manages it. + * @note No need to manage it it's getting deleted by default. + */ class StringView final { @@ -76,9 +76,9 @@ namespace CompilerKit }; /** - * @brief StringBuilder class - * @note These results shall call delete[] after they're used. - */ + * @brief StringBuilder class + * @note These results shall call delete[] after they're used. + */ struct StringBuilder final { static StringView Construct(const CharType* data); diff --git a/Headers/StdKit/XCOFF.hxx b/NDKKit/NFC/XCOFF.hxx index e21a380..57ecfd2 100644 --- a/Headers/StdKit/XCOFF.hxx +++ b/NDKKit/NFC/XCOFF.hxx @@ -1,20 +1,20 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies - File: XCOFF.hpp - Purpose: XCOFF for NewOS. + File: XCOFF.hpp + Purpose: XCOFF for NewOS. - Revision History: + Revision History: - 04/07/24: Added file (amlel) + 04/07/24: Added file (amlel) ------------------------------------------- */ #ifndef __XCOFF__ #define __XCOFF__ -#include <Headers/Defines.hpp> +#include <NDKKit/Defines.hpp> #define kXCOFF64Magic 0x01F7 @@ -38,4 +38,4 @@ namespace CompilerKit } XCoffFileHeader; } // namespace CompilerKit -#endif // ifndef __XCOFF__
\ No newline at end of file +#endif // ifndef __XCOFF__ diff --git a/Headers/ParserKit.hpp b/NDKKit/Parser.hpp index e4277c6..c67057d 100644 --- a/Headers/ParserKit.hpp +++ b/NDKKit/Parser.hpp @@ -1,17 +1,17 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/AsmKit/AsmKit.hpp> +#include <NDKKit/AsmKit/AsmKit.hpp> #include <vector> -namespace ParserKit +namespace CompilerKit { - using namespace CompilerKit; + inline auto cInvalidLang = "?"; /// @brief Compiler backend, implements a frontend, such as C, C++... /// See Toolchain, for some examples. @@ -34,7 +34,12 @@ namespace ParserKit //! @brief What language are we dealing with? virtual const char* Language() { - return "Invalid Language"; + return cInvalidLang; + } + + virtual bool IsValid() + { + return strcmp(this->Language(), cInvalidLang); } }; @@ -43,20 +48,50 @@ namespace ParserKit struct CompilerKeyword; /// we want to do that because to separate keywords. - enum + enum KeywordKind { + eKeywordKindNamespace, + eKeywordKindFunctionStart, + eKeywordKindFunctionEnd, + eKeywordKindVariable, + eKeywordKindVariablePtr, + eKeywordKindType, + eKeywordKindTypePtr, + eKeywordKindExpressionBegin, + eKeywordKindExpressionEnd, + eKeywordKindArgSeparator, + eKeywordKindBodyStart, + eKeywordKindBodyEnd, + eKeywordKindClass, + eKeywordKindPtrAccess, eKeywordKindAccess, - eKeywordKindObject, - eKeywordKindDataType, - eKeywordKindCompilerAttribute, - eKeywordKindKeyword, + eKeywordKindIf, + eKeywordKindElse, + eKeywordKindElseIf, + eKeywordKindVariableAssign, + eKeywordKindVariableDec, + eKeywordKindVariableInc, + eKeywordKindConstant, + eKeywordKindTypedef, + eKeywordKindEndInstr, + eKeywordKindSpecifier, + eKeywordKindInvalid, + eKeywordKindReturn, + eKeywordKindCommentInline, + eKeywordKindCommentMultiLineStart, + eKeywordKindCommentMultiLineEnd, + eKeywordKindEq, + eKeywordKindNotEq, + eKeywordKindGreaterEq, + eKeywordKindLessEq, + eKeywordKindPtr, }; /// \brief Compiler keyword information struct. struct CompilerKeyword { std::string keyword_name; - int32_t keyword_kind = eKeywordKindKeyword; + KeywordKind keyword_kind = eKeywordKindInvalid; }; struct SyntaxLeafList final { @@ -65,11 +100,11 @@ namespace ParserKit Int32 fUserType; #ifdef __PK_USE_STRUCT_INSTEAD__ CompilerKeyword fUserData; - CompilerKeyword fUserValue; #else std::string fUserData; - std::string fUserValue; #endif + + std::string fUserValue; struct SyntaxLeaf* fNext; }; @@ -140,4 +175,4 @@ namespace ParserKit return false; } -} // namespace ParserKit +} // namespace CompilerKit diff --git a/SDK/__mpcc_alloca.hxx b/NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx index f56da9f..02b3123 100644 --- a/SDK/__mpcc_alloca.hxx +++ b/NDKKit/Public/SDK/CRT/__mpcc_alloca.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ diff --git a/SDK/__mpcc_defines.hxx b/NDKKit/Public/SDK/CRT/__mpcc_defines.hxx index c87f570..19ed8a4 100644 --- a/SDK/__mpcc_defines.hxx +++ b/NDKKit/Public/SDK/CRT/__mpcc_defines.hxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ @@ -30,8 +30,9 @@ typedef char* caddr_t; #ifdef __GNUC__ #include <CRT/__mpcc_alloca.hxx> #define __mpcc_alloca(sz) __mpcc_alloca_gcc(sz) +#define __packed__ __attribute__((packed)) #elif defined(__MPCC__) - +#define __packed__ __mpcc_packed__ #define __alloca(sz) __mpcc_alloca(sz) #endif @@ -41,29 +42,21 @@ typedef char* caddr_t; #define __init_decl() \ extern "C" \ { + + #define __fini_decl() \ - } \ - ; + }; \ + + #else #define __init_decl() #define __fini_decl() #endif -#if __has_builtin(__builtin_alloca) -#define alloca(sz) __builtin_alloca(sz) -#ifdef __alloca -#undef __alloca -#endif -#define __alloca alloca -#else -#warning alloca not detected (MPCC) -#endif - typedef long long off_t; typedef unsigned long long uoff_t; -typedef union float_cast -{ +typedef union float_cast { struct { unsigned int mantissa : 23; @@ -72,10 +65,9 @@ typedef union float_cast }; float f; -} __attribute__((packed)) float_cast_t; +} __packed__ float_cast_t; -typedef union double_cast -{ +typedef union double_cast { struct { unsigned long long int mantissa : 52; @@ -84,7 +76,7 @@ typedef union double_cast }; double f; -} __attribute__((packed)) double_cast_t; +} __packed__ double_cast_t; #endif // ifndef __GNUC__ diff --git a/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx b/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx new file mode 100644 index 0000000..dac42ad --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_exception.hxx @@ -0,0 +1,27 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +/// This file is an implementation of __throw* family of functions. + +#include <exception> +#include <iostream> +#include <stdexcept> + +namespace std +{ + inline void __throw_general(void) + { + throw std::runtime_error("NDK C++ Runtime error."); + } + + inline void __throw_domain_error(const char* error) + { + std::cout << "NDK C++: Domain error: " << error << "\r"; + __throw_general(); + } +} // namespace std diff --git a/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx b/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx new file mode 100644 index 0000000..02dbc94 --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_hint.hxx @@ -0,0 +1,20 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#pragma compiler(hint_manifest) + +#define _Input +#define _Output + +#define _Optional + +#define _StrictCheckInput +#define _StrictCheckOutput + +#define _InOut +#define _StrictInOut diff --git a/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx b/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx new file mode 100644 index 0000000..eeaa67b --- /dev/null +++ b/NDKKit/Public/SDK/CRT/__mpcc_malloc.hxx @@ -0,0 +1,30 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#pragma once + +#include <algorithm> + +namespace stdx +{ + /// @brief allocate a new class. + /// @tparam KindClass the class type to allocate. + template <typename KindClass, typename... Args> + inline void* allocate(Args&&... args) + { + return new KindClass(std::forward(args)...); + } + + /// @brief free a class. + /// @tparam KindClass the class type to allocate. + template <typename KindClass> + inline void release(KindClass ptr) + { + if (!ptr) + return; + delete ptr; + } +} // namespace stdx diff --git a/SDK/__mpcc_power.inc b/NDKKit/Public/SDK/CRT/__mpcc_power.inc index 96403a4..90b1364 100644 --- a/SDK/__mpcc_power.inc +++ b/NDKKit/Public/SDK/CRT/__mpcc_power.inc @@ -1,5 +1,5 @@ # Path: SDK/__mpcc_power.inc -# Language: Mahrouss POWER Assembly support for GNU. +# Language: NDK POWER Assembly support for GNU. # Build Date: 2024-6-4 %ifdef __CODETOOLS__ diff --git a/Sources/32asm.cc b/NDKKit/Sources/32asm.cxx index e5aa500..23111bc 100644 --- a/Sources/32asm.cc +++ b/NDKKit/Sources/32asm.cxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ @@ -9,7 +9,7 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 32asm.cxx -// @author Amlal El Mahrouss +// @author ZKA Technologies // @brief 32x0 Assembler. // REMINDER: when dealing with an undefined symbol use (string @@ -19,10 +19,10 @@ #define __ASM_NEED_32x0__ 1 -#include <Headers/AsmKit/CPU/32x0.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> +#include <NDKKit/AsmKit/CPU/32x0.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/NFC/PEF.hpp> #include <filesystem> #include <fstream> #include <iostream> @@ -49,4 +49,4 @@ ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssembler32000) { return 0; } +NDK_MODULE(NewOSAssembler32000) { return 0; } diff --git a/Sources/64asm.cc b/NDKKit/Sources/64asm.cxx index d2568e2..0a92157 100644 --- a/Sources/64asm.cc +++ b/NDKKit/Sources/64asm.cxx @@ -1,6 +1,6 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ @@ -9,8 +9,8 @@ ///////////////////////////////////////////////////////////////////////////////////////// // @file 64asm.cxx -// @author Amlal El Mahrouss -// @brief 64x0 Assembler. +// @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. @@ -19,10 +19,10 @@ #define __ASM_NEED_64x0__ 1 -#include <Headers/AsmKit/CPU/64x0.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> +#include <NDKKit/AsmKit/CPU/64x0.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/NFC/PEF.hpp> #include <algorithm> #include <filesystem> #include <fstream> @@ -105,26 +105,26 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssembler64000) { +NDK_MODULE(NewOSAssembler64000) { for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: v1.10\n64asm: Copyright (c) " - "2024 Mahrouss Logic.\n"; + "ZKA Technologies.\n"; return 0; - } else if (strcmp(argv[i], "-h") == 0) { + } else if (strcmp(argv[i], "/h") == 0) { kStdOut << "64asm: 64x0 Assembler.\n64asm: Copyright (c) 2024 Mahrouss " "Logic.\n"; - kStdOut << "-version: Print program version.\n"; - kStdOut << "-verbose: Print verbose output.\n"; - kStdOut << "-binary: Output as flat binary.\n"; - kStdOut << "-64xxx: Compile for a subset of the X64000.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + kStdOut << "/64xxx: Compile for a subset of the X64000.\n"; return 0; - } else if (strcmp(argv[i], "-binary") == 0) { + } else if (strcmp(argv[i], "/binary") == 0) { kOutputAsBinary = true; continue; - } else if (strcmp(argv[i], "-verbose") == 0) { + } else if (strcmp(argv[i], "/verbose") == 0) { kVerbose = true; continue; } @@ -303,7 +303,7 @@ asm_fail_exit: static bool asm_read_attributes(std::string &line) { // import is the opposite of export, it signals to the ld // that we need this symbol. - if (ParserKit::find_word(line, "import")) { + if (CompilerKit::find_word(line, "import")) { if (kOutputAsBinary) { detail::print_error("Invalid import directive in flat binary mode.", "64asm"); @@ -314,7 +314,7 @@ static bool asm_read_attributes(std::string &line) { /// sanity check to avoid stupid linker errors. if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); + detail::print_error("Invalid import", "power-as"); throw std::runtime_error("invalid_import"); } @@ -364,7 +364,7 @@ static bool asm_read_attributes(std::string &line) { // export is a special keyword used by 64asm to tell the AE output stage to // mark this section as a header. it currently supports .code64, .data64., // .zero64 - else if (ParserKit::find_word(line, "export")) { + else if (CompilerKit::find_word(line, "export")) { if (kOutputAsBinary) { detail::print_error("Invalid export directive in flat binary mode.", "64asm"); @@ -454,9 +454,9 @@ std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, const std::string &file) { std::string err_str; - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { if (line.find('#') != std::string::npos) { line.erase(line.find('#')); } else if (line.find(';') != std::string::npos) { @@ -539,7 +539,7 @@ std::string CompilerKit::Encoder64x0::CheckLine(std::string &line, if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcode64x0.fName); it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcode64x0.fName)) { + if (CompilerKit::find_word(line, opcode64x0.fName)) { if (!isspace(line[line.find(opcode64x0.fName) + strlen(opcode64x0.fName)])) { err_str += "\nMissing space between "; @@ -668,11 +668,11 @@ bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, bool CompilerKit::Encoder64x0::WriteLine(std::string &line, const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; + if (CompilerKit::find_word(line, "export ")) return true; for (auto &opcode64x0 : kOpcodes64x0) { // strict check here - if (ParserKit::find_word(line, opcode64x0.fName) && + if (CompilerKit::find_word(line, opcode64x0.fName) && detail::algorithm::is_valid(line)) { std::string name(opcode64x0.fName); std::string jump_label, cpy_jump_label; @@ -763,7 +763,7 @@ bool CompilerKit::Encoder64x0::WriteLine(std::string &line, "invalid combination of opcode and registers.\nline: " + line, file); throw std::runtime_error("invalid_comb_op_reg"); - } else if (found_some == 1 && name == "dec") { + } else if (found_some == 1 && name == "sub") { detail::print_error( "invalid combination of opcode and registers.\nline: " + line, file); diff --git a/NDKKit/Sources/64x0-cc.cxx b/NDKKit/Sources/64x0-cc.cxx new file mode 100644 index 0000000..19d995d --- /dev/null +++ b/NDKKit/Sources/64x0-cc.cxx @@ -0,0 +1,1627 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// BUGS: 0 +/// TODO: none + +#include <NDKKit/AsmKit/CPU/64x0.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/UUID.hpp> +#include <filesystem> +#include <cstdio> +#include <fstream> +#include <iostream> +#include <memory> +#include <random> +#include <string> +#include <utility> +#include <vector> + +/* C driver */ +/* This is part of the NDK. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file 64x0-cc.cxx +/// @brief 64x0 C Compiler. + +/// TODO: support structures, else if, else, . and -> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kOk (0) + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNAL STUFF OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + // 'my_foo' + std::string fName; + + // if instance: stores a valid register. + std::string fReg; + + // offset count + std::size_t fOffsetsCnt; + + // offset array. + std::vector<std::pair<Int32, std::string>> fOffsets; + }; + + struct CompilerState final + { + std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector<std::string> kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "64k C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector<detail::CompilerType> kCompilerVariables; +static std::vector<std::string> kCompilerFunctions; +static std::vector<detail::CompilerType> kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array<int, std::mt19937::state_size>{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tldw r19, "; + + // make it pretty. + if (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + syntaxLeaf.fUserValue += value + "\n"; + } + + syntaxLeaf.fUserValue += "\tjlr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = "\tlda r12, import "; + syntaxLeaf.fUserValue += + kIfFunction + + "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " + "r10, r11, r12\ndword export .code64 " + + kIfFunction + "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error("assignement of value in struct " + textBuffer, + file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tlda "; + else + substr += "\tldw "; + } + else + { + substr += "\tldw "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + if (var_to_find == kCompilerVariables.cend()) + { + ++kRegisterCounter; + + kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); + kCompilerVariables.push_back({.fName = substr}); + } + + syntaxLeaf.fUserValue += substr; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + if (textBuffer[text_index] == '=') + break; + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tlda r19, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n\tjrl\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "sub "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector<std::string> forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector<CompilerVariableRange> variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (CompilerKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (CompilerKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector<char> opens; + std::vector<char> closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCCInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCCInterface() = default; + ~AssemblyCCInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCCInterface); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArch64x0; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCCInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector<const char*> exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector<std::string> keywords = {"ldw", "stw", "lda", "sta", + "add", "sub", "mv"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector<std::string> access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (CompilerKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import " + needle) != + std::string::npos) + { + std::string range = "import " + needle; + leaf.fUserValue.replace( + leaf.fUserValue.find("import " + needle), range.size(), + needle); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mv"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mv" && keyword != "add" && + keyword != "sub") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mv"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include <Version.hpp> + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "ZKA C Driver, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLang64x0) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyCCInterface()); + kMachine = CompilerKit::AssemblyFactory::kArch64x0; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '/') + { + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/NDKKit/Sources/AssemblyFactory.cxx b/NDKKit/Sources/AssemblyFactory.cxx new file mode 100644 index 0000000..9f1b768 --- /dev/null +++ b/NDKKit/Sources/AssemblyFactory.cxx @@ -0,0 +1,59 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +#include <NDKKit/AsmKit/AsmKit.hpp> +#include <NDKKit/NFC/ErrorID.hpp> + +/** + * @file AssemblyFactory.cxx + * @author amlal (amlal@zeta.com) + * @brief Assembler Kit + * @version 0.1 + * @date 2024-01-27 + * + * @copyright Copyright (c) 2024, ZKA Technologies + * + */ + +#include <iostream> + +//! @file AsmKit.cpp +//! @brief AssemblyKit source implementation. + +namespace CompilerKit +{ + ///! @brief Compile for specific format (ELF, PEF, ZBIN) + Int32 AssemblyFactory::Compile(std::string& sourceFile, + const Int32& arch) noexcept + { + if (sourceFile.length() < 1 || !fMounted) + return MPCC_UNIMPLEMENTED; + + return fMounted->CompileToFormat(sourceFile, arch); + } + + ///! @brief mount assembly backend. + void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept + { + if (mountPtr) + { + fMounted = mountPtr; + } + } + + ///! @brief Unmount assembler. + AssemblyInterface* AssemblyFactory::Unmount() noexcept + { + auto mount_prev = fMounted; + + if (mount_prev) + { + fMounted = nullptr; + } + + return mount_prev; + } +} // namespace CompilerKit diff --git a/Sources/Detail/ReadMe.md b/NDKKit/Sources/Detail/ReadMe.md index e9d0a2c..e9d0a2c 100644 --- a/Sources/Detail/ReadMe.md +++ b/NDKKit/Sources/Detail/ReadMe.md diff --git a/Sources/Detail/asmutils.h b/NDKKit/Sources/Detail/asmutils.hxx index 2408998..abb7f82 100644 --- a/Sources/Detail/asmutils.h +++ b/NDKKit/Sources/Detail/asmutils.hxx @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/AsmKit/AsmKit.hpp> -#include <Headers/ParserKit.hpp> +#include <NDKKit/AsmKit/AsmKit.hpp> +#include <NDKKit/Parser.hpp> using namespace CompilerKit; @@ -32,7 +32,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) { if (errno != 0) { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); + detail::print_error("invalid hex number: " + lineBuffer, "asm"); throw std::runtime_error("invalid_hex"); } } @@ -41,7 +41,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) if (kVerbose) { - kStdOut << "ppcasm: found a base 16 number here: " << lineBuffer.substr(pos) + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) << "\n"; } @@ -52,7 +52,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) { if (errno != 0) { - detail::print_error("invalid binary number:" + lineBuffer, "ppcasm"); + detail::print_error("invalid binary number:" + lineBuffer, "asm"); throw std::runtime_error("invalid_bin"); } } @@ -61,7 +61,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) if (kVerbose) { - kStdOut << "ppcasm: found a base 2 number here:" << lineBuffer.substr(pos) + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) << "\n"; } @@ -72,7 +72,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) { if (errno != 0) { - detail::print_error("invalid octal number: " + lineBuffer, "ppcasm"); + detail::print_error("invalid octal number: " + lineBuffer, "asm"); throw std::runtime_error("invalid_octal"); } } @@ -81,7 +81,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) if (kVerbose) { - kStdOut << "ppcasm: found a base 8 number here:" << lineBuffer.substr(pos) + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) << "\n"; } @@ -92,7 +92,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) { if (errno != 0) { - detail::print_error("invalid hex number: " + lineBuffer, "ppcasm"); + detail::print_error("invalid hex number: " + lineBuffer, "asm"); throw std::runtime_error("invalid_hex"); } } @@ -101,7 +101,7 @@ static NumberCast32 GetNumber32(std::string lineBuffer, std::string numberKey) if (kVerbose) { - kStdOut << "ppcasm: found a base 10 number here:" << lineBuffer.substr(pos) + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) << "\n"; } diff --git a/Sources/Detail/compilerutils.h b/NDKKit/Sources/Detail/compilerutils.hxx index 038f3cf..fd2b6d2 100644 --- a/Sources/Detail/compilerutils.h +++ b/NDKKit/Sources/Detail/compilerutils.hxx @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ #pragma once -#include <Headers/AsmKit/AsmKit.hpp> -#include <Headers/ParserKit.hpp> +#include <NDKKit/AsmKit/AsmKit.hpp> +#include <NDKKit/Parser.hpp> #define kZero64Section ".zero64" #define kCode64Section ".code64" diff --git a/Sources/String.cc b/NDKKit/Sources/String.cxx index 449c933..f69f9b9 100644 --- a/Sources/String.cc +++ b/NDKKit/Sources/String.cxx @@ -2,24 +2,23 @@ * ======================================================== * * CompilerKit - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ /** - * @file String.cc + * @file String.cxx * @author Amlal (amlal@mahrouss-logic.com) * @brief C++ string manipulation API. * @version 0.2 * @date 2024-01-23 * - * @copyright Copyright (c) 2024 Mahrouss Logic + * @copyright Copyright (c) ZKA Technologies * */ -#include <Headers/StdKit/String.hpp> -#include <utility> +#include <NDKKit/NFC/String.hpp> namespace CompilerKit { CharType *StringView::Data() { return m_Data; } @@ -80,10 +79,13 @@ StringView StringBuilder::Construct(const CharType *data) { const char *StringBuilder::FromInt(const char *fmt, int i) { if (!fmt) return ("-1"); - char *ret = new char[8 + string_length(fmt)]; + auto ret_len = 8 + string_length(fmt); + char *ret = new char[ret_len]; if (!ret) return ("-1"); + memset(ret, 0, ret_len); + CharType result[8]; if (!to_str(result, sizeof(int), i)) { delete[] ret; @@ -150,18 +152,18 @@ bool StringBuilder::Equals(const char *lhs, const char *rhs) { return true; } -const char *StringBuilder::Format(const char *fmt, const char *fmt2) { - if (!fmt || !fmt2) return ("?"); +const char *StringBuilder::Format(const char *fmt, const char *fmtRight) { + if (!fmt || !fmtRight) return ("?"); - char *ret = new char[string_length(fmt2) + string_length(fmt2)]; + char *ret = new char[string_length(fmtRight) + string_length(fmtRight)]; if (!ret) return ("?"); for (SizeType idx = 0; idx < string_length(fmt); ++idx) { if (fmt[idx] == '%') { SizeType result_cnt = idx; - for (SizeType y_idx = 0; y_idx < string_length(fmt2); ++y_idx) { - ret[result_cnt] = fmt2[y_idx]; + for (SizeType y_idx = 0; y_idx < string_length(fmtRight); ++y_idx) { + ret[result_cnt] = fmtRight[y_idx]; ++result_cnt; } diff --git a/Sources/bpp.cc b/NDKKit/Sources/bpp.cxx index 1e15366..9a2943c 100644 --- a/Sources/bpp.cc +++ b/NDKKit/Sources/bpp.cxx @@ -2,15 +2,15 @@ * ======================================================== * * bpp - * Copyright Mahrouss Logic, all rights reserved. + * Copyright ZKA Technologies, all rights reserved. * * ======================================================== */ /// BUGS: 0 -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/ErrorID.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/ErrorID.hpp> #include <algorithm> #include <filesystem> #include <fstream> @@ -19,9 +19,9 @@ #define kMacroPrefix '%' -// @author Amlal El Mahrouss (amlel) -// @file bpp.cc -// @brief C preprocessor. +/// @author Amlal El Mahrouss (amlel) +/// @file bpp.cxx +/// @brief Preprocessor. typedef Int32 (*bpp_parser_fn_t)(std::string &line, std::ifstream &hdr_file, std::ofstream &pp_out); @@ -279,7 +279,7 @@ void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { } for (auto macro : kMacros) { - if (ParserKit::find_word(hdr_line, macro.fName) && + if (CompilerKit::find_word(hdr_line, macro.fName) && hdr_line.find("%def") == std::string::npos) { auto value = macro.fValue; @@ -775,7 +775,7 @@ void bpp_parse_file(std::ifstream &hdr_file, std::ofstream &pp_out) { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSPreprocessor) { +NDK_MODULE(NewOSPreprocessor) { try { bool skip = false; bool double_skip = false; @@ -810,23 +810,24 @@ MPCC_MODULE(NewOSPreprocessor) { continue; } - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0) { - printf("%s\n", "bpp v1.11, (c) Mahrouss Logic"); + if (argv[index][0] == '/') { + if (strcmp(argv[index], "/version") == 0) { + printf("%s\n", "bpp v1.11, (c) ZKA Technologies"); return 0; } - if (strcmp(argv[index], "-h") == 0) { - printf("%s\n", "bpp v1.11, (c) Mahrouss Logic"); - printf("%s\n", "-working-dir <path>: set directory to working path."); - printf("%s\n", "-include-dir <path>: add directory to include path."); - printf("%s\n", "-def <name> <value>: def macro."); - printf("%s\n", "-version: print the version."); + if (strcmp(argv[index], "/help") == 0) { + printf("%s\n", "ZKA Preprocessor Driver v1.11, (c) ZKA Technologies"); + printf("%s\n", "/working-dir <path>: set directory to working path."); + printf("%s\n", "/include-dir <path>: add directory to include path."); + printf("%s\n", "/def <name> <value>: def macro."); + printf("%s\n", "/version: print the version."); + printf("%s\n", "/help: show help."); return 0; } - if (strcmp(argv[index], "-include-dir") == 0) { + if (strcmp(argv[index], "/include-dir") == 0) { std::string inc = argv[index + 1]; skip = true; @@ -834,13 +835,13 @@ MPCC_MODULE(NewOSPreprocessor) { kIncludes.push_back(inc); } - if (strcmp(argv[index], "-working-dir") == 0) { + if (strcmp(argv[index], "/working-dir") == 0) { std::string inc = argv[index + 1]; skip = true; kWorkingDir = inc; } - if (strcmp(argv[index], "-def") == 0 && argv[index + 1] != nullptr && + if (strcmp(argv[index], "/def") == 0 && argv[index + 1] != nullptr && argv[index + 2] != nullptr) { std::string macro_key = argv[index + 1]; @@ -892,7 +893,7 @@ MPCC_MODULE(NewOSPreprocessor) { std::cout << e.what() << '\n'; } - return 0; + return 1; } // Last rev 8-1-24 diff --git a/Sources/coff2ae.cc b/NDKKit/Sources/coff2ae.cxx index 952be69..c9ea8c0 100644 --- a/Sources/coff2ae.cc +++ b/NDKKit/Sources/coff2ae.cxx @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/NFC/PEF.hpp> #include <filesystem> #include <fstream> #include <iostream> @@ -15,8 +15,9 @@ ///////////////////////////////////////////////////////////////////////////////////////// -/// @brief COFF To AE entrypoint, the program/module starts here. +/// @file coff2ae.cxx +/// @brief COFF To AE, the program/module starts here. ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSCOFFToAE) { return 0; } +NDK_MODULE(NewOSCOFFToAE) { return 0; } diff --git a/Sources/compile_flags.txt b/NDKKit/Sources/compile_flags.txt index 028be9d..6ec6b8a 100644 --- a/Sources/compile_flags.txt +++ b/NDKKit/Sources/compile_flags.txt @@ -1,5 +1,5 @@ -std=c++20 -I../ --I../StdKit +-I../Headers -I./ -I./Detail/ diff --git a/NDKKit/Sources/cplusplus.cxx b/NDKKit/Sources/cplusplus.cxx new file mode 100644 index 0000000..ae4a300 --- /dev/null +++ b/NDKKit/Sources/cplusplus.cxx @@ -0,0 +1,1025 @@ +/* + * ======================================================== + * + * cplusplus + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +/// bugs: 0 + +#define __PK_USE_STRUCT_INSTEAD__ 1 + +#define kPrintF printf + +#define kOk (0) + +#define kSplashCxx() \ + kPrintF(kWhite "%s\n", "ZKA C++ Compiler Driver, (c) 2024 ZKA Electronics, all rights reserved.") + +// import, @MLAutoRelease { ... }, fn foo() -> auto { ... } + +#include <NDKKit/AsmKit/CPU/amd64.hpp> +#include <NDKKit/Parser.hpp> +#include <UUID.hpp> + +#include <cctype> +#include <cstdio> +#include <fstream> +#include <iostream> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +/* ZKA C++ driver */ +/* This is part of NDK. */ +/* (c) ZKA Technologies */ + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief Optimized C++ Compiler. +/// @todo Throw error for scoped inside scoped variables when they get referenced outside. +/// @todo Add class/struct/enum support. + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +// INTERNALS OF THE C COMPILER + +///////////////////////////////////// + +/// @internal +namespace detail +{ + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Offset based struct/class + struct CompilerStructMap final + { + std::string fName; + std::string fReg; + + // offset counter + std::size_t fOffsetsCnt; + + // offset array + std::vector<std::pair<Int32, std::string>> fOffsets; + }; + + struct CompilerState final + { + std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; + +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + { + file.erase(file.find(".pp"), 3); + } + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cplusplus ] " << kWhite + << ((file == "cplusplus") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cplusplus ] " << kWhite << reason << kBlank + << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cplusplus ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; + +///////////////////////////////////////// + +// ARGUMENTS REGISTERS (R8, R15) + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 8; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::vector<CompilerKit::CompilerKeyword> kKeywords; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector<std::string> kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static size_t kBracesCount = 0UL; + +/* @brief C++ compiler backend for the ZKA C++ driver */ +class CompilerBackendCPlusPlus final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCPlusPlus() = default; + ~CompilerBackendCPlusPlus() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); + + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override; +}; + +/// @internal compiler variables + +static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; +static std::vector<detail::CompilerType> kCompilerVariables; +static std::vector<std::string> kCompilerFunctions; + +static std::vector<std::string> kRegisterMap; + +static std::vector<std::string> cRegisters = { + "rbx", + "rsi", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "xmm12", + "xmm13", + "xmm14", + "xmm15", +}; + +/// @brief The PEF calling convention (caller must save rax, rbp) +/// @note callee must return via **rax**. +static std::vector<std::string> cRegistersCall = { + "rcx", + "rdx", + "r8", + "r9", + "xmm8", + "xmm9", + "xmm10", + "xmm11", +}; + +static size_t kLevelFunction = 0UL; + +/// detail namespaces + +const char* CompilerBackendCPlusPlus::Language() +{ + return "ZKA C++"; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @name Compile +/// @brief Generate MASM assembly from a C++ source. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCPlusPlus::Compile(const std::string& text, + const char* file) +{ + if (text.empty()) + return false; + + // if (expr) + // int name = expr; + // expr; + + std::size_t index = 0UL; + std::vector<std::pair<CompilerKit::CompilerKeyword, std::size_t>> keywords_list; + + bool found = false; + static bool commentBlock = false; + + for (auto& keyword : kKeywords) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + switch (keyword.keyword_kind) + { + case CompilerKit::eKeywordKindCommentMultiLineStart: { + commentBlock = true; + return true; + } + case CompilerKit::eKeywordKindCommentMultiLineEnd: { + commentBlock = false; + break; + } + case CompilerKit::eKeywordKindCommentInline: { + break; + } + default: + break; + } + + if (text[text.find(keyword.keyword_name) - 1] == '+' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) - 1] == '-' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + if (text[text.find(keyword.keyword_name) + 1] == '=' && + keyword.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + continue; + + keywords_list.emplace_back(std::make_pair(keyword, index)); + ++index; + + found = true; + } + } + + if (!found && !commentBlock) + { + for (size_t i = 0; i < text.size(); i++) + { + if (isalnum(text[i])) + { + detail::print_error("syntax error: " + text, file); + return false; + } + } + } + + for (auto& keyword : keywords_list) + { + auto syntax_tree = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + switch (keyword.first.keyword_kind) + { + case CompilerKit::KeywordKind::eKeywordKindIf: { + auto expr = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 1, text.find(")") - 1); + + if (expr.find(">=") != std::string::npos) + { + auto left = text.substr(text.find(keyword.first.keyword_name) + keyword.first.keyword_name.size() + 2, expr.find("<=") + strlen("<=")); + auto right = text.substr(expr.find(">=") + strlen(">="), text.find(")") - 1); + + size_t i = right.size() - 1; + + try + { + while (!std::isalnum(right[i])) + { + right.erase(i, 1); + --i; + } + + right.erase(0, i); + } + catch (...) + { + right.erase(0, i); + } + + i = left.size() - 1; + try + { + + while (!std::isalnum(left[i])) + { + left.erase(i, 1); + --i; + } + + left.erase(0, i); + } + catch (...) + { + left.erase(0, i); + } + + if (!isdigit(left[0]) || + !isdigit(right[0])) + { + auto indexRight = 0UL; + + auto& valueOfVar = !isdigit(left[0]) ? left : right; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + "," + cRegisters[indexRight + 1] + "\n"; + + goto done_iterarting_on_if; + } + + auto& valueOfVarOpposite = isdigit(left[0]) ? left : right; + + syntax_tree.fUserValue += "mov " + cRegisters[indexRight + 1] + ", " + valueOfVarOpposite + "\n"; + syntax_tree.fUserValue += "mov " + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + syntax_tree.fUserValue += "cmp " + cRegisters[kRegisterMap.size() - 1] + ", " + cRegisters[indexRight + 1] + "\n"; + + break; + } + } + + done_iterarting_on_if: + + std::string fnName = text; + fnName.erase(fnName.find(keyword.first.keyword_name)); + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue += "jge offset [rsp + 4]\n"; + } + + break; + } + case CompilerKit::KeywordKind::eKeywordKindFunctionStart: { + if (text.ends_with(";")) + { + break; + } + + for (auto& ch : text) + { + if (isdigit(ch)) + { + goto dont_accept; + } + } + + goto accept; + + dont_accept: + return true; + + accept: + std::string fnName = text; + + for (auto& ch : fnName) + { + if (ch == ' ') + ch = '_'; + } + + syntax_tree.fUserValue = "export .code64 __MPCC_" + fnName + "\n"; + + ++kLevelFunction; + } + case CompilerKit::KeywordKind::eKeywordKindFunctionEnd: { + if (text.ends_with(";")) + break; + + --kLevelFunction; + + if (kRegisterMap.size() > cRegisters.size()) + { + --kLevelFunction; + } + + if (kLevelFunction < 1) + kRegisterMap.clear(); + break; + } + case CompilerKit::KeywordKind::eKeywordKindEndInstr: + case CompilerKit::KeywordKind::eKeywordKindVariableInc: + case CompilerKit::KeywordKind::eKeywordKindVariableDec: + case CompilerKit::KeywordKind::eKeywordKindVariableAssign: { + std::string valueOfVar = ""; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + valueOfVar = text.substr(text.find("+=") + 2); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + valueOfVar = text.substr(text.find("-=") + 2); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + { + valueOfVar = text.substr(text.find("=") + 1); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + break; + } + + while (valueOfVar.find(";") != std::string::npos && + keyword.first.keyword_kind != CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + valueOfVar.erase(valueOfVar.find(";")); + } + + std::string varName = text; + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + varName.erase(varName.find("+=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + varName.erase(varName.find("-=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableAssign) + { + varName.erase(varName.find("=")); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + varName.erase(varName.find(";")); + } + + static bool typeFound = false; + + for (auto& keyword : kKeywords) + { + if (keyword.keyword_kind == CompilerKit::eKeywordKindType) + { + if (text.find(keyword.keyword_name) != std::string::npos) + { + if (text[text.find(keyword.keyword_name)] == ' ') + { + typeFound = false; + continue; + } + + typeFound = true; + } + } + } + + std::string instr = "mov "; + + if (typeFound) + { + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + detail::print_error("Can't increment variable when it's being created.", file); + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + detail::print_error("Can't decrement variable when it's being created.", file); + } + + if (kRegisterMap.size() > cRegisters.size()) + { + ++kLevelFunction; + } + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + std::size_t indexRight = 0UL; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != valueOfVar) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + goto done; + } + + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size() - 1] + ", " + valueOfVar + "\n"; + break; + } + + if (((int)indexRight - 1) < 0) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + } + + done: + kRegisterMap.push_back(varName); + } + else + { + if (kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindType || + kKeywords[keyword.second - 1].keyword_kind == CompilerKit::eKeywordKindTypePtr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindEndInstr) + { + syntax_tree.fUserValue = "\n"; + continue; + } + + if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableInc) + { + instr = "add "; + } + else if (keyword.first.keyword_kind == CompilerKit::KeywordKind::eKeywordKindVariableDec) + { + instr = "sub "; + } + + std::string varErrCpy = varName; + + while (varName.find(" ") != std::string::npos) + { + varName.erase(varName.find(" "), 1); + } + + while (varName.find("\t") != std::string::npos) + { + varName.erase(varName.find("\t"), 1); + } + + std::size_t indxReg = 0UL; + + for (size_t i = 0; !isalnum(valueOfVar[i]); i++) + { + if (i > valueOfVar.size()) + break; + + valueOfVar.erase(i, 1); + } + + while (valueOfVar.find(" ") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find(" "), 1); + } + + while (valueOfVar.find("\t") != std::string::npos) + { + valueOfVar.erase(valueOfVar.find("\t"), 1); + } + + constexpr auto cTrueVal = "true"; + constexpr auto cFalseVal = "false"; + + /// interpet boolean values, since we're on C++ + + if (valueOfVar == cTrueVal) + { + valueOfVar = "1"; + } + else if (valueOfVar == cFalseVal) + { + valueOfVar = "0"; + } + + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != varName) + continue; + + std::size_t indexRight = 0ul; + + for (auto pairRight : kRegisterMap) + { + ++indexRight; + + if (pairRight != varName) + { + syntax_tree.fUserValue = instr + cRegisters[kRegisterMap.size()] + ", " + valueOfVar + "\n"; + continue; + } + + syntax_tree.fUserValue = instr + cRegisters[indexRight - 1] + ", " + valueOfVar + "\n"; + break; + } + + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + varErrCpy, file); + } + } + + break; + } + case CompilerKit::KeywordKind::eKeywordKindReturn: { + auto pos = text.find("return") + strlen("return") + 1; + std::string subText = text.substr(pos); + subText = subText.erase(subText.find(";")); + size_t indxReg = 0UL; + + if (subText[0] != '\"' && + subText[0] != '\'') + { + if (!isdigit(subText[0])) + { + for (auto pair : kRegisterMap) + { + ++indxReg; + + if (pair != subText) + continue; + + syntax_tree.fUserValue = "mov rax, " + cRegisters[indxReg] + "\r\nret\n"; + break; + } + + if (syntax_tree.fUserValue.empty()) + { + detail::print_error("Variable not declared: " + subText, file); + } + } + else + { + syntax_tree.fUserValue = "mov rax, " + subText + "\r\nret\n"; + } + } + else + { + syntax_tree.fUserValue = "mov rcx, " + subText + "\n"; + syntax_tree.fUserValue = "mov rax, rcx\r\nret\n"; + } + + break; + } + default: + break; + } + + syntax_tree.fUserData = keyword.first; + kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); + } + +_MpccOkay: + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyCPlusPlusInterface final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyCPlusPlusInterface() = default; + ~AssemblyCPlusPlusInterface() override = default; + + MPCC_COPY_DEFAULT(AssemblyCPlusPlusInterface); + + [[maybe_unused]] + static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchAMD64; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyCPlusPlusInterface::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + + const char* cExts[] = kAsmFileExts; + + std::string dest = src_file; + dest += cExts[4]; + + if (dest.empty()) + { + dest = "CXX-NDK-"; + + std::random_device rd; + auto seed_data = std::array<int, std::mt19937::state_size>{}; + + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator(generator); + + auto id = gen(); + dest += uuids::to_string(id); + } + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "; Language: AMD64 assembly. (Generated from C++)\n"; + (*kState.fOutputAssembly) << "; Date: " << fmt << "\n"; + (*kState.fOutputAssembly) << "#bits 64\n#org 0x1000000" + << "\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.emplace_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string source; + + while (std::getline(src_fp, source)) + { + // Compile into an object file. + kCompilerBackend->Compile(source.c_str(), src.c_str()); + } + + for (auto& ast : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << ast.fUserValue; + } + + if (kAcceptableErrors > 0) + return -1; + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +static void cxx_print_help() +{ + kSplashCxx(); + kPrintF("%s", "No help available, see:\n"); + kPrintF("%s", "www.zeta.com/developer/cplusplus\n"); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExtListCxx \ + { \ + ".cpp", ".cxx", ".cc", ".c++", ".cp" \ + } + +NDK_MODULE(CompilerCPlusPlus) +{ + bool skip = false; + + kKeywords.push_back({.keyword_name = "if", .keyword_kind = CompilerKit::eKeywordKindIf}); + kKeywords.push_back({.keyword_name = "else", .keyword_kind = CompilerKit::eKeywordKindElse}); + kKeywords.push_back({.keyword_name = "else if", .keyword_kind = CompilerKit::eKeywordKindElseIf}); + + kKeywords.push_back({.keyword_name = "class", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "struct", .keyword_kind = CompilerKit::eKeywordKindClass}); + kKeywords.push_back({.keyword_name = "namespace", .keyword_kind = CompilerKit::eKeywordKindNamespace}); + kKeywords.push_back({.keyword_name = "typedef", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "using", .keyword_kind = CompilerKit::eKeywordKindTypedef}); + kKeywords.push_back({.keyword_name = "{", .keyword_kind = CompilerKit::eKeywordKindBodyStart}); + kKeywords.push_back({.keyword_name = "}", .keyword_kind = CompilerKit::eKeywordKindBodyEnd}); + kKeywords.push_back({.keyword_name = "auto", .keyword_kind = CompilerKit::eKeywordKindVariable}); + kKeywords.push_back({.keyword_name = "int", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "bool", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "unsigned", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "short", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "char", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "long", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "float", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "double", .keyword_kind = CompilerKit::eKeywordKindType}); + kKeywords.push_back({.keyword_name = "void", .keyword_kind = CompilerKit::eKeywordKindType}); + + kKeywords.push_back({.keyword_name = "auto*", .keyword_kind = CompilerKit::eKeywordKindVariablePtr}); + kKeywords.push_back({.keyword_name = "int*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "bool*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "unsigned*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "short*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "char*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "long*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "float*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "double*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + kKeywords.push_back({.keyword_name = "void*", .keyword_kind = CompilerKit::eKeywordKindTypePtr}); + + kKeywords.push_back({.keyword_name = "(", .keyword_kind = CompilerKit::eKeywordKindFunctionStart}); + kKeywords.push_back({.keyword_name = ")", .keyword_kind = CompilerKit::eKeywordKindFunctionEnd}); + kKeywords.push_back({.keyword_name = "=", .keyword_kind = CompilerKit::eKeywordKindVariableAssign}); + kKeywords.push_back({.keyword_name = "+=", .keyword_kind = CompilerKit::eKeywordKindVariableInc}); + kKeywords.push_back({.keyword_name = "-=", .keyword_kind = CompilerKit::eKeywordKindVariableDec}); + kKeywords.push_back({.keyword_name = "const", .keyword_kind = CompilerKit::eKeywordKindConstant}); + kKeywords.push_back({.keyword_name = "*", .keyword_kind = CompilerKit::eKeywordKindPtr}); + kKeywords.push_back({.keyword_name = "->", .keyword_kind = CompilerKit::eKeywordKindPtrAccess}); + kKeywords.push_back({.keyword_name = ".", .keyword_kind = CompilerKit::eKeywordKindAccess}); + kKeywords.push_back({.keyword_name = ",", .keyword_kind = CompilerKit::eKeywordKindArgSeparator}); + kKeywords.push_back({.keyword_name = ";", .keyword_kind = CompilerKit::eKeywordKindEndInstr}); + kKeywords.push_back({.keyword_name = ":", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "public:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "private:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "protected:", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "final", .keyword_kind = CompilerKit::eKeywordKindSpecifier}); + kKeywords.push_back({.keyword_name = "return", .keyword_kind = CompilerKit::eKeywordKindReturn}); + kKeywords.push_back({.keyword_name = "/*", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "*/", .keyword_kind = CompilerKit::eKeywordKindCommentMultiLineStart}); + kKeywords.push_back({.keyword_name = "//", .keyword_kind = CompilerKit::eKeywordKindCommentInline}); + kKeywords.push_back({.keyword_name = "==", .keyword_kind = CompilerKit::eKeywordKindEq}); + kKeywords.push_back({.keyword_name = "!=", .keyword_kind = CompilerKit::eKeywordKindNotEq}); + kKeywords.push_back({.keyword_name = ">=", .keyword_kind = CompilerKit::eKeywordKindGreaterEq}); + kKeywords.push_back({.keyword_name = "<=", .keyword_kind = CompilerKit::eKeywordKindLessEq}); + + kFactory.Mount(new AssemblyCPlusPlusInterface()); + kCompilerBackend = new CompilerBackendCPlusPlus(); + + for (auto index = 1UL; index < argc; ++index) + { + if (argv[index][0] == '/') + { + if (skip) + { + skip = false; + continue; + } + + if (strcmp(argv[index], "/v") == 0 || + strcmp(argv[index], "/version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "/verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "/h") == 0 || strcmp(argv[index], "/help") == 0) + { + cxx_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "/dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "/max-errors") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown option: "; + err += argv[index]; + + detail::print_error(err, "cplusplus"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string argv_i = argv[index]; + + std::vector exts = kExtListCxx; + bool found = false; + + for (std::string ext : exts) + { + if (argv_i.find(ext) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + if (kState.fVerbose) + { + detail::print_error(argv_i + " is not a valid C++ source.\n", "cplusplus"); + } + + return 1; + } + + if (kFactory.Compile(argv_i, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 +// diff --git a/Sources/elf2ae.cc b/NDKKit/Sources/elf2ae.cxx index 77568dc..451c706 100644 --- a/Sources/elf2ae.cc +++ b/NDKKit/Sources/elf2ae.cxx @@ -1,12 +1,12 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/NFC/PEF.hpp> #include <filesystem> #include <fstream> #include <iostream> @@ -19,4 +19,4 @@ ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSELFToAE) { return 0; } +NDK_MODULE(NewOSELFToAE) { return 0; } diff --git a/NDKKit/Sources/i64asm.cxx b/NDKKit/Sources/i64asm.cxx new file mode 100644 index 0000000..ed77988 --- /dev/null +++ b/NDKKit/Sources/i64asm.cxx @@ -0,0 +1,1484 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +///////////////////////////////////////////////////////////////////////////////////////// + +/// @file i64asm.cxx +/// @author Amlal EL Mahrouss +/// @brief AMD64 Assembler. + +/// REMINDER: when dealing with an undefined symbol use (string +/// size):LinkerFindSymbol:(string) so that ld will look for it. + +///////////////////////////////////////////////////////////////////////////////////////// + +/// bugs: 0 + +/// feature request: 1 +/// Encode registers in mov, add, xor... + +///////////////////////////////////////////////////////////////////////////////////////// + +#define __ASM_NEED_AMD64__ 1 + +#define kAssemblerPragmaSymStr "#" +#define kAssemblerPragmaSym '#' + +#include <NDKKit/AsmKit/CPU/amd64.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/NFC/PEF.hpp> +#include <algorithm> +#include <cstdlib> +#include <filesystem> +#include <fstream> +#include <iostream> +#include <memory> +#include <vector> + +///////////////////// + +// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kWhite) +#define kStdErr (std::cout << kRed) + +static char kOutputArch = CompilerKit::kPefArchAMD64; +static Boolean kOutputAsBinary = false; + +static UInt32 kErrorLimit = 10; +static UInt32 kAcceptableErrors = 0; + +constexpr auto cAMD64IPAlignment = 0x4U; + +static std::size_t kCounter = 1UL; + +static std::uintptr_t kOrigin = kPefBaseOrigin; +static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; + +/// @brief keep it simple by default. +static std::int32_t kRegisterBitWidth = 16U; + +static bool kVerbose = false; + +static std::vector<i64_byte_t> kAppBytes; + +static CompilerKit::AERecordHeader kCurrentRecord{ + .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; + +static std::vector<CompilerKit::AERecordHeader> kRecords; +static std::vector<std::string> kDefinedSymbols; +static std::vector<std::string> kUndefinedSymbols; + +static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; +static const std::string kRelocSymbol = ":RuntimeSymbol:"; + +// \brief forward decl. +static bool asm_read_attributes(std::string& line); + +namespace detail +{ + void print_error(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + kStdErr << kRed << "[ i64asm ] " << kWhite + << ((file == "i64asm") ? "internal assembler error " + : ("in file, " + file)) + << kBlank << std::endl; + kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + void print_warning(std::string reason, const std::string& file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (!file.empty()) + { + kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; + } + + kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank + << std::endl; + } +} // namespace detail + +#include <asmutils.hxx> + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief AMD64 assembler entrypoint, the program/module starts here. + +///////////////////////////////////////////////////////////////////////////////////////// + +NDK_MODULE(NewOSAssemblerAMD64) +{ + //////////////// CPU OPCODES BEGIN //////////////// + + std::string opcodes_jump[kJumpLimit] = { + "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", + "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", + "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; + + for (i64_hword_t i = 0; i < kJumpLimit; i++) + { + CpuOpcodeAMD64 code{ + .fName = opcodes_jump[i], + .fOpcode = static_cast<i64_hword_t>(kAsmJumpOpcode + i)}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + kOpcodesAMD64.push_back(code); + + for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) + { + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; + kOpcodesAMD64.push_back(code); + } + + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + kOpcodesAMD64.push_back(lahf); + + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + kOpcodesAMD64.push_back(lds); + + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + kOpcodesAMD64.push_back(lea); + + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + kOpcodesAMD64.push_back(nop); + + //////////////// CPU OPCODES END //////////////// + + for (size_t i = 1; i < argc; ++i) + { + if (argv[i][0] == '/') + { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: v1.10\ni64asm: Copyright " + "(c) ZKA Technologies.\n"; + return 0; + } + else if (strcmp(argv[i], "/h") == 0) + { + kStdOut << "i64asm: AMD64 Assembler Driver.\ni64asm: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version: Print program version.\n"; + kStdOut << "/verbose: Print verbose output.\n"; + kStdOut << "/binary: Output as flat binary.\n"; + + return 0; + } + else if (strcmp(argv[i], "/binary") == 0) + { + kOutputAsBinary = true; + continue; + } + else if (strcmp(argv[i], "/verbose") == 0) + { + kVerbose = true; + continue; + } + + kStdOut << "i64asm: ignore " << argv[i] << "\n"; + continue; + } + + if (!std::filesystem::exists(argv[i])) + { + kStdOut << "i64asm: can't open: " << argv[i] << std::endl; + goto asm_fail_exit; + } + + std::string object_output(argv[i]); + + for (auto& ext : kAsmFileExts) + { + if (object_output.find(ext) != std::string::npos) + { + object_output.erase(object_output.find(ext), std::strlen(ext)); + } + } + + object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; + + std::ifstream file_ptr(argv[i]); + std::ofstream file_ptr_out(object_output, std::ofstream::binary); + + if (file_ptr_out.bad()) + { + if (kVerbose) + { + kStdOut << "i64asm: error: " << strerror(errno) << "\n"; + } + } + + std::string line; + + CompilerKit::AEHeader hdr{0}; + + memset(hdr.fPad, kAEInvalidOpcode, kAEPad); + + hdr.fMagic[0] = kAEMag0; + hdr.fMagic[1] = kAEMag1; + hdr.fSize = sizeof(CompilerKit::AEHeader); + hdr.fArch = kOutputArch; + + ///////////////////////////////////////////////////////////////////////////////////////// + + // COMPILATION LOOP + + ///////////////////////////////////////////////////////////////////////////////////////// + + CompilerKit::EncoderAMD64 asm64; + + while (std::getline(file_ptr, line)) + { + if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) + { + detail::print_error(ln, argv[i]); + continue; + } + + try + { + asm_read_attributes(line); + asm64.WriteLine(line, argv[i]); + } + catch (const std::exception& e) + { + if (kVerbose) + { + std::string what = e.what(); + detail::print_warning("exit because of: " + what, "i64asm"); + } + + try + { + std::filesystem::remove(object_output); + } + catch (...) + { + } + + goto asm_fail_exit; + } + } + + if (!kOutputAsBinary) + { + if (kVerbose) + { + kStdOut << "i64asm: Writing object file...\n"; + } + + // this is the final step, write everything to the file. + + auto pos = file_ptr_out.tellp(); + + hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); + + file_ptr_out << hdr; + + if (kRecords.empty()) + { + kStdErr << "i64asm: At least one record is needed to write an object " + "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; + + std::filesystem::remove(object_output); + return -1; + } + + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + std::size_t record_count = 0UL; + + for (auto& rec : kRecords) + { + if (kVerbose) + kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; + + rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; + rec.fOffset = record_count; + ++record_count; + + file_ptr_out << rec; + } + + // increment once again, so that we won't lie about the kUndefinedSymbols. + ++record_count; + + for (auto& sym : kUndefinedSymbols) + { + CompilerKit::AERecordHeader _record_hdr{0}; + + if (kVerbose) + kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; + + _record_hdr.fKind = kAEInvalidOpcode; + _record_hdr.fSize = sym.size(); + _record_hdr.fOffset = record_count; + + ++record_count; + + memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); + memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + + file_ptr_out << _record_hdr; + + ++kCounter; + } + + auto pos_end = file_ptr_out.tellp(); + + file_ptr_out.seekp(pos); + + hdr.fStartCode = pos_end; + hdr.fCodeSize = kAppBytes.size(); + + file_ptr_out << hdr; + + file_ptr_out.seekp(pos_end); + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: Write raw binary...\n"; + } + } + + // byte from byte, we write this. + for (auto& byte : kAppBytes) + { + if (byte == 0) + continue; + + if (byte == 0xFF) + { + byte = 0; + } + + file_ptr_out << reinterpret_cast<const char*>(&byte)[0]; + } + + if (kVerbose) + kStdOut << "i64asm: Wrote file with program in it.\n"; + + file_ptr_out.flush(); + file_ptr_out.close(); + + if (kVerbose) + kStdOut << "i64asm: Exit succeeded.\n"; + + return 0; + } + +asm_fail_exit: + + if (kVerbose) + kStdOut << "i64asm: Exit failed.\n"; + + return -1; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for attributes +// returns true if any was found. + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool asm_read_attributes(std::string& line) +{ + // import is the opposite of export, it signals to the ld + // that we need this symbol. + if (CompilerKit::find_word(line, "import")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_import_bin"); + } + + auto name = line.substr(line.find("import") + strlen("import") + 1); + + if (name.size() == 0) + { + detail::print_error("Invalid import", "power-as"); + throw std::runtime_error("invalid_import"); + } + + std::string result = std::to_string(name.size()); + result += kUndefinedSymbol; + + // mangle this + for (char& j : name) + { + if (j == ' ' || j == ',') + j = '$'; + } + + result += name; + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, result.c_str(), result.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + // export is a special keyword used by i64asm to tell the AE output stage to + // mark this section as a header. it currently supports .code64, .data64 and + // .zero64. + else if (CompilerKit::find_word(line, "export")) + { + if (kOutputAsBinary) + { + detail::print_error("Invalid directive in flat binary mode.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + auto name = line.substr(line.find("export") + strlen("export") + 1); + + std::string name_copy = name; + + for (char& j : name) + { + if (j == ' ') + j = '$'; + } + + if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != + kDefinedSymbols.end()) + { + detail::print_error("Symbol already defined.", "i64asm"); + throw std::runtime_error("invalid_export_bin"); + } + + kDefinedSymbols.push_back(name); + + if (name.find(".code64") != std::string::npos) + { + // data is treated as code. + + name_copy.erase(name_copy.find(".code64"), strlen(".code64")); + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + else if (name.find(".data64") != std::string::npos) + { + // no code will be executed from here. + + name_copy.erase(name_copy.find(".data64"), strlen(".data64")); + kCurrentRecord.fKind = CompilerKit::kPefData; + } + else if (name.find(".zero64") != std::string::npos) + { + // this is a bss section. + + name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); + kCurrentRecord.fKind = CompilerKit::kPefZero; + } + + // this is a special case for the start stub. + // we want this so that ld can find it. + + if (name == kPefStart) + { + kCurrentRecord.fKind = CompilerKit::kPefCode; + } + + while (name_copy.find(" ") != std::string::npos) + name_copy.erase(name_copy.find(" "), 1); + + kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); + ++kOrigin; + + // now we can tell the code size of the previous kCurrentRecord. + + if (!kRecords.empty()) + kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); + + memset(kCurrentRecord.fName, 0, kAESymbolLen); + memcpy(kCurrentRecord.fName, name.c_str(), name.size()); + + ++kCounter; + + memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); + + kRecords.emplace_back(kCurrentRecord); + + return true; + } + + return false; +} + +// \brief algorithms and helpers. + +namespace detail::algorithm +{ + // \brief authorize a brief set of characters. + static inline bool is_not_alnum_space(char c) + { + return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || + (c == ',') || (c == '(') || (c == ')') || (c == '"') || + (c == '\'') || (c == '[') || (c == ']') || (c == '+') || + (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); + } + + bool is_valid(const std::string& str) + { + return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); + } +} // namespace detail::algorithm + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Check for line (syntax check) + +///////////////////////////////////////////////////////////////////////////////////////// + +std::string CompilerKit::EncoderAMD64::CheckLine(std::string& line, + const std::string& file) +{ + std::string err_str; + + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + CompilerKit::find_word(line, kAssemblerPragmaSymStr) || + CompilerKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) + { + if (line.find(';') != std::string::npos) + { + line.erase(line.find(';')); + } + else + { + // now check the line for validity + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non valid characters.\nhere -> "; + err_str += line; + } + } + + return err_str; + } + + if (!detail::algorithm::is_valid(line)) + { + err_str = "Line contains non alphanumeric characters.\nHere -> "; + err_str += line; + + return err_str; + } + + // check for a valid instruction format. + + if (line.find(',') != std::string::npos) + { + if (line.find(',') + 1 == line.size()) + { + err_str += "\nInstruction lacks right register, here -> "; + err_str += line.substr(line.find(',')); + + return err_str; + } + else + { + bool nothing_on_right = true; + + if (line.find(',') + 1 > line.size()) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + + auto substr = line.substr(line.find(',') + 1); + + for (auto& ch : substr) + { + if (ch != ' ' && ch != '\t') + { + nothing_on_right = false; + } + } + + // this means we found nothing after that ',' . + if (nothing_on_right) + { + err_str += "\nInstruction not complete, here -> "; + err_str += line; + + return err_str; + } + } + } + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + if (CompilerKit::find_word(line, opcodeAMD64.fName)) + { + return err_str; + } + } + + err_str += "\nUnrecognized instruction -> " + line; + + return err_str; +} + +bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); + res += kOrigin; + + if (errno != 0) + { + return false; + } + + CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + for (char& i : num.number) + { + if (i == 0) + i = 0xFF; + + kAppBytes.push_back(i); + } + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t& pos, + std::string& jump_label) +{ + if (!isdigit(jump_label[pos])) + return false; + + switch (jump_label[pos + 1]) + { + case 'x': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); + !res) + { + if (errno != 0) + { + detail::print_error("invalid hex number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_hex"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 16 number here: " + << jump_label.substr(pos) << "\n"; + } + + return true; + } + case 'b': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); + !res) + { + if (errno != 0) + { + detail::print_error("invalid binary number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_bin"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 2 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + case 'o': { + if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); + !res) + { + if (errno != 0) + { + detail::print_error("invalid octal number: " + jump_label, "i64asm"); + throw std::runtime_error("invalid_octal"); + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 8 number here: " + << jump_label.substr(pos) << "\n"; + } + + kAppBytes.push_back(num.number); + + return true; + } + default: { + break; + } + } + + /* check for errno and stuff like that */ + if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) + { + if (errno != 0) + { + return false; + } + } + + CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( + strtol(jump_label.substr(pos).c_str(), nullptr, 10)); + + kAppBytes.push_back(num.number); + + if (kVerbose) + { + kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) + << "\n"; + } + + return true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +// @brief Read and write an instruction to the output array. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerKit::EncoderAMD64::WriteLine(std::string& line, + const std::string& file) +{ + if (CompilerKit::find_word(line, "export ")) + return true; + + struct RegMapAMD64 + { + std::string fName; + i64_byte_t fModRM; + }; + + std::vector<RegMapAMD64> REGISTER_LIST{ + {.fName = "ax", .fModRM = 0x0}, + {.fName = "cx", .fModRM = 1}, + {.fName = "dx", .fModRM = 0x2}, + {.fName = "bx", .fModRM = 3}, + {.fName = "sp", .fModRM = 0x4}, + {.fName = "bp", .fModRM = 5}, + {.fName = "si", .fModRM = 0x6}, + {.fName = "di", .fModRM = 7}, + {.fName = "r8", .fModRM = 8}, + {.fName = "r13", .fModRM = 9}, + {.fName = "r9", .fModRM = 10}, + {.fName = "r14", .fModRM = 11}, + {.fName = "r10", .fModRM = 12}, + {.fName = "r15", .fModRM = 13}, + {.fName = "r11", .fModRM = 14}, + }; + + bool foundInstruction = false; + + for (auto& opcodeAMD64 : kOpcodesAMD64) + { + // strict check here + if (CompilerKit::find_word(line, opcodeAMD64.fName) && + detail::algorithm::is_valid(line)) + { + foundInstruction = true; + std::string name(opcodeAMD64.fName); + + /// Move instruction handler. + if (name.find("mov") != std::string::npos) + { + std::string substr = line.substr(line.find(name) + name.size()); + + uint64_t bits = kRegisterBitWidth; + + if (substr.find(",") == std::string::npos) + { + detail::print_error("Syntax error.", "i64asm"); + throw std::runtime_error("syntax_err"); + } + + bool onlyOneReg = true; + + std::vector<RegMapAMD64> currentRegList; + + for (auto& reg : REGISTER_LIST) + { + std::vector<char> regExt = {'e', 'r'}; + + for (auto& ext : regExt) + { + std::string registerName; + + if (bits > 16) + registerName.push_back(ext); + + registerName += reg.fName; + + while (line.find(registerName) != std::string::npos) + { + line.erase(line.find(registerName), registerName.size()); + + if (bits == 16) + { + if (registerName[0] == 'r') + { + detail::print_error( + "invalid size for register, current bit width is: " + + std::to_string(kRegisterBitWidth), + file); + throw std::runtime_error("invalid_reg_size"); + } + } + + currentRegList.push_back( + {.fName = registerName, .fModRM = reg.fModRM}); + } + } + } + + if (currentRegList.size() > 1) + onlyOneReg = false; + + bool hasRBasedRegs = false; + + if (!onlyOneReg) + { + /// very tricky to understand. + /// but this checks for a r8 through r15 register. + if (currentRegList[0].fName[0] == 'r' || + currentRegList[1].fName[0] == 'r') + { + if (isdigit(currentRegList[0].fName[1]) && + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4d); + hasRBasedRegs = true; + } + else if (isdigit(currentRegList[0].fName[1]) || + isdigit(currentRegList[1].fName[1])) + { + kAppBytes.emplace_back(0x4c); + hasRBasedRegs = true; + } + } + } + + if (bits == 64 || bits == 32) + { + if (!hasRBasedRegs && bits >= 32) + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + } + + kAppBytes.emplace_back(0x89); + } + else if (bits == 16) + { + if (hasRBasedRegs) + { + detail::print_error( + "Invalid combination of operands and registers.", "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + kAppBytes.emplace_back(0x66); + kAppBytes.emplace_back(0x89); + } + + if (currentRegList[1].fName[0] == 'r' && + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[0].fName[0] == 'r' && + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (bits == 16) + { + if (currentRegList[0].fName[0] == 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] == 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + else + { + if (currentRegList[0].fName[0] != 'r' || + currentRegList[0].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + + if (currentRegList[1].fName[0] != 'r' || + currentRegList[1].fName[0] == 'e') + { + detail::print_error("Invalid combination of operands and registers.", + "i64asm"); + throw std::runtime_error("comb_op_reg"); + } + } + + /// encode register using the modrm encoding. + + auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | + currentRegList[0].fModRM); + + kAppBytes.emplace_back(modrm); + + break; + } + else if (name == "int" || name == "into" || name == "intd") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + this->WriteNumber8(line.find(name) + name.size() + 1, line); + + break; + } + else if (name == "jmp" || name == "call") + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) + { + throw std::runtime_error("BUG: WriteNumber32"); + } + + break; + } + else + { + kAppBytes.emplace_back(opcodeAMD64.fOpcode); + + break; + } + } + } + + if (line[0] == kAssemblerPragmaSym) + { + if (foundInstruction) + { + detail::print_error("Syntax error: " + line, "i64asm"); + throw std::runtime_error("syntax_err"); + } + + if (line.find("bits 64") != std::string::npos) + { + kRegisterBitWidth = 64U; + } + else if (line.find("bits 32") != std::string::npos) + { + kRegisterBitWidth = 32U; + } + else if (line.find("bits 16") != std::string::npos) + { + kRegisterBitWidth = 16U; + } + else if (line.find("org") != std::string::npos) + { + size_t base[] = {10, 16, 2, 7}; + + for (size_t i = 0; i < 4; i++) + { + if (kOrigin = strtol( + (line.substr(line.find("org") + strlen("org") + 1)).c_str(), + nullptr, base[i]); + kOrigin) + { + if (errno != 0) + { + continue; + } + else + { + if (kVerbose) + { + kStdOut << "i64asm: origin set: " << kOrigin << std::endl; + } + + break; + } + } + } + } + } + /// write a dword + else if (line.find(".dword") != std::string::npos) + { + this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); + } + /// write a long + else if (line.find(".long") != std::string::npos) + { + this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); + } + /// write a 16-bit number + else if (line.find(".word") != std::string::npos) + { + this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); + } + + kOrigin += cAMD64IPAlignment; + + return true; +} + +// Last rev 13-1-24 diff --git a/NDKKit/Sources/link.cxx b/NDKKit/Sources/link.cxx new file mode 100644 index 0000000..0708bd0 --- /dev/null +++ b/NDKKit/Sources/link.cxx @@ -0,0 +1,741 @@ +/* ------------------------------------------- + + Copyright ZKA Technologies + +------------------------------------------- */ + +/// @file link.cxx +/// @author Amlal EL Mahrouss (amlel) +/// @brief ZKA Technologies Linker. + +/// Last Rev: Sat Feb 24 CET 2024 + +/// @note Do not look up for anything with .code64/.data64/.zero64! +/// It will be loaded when program will start up! + +#include <NDKKit/NFC/ErrorID.hpp> + +//! Assembler Kit +#include <NDKKit/AsmKit/AsmKit.hpp> + +//! Preferred Executable Format +#include <NDKKit/NFC/PEF.hpp> +#include <NDKKit/UUID.hpp> +#include <filesystem> +#include <random> +#include <vector> + +//! Dist version +#include <NDKKit/Version.hpp> + +//! Advanced Executable Object Format +#include <NDKKit/NFC/AE.hpp> + +//! C++ I/O headers. +#include <fstream> +#include <iostream> + +#define kLinkerVersion "ZKA Linker Driver %s, (c) ZKA Technologies 2024, all rights reserved.\n" + +#define StringCompare(DST, SRC) strcmp(DST, SRC) + +#define kPefNoCpu 0U +#define kPefNoSubCpu 0U + +#define kWhite "\e[0;97m" +#define kStdOut (std::cout << kWhite) + +#define kLinkerDefaultOrigin kPefBaseOrigin +#define kLinkerId 0x5046FF +#define kLinkerAbiContainer "Container:Abi:" + +enum +{ + eABIStart = 0x1010, /* Invalid ABI start of ABI list. */ + eABINewOS = 0x5046, /* PF (NewOSKrnl) */ + eABIMTL = 0x4650, /* FP (MTL firmware) */ + eABIInvalid = 1, +}; + +static std::string kOutput = ""; +static Int32 kAbi = eABINewOS; +static Int32 kSubArch = kPefNoSubCpu; +static Int32 kArch = CompilerKit::kPefArchInvalid; +static Bool kFatBinaryEnable = false; +static Bool kStartFound = false; +static Bool kDuplicateSymbols = false; +static Bool kVerbose = false; + +/* link is to be found, mld is to be found at runtime. */ +static const char* kLdDefineSymbol = ":UndefinedSymbol:"; +static const char* kLdDynamicSym = ":RuntimeSymbol:"; + +/* object code and list. */ +static std::vector<std::string> kObjectList; +static std::vector<char> kObjectBytes; + +#define kPrintF printf +#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) + +NDK_MODULE(NewOSLinker) +{ + bool is_executable = true; + + /** + * @brief parse flags and such. + * + */ + for (size_t i = 1; i < argc; ++i) + { + if (StringCompare(argv[i], "/help") == 0) + { + kLinkerSplash(); + kStdOut << "/version: Show linker version.\n"; + kStdOut << "/help: Show linker help.\n"; + kStdOut << "/verbose: Enable linker trace.\n"; + kStdOut << "/shared: Output as a shared PEF.\n"; + kStdOut << "/fat-bin: Output as a FAT PEF.\n"; + kStdOut << "/32x0: Output as a 32x0 PEF.\n"; + kStdOut << "/64x0: Output as a 64x0 PEF.\n"; + kStdOut << "/amd64: Output as a AMD64 PEF.\n"; + kStdOut << "/rv64: Output as a RISC-V PEF.\n"; + kStdOut << "/power64: Output as a POWER PEF.\n"; + kStdOut << "/arm64: Output as a ARM64 PEF.\n"; + kStdOut << "/output-file: Select the output file name.\n"; + + return 0; + } + else if (StringCompare(argv[i], "/version") == 0) + { + kLinkerSplash(); + return 0; + } + else if (StringCompare(argv[i], "/fat-bin") == 0) + { + kFatBinaryEnable = true; + + continue; + } + else if (StringCompare(argv[i], "/64x0") == 0) + { + kArch = CompilerKit::kPefArch64000; + + continue; + } + else if (StringCompare(argv[i], "/amd64") == 0) + { + kArch = CompilerKit::kPefArchAMD64; + + continue; + } + else if (StringCompare(argv[i], "/32x0") == 0) + { + kArch = CompilerKit::kPefArch32000; + + continue; + } + else if (StringCompare(argv[i], "/power64") == 0) + { + kArch = CompilerKit::kPefArchPowerPC; + + continue; + } + else if (StringCompare(argv[i], "/arm64") == 0) + { + kArch = CompilerKit::kPefArchARM64; + + continue; + } + else if (StringCompare(argv[i], "/verbose") == 0) + { + kVerbose = true; + + continue; + } + else if (StringCompare(argv[i], "/shared") == 0) + { + if (kOutput.empty()) + { + continue; + } + + if (kOutput.find(kPefExt) != std::string::npos) + kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); + + kOutput += kPefDylibExt; + + is_executable = false; + + continue; + } + else if (StringCompare(argv[i], "/output-file") == 0) + { + kOutput = argv[i + 1]; + ++i; + + continue; + } + else + { + if (argv[i][0] == '/') + { + kStdOut << "link: unknown flag: " << argv[i] << "\n"; + return MPCC_EXEC_ERROR; + } + + kObjectList.emplace_back(argv[i]); + + continue; + } + } + + if (kOutput.empty()) + { + kStdOut << "link: no output filename set." << std::endl; + return MPCC_EXEC_ERROR; + } + + // sanity check. + if (kObjectList.empty()) + { + kStdOut << "link: no input files." << std::endl; + return MPCC_EXEC_ERROR; + } + else + { + namespace fs = std::filesystem; + + // check for existing files, if they don't throw an error. + for (auto& obj : kObjectList) + { + if (!fs::exists(obj)) + { + // if filesystem doesn't find file + // -> throw error. + kStdOut << "link: no such file: " << obj << std::endl; + return MPCC_EXEC_ERROR; + } + } + } + + // PEF expects a valid architecture when outputing a binary. + if (kArch == 0) + { + kStdOut << "link: no target architecture set, can't continue." << std::endl; + return MPCC_EXEC_ERROR; + } + + CompilerKit::PEFContainer pef_container{}; + + int32_t archs = kArch; + + pef_container.Count = 0UL; + pef_container.Kind = CompilerKit::kPefKindExec; + pef_container.SubCpu = kSubArch; + pef_container.Linker = kLinkerId; // ZKA Technologies Linker + pef_container.Abi = kAbi; // Multi-Processor UX ABI + pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; + pef_container.Magic[1] = kPefMagic[1]; + pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; + pef_container.Magic[3] = kPefMagic[3]; + pef_container.Version = kPefVersion; + + // specify the start address, can be 0x10000 + pef_container.Start = kLinkerDefaultOrigin; + pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); + + std::ofstream outputFc(kOutput, std::ofstream::binary); + + if (outputFc.bad()) + { + if (kVerbose) + { + kStdOut << "link: error: " << strerror(errno) << "\n"; + } + + return MPCC_FILE_NOT_FOUND; + } + + //! Read AE to convert as PEF. + + std::vector<CompilerKit::PEFCommandHeader> commandHdrsList; + CompilerKit::Utils::AEReadableProtocol readProto{}; + + for (const auto& i : kObjectList) + { + if (!std::filesystem::exists(i)) + continue; + + CompilerKit::AEHeader hdr{}; + + readProto.FP = std::ifstream(i, std::ifstream::binary); + readProto.FP >> hdr; + + auto ae_header = hdr; + + if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && + ae_header.fSize == sizeof(CompilerKit::AEHeader)) + { + if (ae_header.fArch != kArch) + { + if (kVerbose) + kStdOut << "link: info: is this a FAT binary? : "; + + if (!kFatBinaryEnable) + { + if (kVerbose) + kStdOut << "No.\n"; + + kStdOut << "link: error: object " << i + << " is a different kind of architecture and output isn't " + "treated as a FAT binary." + << std::endl; + + std::remove(kOutput.c_str()); + return MPCC_FAT_ERROR; + } + else + { + if (kVerbose) + { + kStdOut << "Yes.\n"; + } + } + } + + // append arch type to archs varaible. + archs |= ae_header.fArch; + std::size_t cnt = ae_header.fCount; + + if (kVerbose) + kStdOut << "link: object header found, record count: " << cnt << "\n"; + + pef_container.Count = cnt; + + char_type* raw_ae_records = + new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; + memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); + + auto* ae_records = readProto.Read(raw_ae_records, cnt); + for (size_t ae_record_index = 0; ae_record_index < cnt; + ++ae_record_index) + { + CompilerKit::PEFCommandHeader command_header{0}; + size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; + + memcpy(command_header.Name, ae_records[ae_record_index].fName, + kPefNameLen); + + // check this header if it's any valid. + if (std::string(command_header.Name).find(".code64") == + std::string::npos && + std::string(command_header.Name).find(".data64") == + std::string::npos && + std::string(command_header.Name).find(".zero64") == + std::string::npos) + { + if (std::string(command_header.Name).find(kPefStart) == + std::string::npos && + *command_header.Name == 0) + { + if (std::string(command_header.Name).find(kLdDefineSymbol) != + std::string::npos) + { + goto ld_mark_header; + } + else + { + continue; + } + } + } + + if (std::string(command_header.Name).find(kPefStart) != + std::string::npos && + std::string(command_header.Name).find(".code64") != + std::string::npos) + { + kStartFound = true; + } + + ld_mark_header: + command_header.Offset = offsetOfData; + command_header.Kind = ae_records[ae_record_index].fKind; + command_header.Size = ae_records[ae_record_index].fSize; + command_header.Cpu = ae_header.fArch; + command_header.SubCpu = ae_header.fSubArch; + + if (kVerbose) + { + kStdOut << "link: object record: " + << ae_records[ae_record_index].fName << " was marked.\n"; + + kStdOut << "link: object record offset: " << command_header.Offset << "\n"; + } + + commandHdrsList.emplace_back(command_header); + } + + delete[] raw_ae_records; + + std::vector<char> bytes; + bytes.resize(ae_header.fCodeSize); + + readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); + readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); + + for (auto& byte : bytes) + { + kObjectBytes.push_back(byte); + } + + readProto.FP.close(); + + continue; + } + + kStdOut << "link: not an object: " << i << std::endl; + std::remove(kOutput.c_str()); + + // don't continue, it is a fatal error. + return MPCC_EXEC_ERROR; + } + + pef_container.Cpu = archs; + + outputFc << pef_container; + + if (kVerbose) + { + kStdOut << "link: wrote container header.\n"; + } + + outputFc.seekp(std::streamsize(pef_container.HdrSz)); + + std::vector<std::string> not_found; + std::vector<std::string> symbols; + + // step 2: check for errors (multiple symbols, undefined ones) + + for (auto& commandHdr : commandHdrsList) + { + // check if this symbol needs to be resolved. + if (std::string(commandHdr.Name).find(kLdDefineSymbol) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; + + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it == not_found.end()) + { + not_found.emplace_back(commandHdr.Name); + } + } + + symbols.emplace_back(commandHdr.Name); + } + + // Now try to solve these symbols. + + for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); + ++not_found_idx) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdrsList[not_found_idx].Name)); + it != not_found.end()) + { + std::string symbol_imp = *it; + + if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) + continue; + + // erase the lookup prefix. + symbol_imp.erase( + 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); + + // demangle everything. + while (symbol_imp.find('$') != std::string::npos) + symbol_imp.erase(symbol_imp.find('$'), 1); + + // the reason we do is because, this may not match the symbol, and we need + // to look for other matching symbols. + for (auto& commandHdr : commandHdrsList) + { + if (std::string(commandHdr.Name).find(symbol_imp) != + std::string::npos && + std::string(commandHdr.Name).find(kLdDefineSymbol) == + std::string::npos) + { + std::string undefined_symbol = commandHdr.Name; + auto result_of_sym = + undefined_symbol.substr(undefined_symbol.find(symbol_imp)); + + for (int i = 0; result_of_sym[i] != 0; ++i) + { + if (result_of_sym[i] != symbol_imp[i]) + goto ld_continue_search; + } + + not_found.erase(it); + + if (kVerbose) + kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; + + break; + } + } + + ld_continue_search: + continue; + } + } + + // step 3: check for errors (recheck if we have those symbols.) + + if (!kStartFound && is_executable) + { + if (kVerbose) + kStdOut + << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " + "against your compiler's runtime library.\n"; + + kStdOut << "link: undefined entrypoint " << kPefStart + << " for executable: " << kOutput << "\n"; + } + + // step 4: write all PEF commands. + + CompilerKit::PEFCommandHeader dateHeader{}; + + time_t timestamp = time(nullptr); + + std::string timeStampStr = "Container:BuildEpoch:"; + timeStampStr += std::to_string(timestamp); + + strcpy(dateHeader.Name, timeStampStr.c_str()); + + dateHeader.Flags = 0; + dateHeader.Kind = CompilerKit::kPefZero; + dateHeader.Offset = outputFc.tellp(); + dateHeader.Size = timeStampStr.size(); + + commandHdrsList.push_back(dateHeader); + + CompilerKit::PEFCommandHeader abiHeader{}; + + std::string abi = kLinkerAbiContainer; + + switch (kArch) + { + case CompilerKit::kPefArchAMD64: { + abi += "MSFT"; + break; + } + case CompilerKit::kPefArchPowerPC: { + abi += "SYSV"; + break; + } + case CompilerKit::kPefArch32000: + case CompilerKit::kPefArch64000: { + abi += "MHRA"; + break; + } + default: { + abi += " IDK"; + break; + } + } + + memcpy(abiHeader.Name, abi.c_str(), abi.size()); + + abiHeader.Size = abi.size(); + abiHeader.Offset = outputFc.tellp(); + abiHeader.Flags = 0; + abiHeader.Kind = CompilerKit::kPefLinkerID; + + commandHdrsList.push_back(abiHeader); + + CompilerKit::PEFCommandHeader uuidHeader{}; + + std::random_device rd; + + auto seedData = std::array<int, std::mt19937::state_size>{}; + std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); + std::seed_seq seq(std::begin(seedData), std::end(seedData)); + std::mt19937 generator(seq); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid id = gen(); + auto uuidStr = uuids::to_string(id); + + memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); + memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), + uuidStr.size()); + + uuidHeader.Size = 16; + uuidHeader.Offset = outputFc.tellp(); + uuidHeader.Flags = 0; + uuidHeader.Kind = CompilerKit::kPefZero; + + commandHdrsList.push_back(uuidHeader); + + // prepare a symbol vector. + std::vector<std::string> undefSymbols; + std::vector<std::string> duplSymbols; + std::vector<std::string> resolveSymbols; + + constexpr Int32 cPaddingOffset = 16; + + size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; + + // Finally write down the command headers. + // And check for any duplications + for (size_t commandHeaderIndex = 0UL; + commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) + { + if (std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[commandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + std::string symbolName = commandHdrsList[commandHeaderIndex].Name; + + if (!symbolName.empty()) + { + undefSymbols.emplace_back(symbolName); + } + + commandHdrsList[commandHeaderIndex].Offset += previousOffset; + previousOffset += commandHdrsList[commandHeaderIndex].Size; + + std::string name = commandHdrsList[commandHeaderIndex].Name; + + /// so this is valid when we get to the entrypoint. + /// it is always a code64 container. And should equal to kPefStart as well. + /// this chunk of code updates the pef_container.Start with the updated offset. + if (name.find(kPefStart) != std::string::npos && + name.find(".code64") != std::string::npos) + { + pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; + auto tellCurPos = outputFc.tellp(); + + outputFc.seekp(0); + outputFc << pef_container; + + outputFc.seekp(tellCurPos); + } + + if (kVerbose) + { + kStdOut << "link: command header name: " << name << "\n"; + kStdOut << "link: real address of command header content: " << commandHdrsList[commandHeaderIndex].Offset << "\n"; + } + + outputFc << commandHdrsList[commandHeaderIndex]; + + for (size_t subCommandHeaderIndex = 0UL; + subCommandHeaderIndex < commandHdrsList.size(); + ++subCommandHeaderIndex) + { + if (subCommandHeaderIndex == commandHeaderIndex) + continue; + + if (std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDefineSymbol) != std::string::npos && + std::string(commandHdrsList[subCommandHeaderIndex].Name) + .find(kLdDynamicSym) == std::string::npos) + { + if (kVerbose) + { + kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; + } + + // ignore :UndefinedSymbol: headers, they do not contain code. + continue; + } + + auto& commandHdr = commandHdrsList[subCommandHeaderIndex]; + + if (commandHdr.Name == + std::string(commandHdrsList[commandHeaderIndex].Name)) + { + if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), + commandHdr.Name) == duplSymbols.cend()) + { + duplSymbols.emplace_back(commandHdr.Name); + } + + if (kVerbose) + kStdOut << "link: found duplicate symbol: " << commandHdr.Name + << "\n"; + + kDuplicateSymbols = true; + } + } + } + + if (!duplSymbols.empty()) + { + for (auto& symbol : duplSymbols) + { + kStdOut << "link: multiple symbols of " << symbol << ".\n"; + } + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + // step 2.5: write program bytes. + + for (auto byte : kObjectBytes) + { + outputFc << byte; + } + + if (kVerbose) + kStdOut << "link: wrote contents of: " << kOutput << "\n"; + + // step 3: check if we have those symbols + + std::vector<std::string> unrefSyms; + + for (auto& commandHdr : commandHdrsList) + { + if (auto it = std::find(not_found.begin(), not_found.end(), + std::string(commandHdr.Name)); + it != not_found.end()) + { + unrefSyms.emplace_back(commandHdr.Name); + } + } + + if (!unrefSyms.empty()) + { + for (auto& unreferenced_symbol : unrefSyms) + { + kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; + } + } + + if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || + !unrefSyms.empty()) + { + if (kVerbose) + kStdOut << "link: file: " << kOutput + << ", is corrupt, removing file...\n"; + + std::remove(kOutput.c_str()); + return MPCC_EXEC_ERROR; + } + + return 0; +} + +// Last rev 13-1-24 diff --git a/Sources/ppcasm.cc b/NDKKit/Sources/power-as.cxx index fcf0a5d..8a6b7ef 100644 --- a/Sources/ppcasm.cc +++ b/NDKKit/Sources/power-as.cxx @@ -1,13 +1,13 @@ /* ------------------------------------------- - Copyright Mahrouss Logic + Copyright ZKA Technologies ------------------------------------------- */ ///////////////////////////////////////////////////////////////////////////////////////// -/// @file ppcasm.cxx -/// @author Amlal El Mahrouss +/// @file power-as.cxx +/// @author Amlal EL Mahrouss /// @brief POWER Assembler. /// REMINDER: when dealing with an undefined symbol use (string @@ -17,16 +17,16 @@ #define __ASM_NEED_PPC__ 1 -#include <Headers/AsmKit/CPU/ppc.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> -#include <Headers/Version.hxx> -#include <algorithm> +#include <NDKKit/NFC/ErrorID.hpp> +#include <NDKKit/AsmKit/CPU/ppc.hpp> +#include <NDKKit/NFC/PEF.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/NFC/AE.hpp> +#include <NDKKit/Version.hpp> #include <filesystem> -#include <fstream> +#include <algorithm> #include <iostream> -#include <memory> +#include <fstream> #include <vector> ///////////////////// @@ -43,11 +43,11 @@ #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) +constexpr auto cPowerIPAlignment = 0x4U; + static CharType kOutputArch = CompilerKit::kPefArchPowerPC; static Boolean kOutputAsBinary = false; -constexpr auto cPowerIPAlignment = 0x4U; - static UInt32 kErrorLimit = 10; static UInt32 kAcceptableErrors = 0; @@ -76,11 +76,11 @@ namespace detail { void print_error(std::string reason, const std::string &file) noexcept { if (reason[0] == '\n') reason.erase(0, 1); - kStdErr << kRed << "[ ppcasm ] " << kWhite - << ((file == "ppcasm") ? "internal assembler error " + kStdErr << kRed << "[ power-as ] " << kWhite + << ((file == "power-as") ? "internal assembler error " : ("in file, " + file)) << kBlank << std::endl; - kStdErr << kRed << "[ ppcasm ] " << kWhite << reason << kBlank << std::endl; + kStdErr << kRed << "[ power-as ] " << kWhite << reason << kBlank << std::endl; if (kAcceptableErrors > kErrorLimit) std::exit(3); @@ -94,13 +94,13 @@ void print_warning(std::string reason, const std::string &file) noexcept { kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; } - kStdOut << kYellow << "[ ppcasm ] " << kWhite << reason << kBlank + kStdOut << kYellow << "[ power-as ] " << kWhite << reason << kBlank << std::endl; } } // namespace detail /// Do not move it on top! it uses the assembler detail namespace! -#include <asmutils.h> +#include <asmutils.hxx> ///////////////////////////////////////////////////////////////////////////////////////// @@ -108,37 +108,36 @@ void print_warning(std::string reason, const std::string &file) noexcept { ///////////////////////////////////////////////////////////////////////////////////////// -MPCC_MODULE(NewOSAssemblerPowerPC) { +NDK_MODULE(NewOSAssemblerPowerPC) { for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "ppcasm: POWER Assembler.\nppcasm: " << kDistVersion << "\nppcasm: " + if (argv[i][0] == '/') { + if (strcmp(argv[i], "/version") == 0 || strcmp(argv[i], "/v") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: " << kDistVersion << "\npower-as: " "Copyright (c) " - "2024 Mahrouss Logic.\n"; + "ZKA Technologies.\n"; return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "ppcasm: POWER Assembler.\nppcasm: 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"; + } else if (strcmp(argv[i], "/h") == 0) { + kStdOut << "power-as: POWER64 Assembler Driver.\npower-as: Copyright (c) 2024 " + "ZKA Technologies.\n"; + kStdOut << "/version,/v: print program version.\n"; + kStdOut << "/verbose: print verbose output.\n"; + kStdOut << "/binary: output as flat binary.\n"; return 0; - } else if (strcmp(argv[i], "-binary") == 0) { + } else if (strcmp(argv[i], "/binary") == 0) { kOutputAsBinary = true; continue; - } else if (strcmp(argv[i], "-verbose") == 0) { + } else if (strcmp(argv[i], "/verbose") == 0) { kVerbose = true; continue; } - kStdOut << "ppcasm: ignore " << argv[i] << "\n"; + kStdOut << "power-as: ignore " << argv[i] << "\n"; continue; } if (!std::filesystem::exists(argv[i])) { - kStdOut << "ppcasm: can't open: " << argv[i] << std::endl; + kStdOut << "power-as: can't open: " << argv[i] << std::endl; goto asm_fail_exit; } @@ -157,7 +156,7 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (file_ptr_out.bad()) { if (kVerbose) { - kStdOut << "ppcasm: error: " << strerror(errno) << "\n"; + kStdOut << "power-as: error: " << strerror(errno) << "\n"; } } @@ -192,7 +191,7 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { } catch (const std::exception &e) { if (kVerbose) { std::string what = e.what(); - detail::print_warning("exit because of: " + what, "ppcasm"); + detail::print_warning("exit because of: " + what, "power-as"); } std::filesystem::remove(object_output); @@ -202,7 +201,7 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { if (!kOutputAsBinary) { if (kVerbose) { - kStdOut << "ppcasm: Writing object file...\n"; + kStdOut << "power-as: Writing object file...\n"; } // this is the final step, write everything to the file. @@ -214,8 +213,8 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { file_ptr_out << hdr; if (kRecords.empty()) { - kStdErr << "ppcasm: At least one record is needed to write an object " - "file.\nppcasm: Make one using `export .code64 foo_bar`.\n"; + kStdErr << "power-as: At least one record is needed to write an object " + "file.\npower-as: Make one using `export .code64 foo_bar`.\n"; std::filesystem::remove(object_output); return -1; @@ -225,36 +224,36 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { std::size_t record_count = 0UL; - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "ppcasm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; + for (auto &record_hdr : kRecords) { + record_hdr.fFlags |= CompilerKit::kKindRelocationAtRuntime; + record_hdr.fOffset = record_count; ++record_count; - file_ptr_out << rec; + file_ptr_out << record_hdr; + + if (kVerbose) + kStdOut << "power-as: Wrote record " << record_hdr.fName << "...\n"; } // increment once again, so that we won't lie about the kUndefinedSymbols. ++record_count; for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; + CompilerKit::AERecordHeader undefined_sym{0}; if (kVerbose) - kStdOut << "ppcasm: Wrote symbol " << sym << " to file...\n"; + kStdOut << "power-as: Wrote symbol " << sym << " to file...\n"; - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; + undefined_sym.fKind = kAEInvalidOpcode; + undefined_sym.fSize = sym.size(); + undefined_sym.fOffset = record_count; ++record_count; - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); + memset(undefined_sym.fPad, kAEInvalidOpcode, kAEPad); + memcpy(undefined_sym.fName, sym.c_str(), sym.size()); - file_ptr_out << _record_hdr; + file_ptr_out << undefined_sym; ++kCounter; } @@ -271,7 +270,7 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { file_ptr_out.seekp(pos_end); } else { if (kVerbose) { - kStdOut << "ppcasm: Write raw binary...\n"; + kStdOut << "power-as: Write raw binary...\n"; } } @@ -280,21 +279,21 @@ MPCC_MODULE(NewOSAssemblerPowerPC) { file_ptr_out.write(reinterpret_cast<const char *>(&byte), sizeof(byte)); } - if (kVerbose) kStdOut << "ppcasm: Wrote file with program in it.\n"; + if (kVerbose) kStdOut << "power-as: Wrote file with program in it.\n"; file_ptr_out.flush(); file_ptr_out.close(); - if (kVerbose) kStdOut << "ppcasm: Exit succeeded.\n"; + if (kVerbose) kStdOut << "power-as: Exit succeeded.\n"; return 0; } asm_fail_exit: - if (kVerbose) kStdOut << "ppcasm: Exit failed.\n"; + if (kVerbose) kStdOut << "power-as: Exit failed.\n"; - return -1; + return MPCC_EXEC_ERROR; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -307,17 +306,17 @@ asm_fail_exit: static bool asm_read_attributes(std::string &line) { // import is the opposite of export, it signals to the li // that we need this symbol. - if (ParserKit::find_word(line, "import")) { + if (CompilerKit::find_word(line, "import")) { if (kOutputAsBinary) { detail::print_error("Invalid import directive in flat binary mode.", - "ppcasm"); + "power-as"); throw std::runtime_error("invalid_import_bin"); } auto name = line.substr(line.find("import") + strlen("import") + 1); if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); + detail::print_error("Invalid import", "power-as"); throw std::runtime_error("invalid_import"); } @@ -364,13 +363,13 @@ static bool asm_read_attributes(std::string &line) { return true; } - // export is a special keyword used by ppcasm to tell the AE output stage to + // export is a special keyword used by power-as to tell the AE output stage to // mark this section as a header. it currently supports .code64, .data64., // .zero64 - else if (ParserKit::find_word(line, "export")) { + else if (CompilerKit::find_word(line, "export")) { if (kOutputAsBinary) { detail::print_error("Invalid export directive in flat binary mode.", - "ppcasm"); + "power-as"); throw std::runtime_error("invalid_export_bin"); } @@ -457,9 +456,9 @@ std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, const std::string &file) { std::string err_str; - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - line.find('#') != std::string::npos || ParserKit::find_word(line, ";")) { + if (line.empty() || CompilerKit::find_word(line, "import") || + CompilerKit::find_word(line, "export") || + line.find('#') != std::string::npos || CompilerKit::find_word(line, ";")) { if (line.find('#') != std::string::npos) { line.erase(line.find('#')); } else if (line.find(';') != std::string::npos) { @@ -525,7 +524,7 @@ std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, std::vector<std::string> filter_inst = {"blr", "bl", "sc"}; for (auto &opcodePPC : kOpcodesPowerPC) { - if (ParserKit::find_word(line, opcodePPC.name)) { + if (CompilerKit::find_word(line, opcodePPC.name)) { for (auto &op : operands_inst) { // if only the instruction was found. if (line == op) { @@ -540,7 +539,7 @@ std::string CompilerKit::EncoderPowerPC::CheckLine(std::string &line, if (auto it = std::find(filter_inst.begin(), filter_inst.end(), opcodePPC.name); it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcodePPC.name)) { + if (CompilerKit::find_word(line, opcodePPC.name)) { if (!isspace( line[line.find(opcodePPC.name) + strlen(opcodePPC.name)])) { err_str += "\nMissing space between "; @@ -569,7 +568,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, 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, "ppcasm"); + detail::print_error("invalid hex number: " + jump_label, "power-as"); throw std::runtime_error("invalid_hex"); } } @@ -582,7 +581,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, } if (kVerbose) { - kStdOut << "ppcasm: found a base 16 number here: " + kStdOut << "power-as: found a base 16 number here: " << jump_label.substr(pos) << "\n"; } @@ -592,7 +591,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, 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, "ppcasm"); + detail::print_error("invalid binary number: " + jump_label, "power-as"); throw std::runtime_error("invalid_bin"); } } @@ -601,7 +600,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); if (kVerbose) { - kStdOut << "ppcasm: found a base 2 number here: " + kStdOut << "power-as: found a base 2 number here: " << jump_label.substr(pos) << "\n"; } @@ -615,7 +614,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, 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, "ppcasm"); + detail::print_error("invalid octal number: " + jump_label, "power-as"); throw std::runtime_error("invalid_octal"); } } @@ -624,7 +623,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); if (kVerbose) { - kStdOut << "ppcasm: found a base 8 number here: " + kStdOut << "power-as: found a base 8 number here: " << jump_label.substr(pos) << "\n"; } @@ -654,7 +653,7 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, } if (kVerbose) { - kStdOut << "ppcasm: found a base 10 number here: " << jump_label.substr(pos) + kStdOut << "power-as: found a base 10 number here: " << jump_label.substr(pos) << "\n"; } @@ -669,12 +668,12 @@ bool CompilerKit::EncoderPowerPC::WriteNumber(const std::size_t &pos, bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, const std::string &file) { - if (ParserKit::find_word(line, "export")) return true; + if (CompilerKit::find_word(line, "export")) return true; if (!detail::algorithm::is_valid(line)) return true; for (auto &opcodePPC : kOpcodesPowerPC) { // strict check here - if (ParserKit::find_word(line, opcodePPC.name)) { + if (CompilerKit::find_word(line, opcodePPC.name)) { std::string name(opcodePPC.name); std::string jump_label, cpy_jump_label; std::vector<size_t> found_registers_index; @@ -878,9 +877,9 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, } if (kVerbose) { - kStdOut << "ppcasm: Found register: " << register_syntax + kStdOut << "power-as: Found register: " << register_syntax << "\n"; - kStdOut << "ppcasm: Amount of registers in instruction: " + kStdOut << "power-as: Amount of registers in instruction: " << found_some_count << "\n"; } @@ -946,7 +945,7 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, // remember! register to register! if (found_some_count == 1) { detail::print_error( - "Unrecognized register found.\ntip: each ppcasm register " + "Unrecognized register found.\ntip: each power-as register " "starts with 'r'.\nline: " + line, file); diff --git a/NDKKit/Sources/power-cc.cxx b/NDKKit/Sources/power-cc.cxx new file mode 100644 index 0000000..4c07a04 --- /dev/null +++ b/NDKKit/Sources/power-cc.cxx @@ -0,0 +1,1645 @@ +/* + * ======================================================== + * + * cc + * Copyright ZKA Technologies, all rights reserved. + * + * ======================================================== + */ + +#include <NDKKit/AsmKit/CPU/ppc.hpp> +#include <NDKKit/Parser.hpp> +#include <NDKKit/UUID.hpp> +#include <filesystem> +#include <fstream> +#include <iostream> +#include <memory> +#include <random> +#include <string> +#include <utility> +#include <vector> +#include <cstdio> + +#define kOk 0 + +/// @author Amlal El Mahrouss (amlel) +/// @file cc.cxx +/// @brief POWER C Compiler. + +///////////////////// + +/// ANSI ESCAPE CODES + +///////////////////// + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +///////////////////////////////////// + +/// INTERNAL STRUCT OF THE C COMPILER + +///////////////////////////////////// + +namespace detail +{ + // \brief name to register struct. + struct CompilerRegisterMap final + { + std::string fName; + std::string fReg; + }; + + // \brief Map for C structs + // \author amlel + struct CompilerStructMap final + { + /// 'struct::my_foo' + std::string fName; + + /// if instance: stores a valid register. + std::string fReg; + + /// offset count + std::size_t fOffsetsCnt; + + /// offset array. + std::vector<std::pair<Int32, std::string>> fOffsets; + }; + + struct CompilerState final + { + std::vector<CompilerKit::SyntaxLeafList> fSyntaxTreeList; + std::vector<CompilerRegisterMap> kStackFrame; + std::vector<CompilerStructMap> kStructMap; + CompilerKit::SyntaxLeafList* fSyntaxTree{nullptr}; + std::unique_ptr<std::ofstream> fOutputAssembly; + std::string fLastFile; + std::string fLastError; + bool fVerbose; + }; +} // namespace detail + +static detail::CompilerState kState; +static SizeType kErrorLimit = 100; +static std::string kIfFunction = ""; +static Int32 kAcceptableErrors = 0; + +namespace detail +{ + /// @brief prints an error into stdout. + /// @param reason the reason of the error. + /// @param file where does it originate from? + void print_error(std::string reason, std::string file) noexcept + { + if (reason[0] == '\n') + reason.erase(0, 1); + + if (file.find(".pp") != std::string::npos) + file.erase(file.find(".pp"), 3); + + if (kState.fLastFile != file) + { + std::cout << kRed << "[ cc ] " << kWhite + << ((file == "cc") ? "internal compiler error " + : ("in file, " + file)) + << kBlank << std::endl; + std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; + + kState.fLastFile = file; + } + else + { + std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite + << reason << kBlank << std::endl; + } + + if (kAcceptableErrors > kErrorLimit) + std::exit(3); + + ++kAcceptableErrors; + } + + struct CompilerType final + { + std::string fName; + std::string fValue; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// Target architecture. +static int kMachine = 0; + +///////////////////////////////////////// + +// REGISTERS ACCORDING TO USED ASSEMBLER + +///////////////////////////////////////// + +static size_t kRegisterCnt = kAsmRegisterLimit; +static size_t kStartUsable = 2; +static size_t kUsableLimit = 15; +static size_t kRegisterCounter = kStartUsable; +static std::string kRegisterPrefix = kAsmRegisterPrefix; + +///////////////////////////////////////// + +// COMPILER PARSING UTILITIES/STATES. + +///////////////////////////////////////// + +static std::vector<std::string> kFileList; +static CompilerKit::AssemblyFactory kFactory; +static bool kInStruct = false; +static bool kOnWhileLoop = false; +static bool kOnForLoop = false; +static bool kInBraces = false; +static bool kIfFound = false; +static size_t kBracesCount = 0UL; + +/* @brief C compiler backend for C */ +class CompilerBackendCLang final : public CompilerKit::CompilerBackend +{ +public: + explicit CompilerBackendCLang() = default; + ~CompilerBackendCLang() override = default; + + MPCC_COPY_DEFAULT(CompilerBackendCLang); + + std::string Check(const char* text, const char* file); + bool Compile(const std::string& text, const char* file) override; + + const char* Language() override + { + return "POWER C"; + } +}; + +static CompilerBackendCLang* kCompilerBackend = nullptr; +static std::vector<detail::CompilerType> kCompilerVariables; +static std::vector<std::string> kCompilerFunctions; +static std::vector<detail::CompilerType> kCompilerTypes; + +namespace detail +{ + union number_cast final { + public: + number_cast(UInt64 _Raw) + : _Raw(_Raw) + { + } + + public: + char _Num[8]; + UInt64 _Raw; + }; + + union double_cast final { + public: + double_cast(float _Raw) + : _Raw(_Raw) + { + } + + public: + char _Sign; + char _Lh[8]; + char _Rh[23]; + + float _Raw; + }; +} // namespace detail + +///////////////////////////////////////////////////////////////////////////////////////// + +// @name Compile +// @brief Generate MASM from a C assignement. + +///////////////////////////////////////////////////////////////////////////////////////// + +bool CompilerBackendCLang::Compile(const std::string& text, const char* file) +{ + std::string textBuffer = text; + + bool typeFound = false; + bool fnFound = false; + + // setup generator. + std::random_device rd; + + auto seed_data = std::array<int, std::mt19937::state_size>{}; + std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); + std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); + std::mt19937 generator(seq); + + // start parsing + for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) + { + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + + auto gen = uuids::uuid_random_generator{generator}; + uuids::uuid out = gen(); + + detail::number_cast time_off = (UInt64)out.as_bytes().data(); + + if (!typeFound) + { + auto substr = textBuffer.substr(text_index); + std::string match_type; + + for (size_t y = 0; y < substr.size(); ++y) + { + if (substr[y] == ' ') + { + while (match_type.find(' ') != std::string::npos) + { + match_type.erase(match_type.find(' ')); + } + + for (auto& clType : kCompilerTypes) + { + if (clType.fName == match_type) + { + match_type.clear(); + + std::string buf; + + buf += clType.fValue; + buf += ' '; + + if (substr.find('=') != std::string::npos) + { + break; + } + + if (textBuffer.find('(') != std::string::npos) + { + syntaxLeaf.fUserValue = buf; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + typeFound = true; + break; + } + } + + break; + } + + match_type += substr[y]; + } + } + + if (textBuffer[text_index] == '{') + { + if (kInStruct) + { + continue; + } + + kInBraces = true; + ++kBracesCount; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // return keyword handler + if (textBuffer[text_index] == 'r') + { + std::string return_keyword; + return_keyword += "return"; + + std::size_t index = 0UL; + + std::string value; + + for (size_t return_index = text_index; return_index < textBuffer.size(); + ++return_index) + { + if (textBuffer[return_index] != return_keyword[index]) + { + for (size_t value_index = return_index; + value_index < textBuffer.size(); ++value_index) + { + if (textBuffer[value_index] == ';') + break; + + value += textBuffer[value_index]; + } + + break; + } + + ++index; + } + + if (index == return_keyword.size()) + { + if (!value.empty()) + { + if (value.find('(') != std::string::npos) + { + value.erase(value.find('(')); + } + + if (!isdigit(value[value.find('(') + 2])) + { + std::string tmp = value; + bool reg_to_reg = false; + + value.clear(); + + value += " import"; + value += tmp; + } + + syntaxLeaf.fUserValue = "\tmr r31, "; + + // make it pretty. + while (value.find('\t') != std::string::npos) + value.erase(value.find('\t'), 1); + + while (value.find(' ') != std::string::npos) + value.erase(value.find(' '), 1); + + while (value.find("import") != std::string::npos) + value.erase(value.find("import"), strlen("import")); + + bool found = false; + + for (auto& reg : kState.kStackFrame) + { + if (value.find(reg.fName) != std::string::npos) + { + found = true; + syntaxLeaf.fUserValue += reg.fReg; + break; + } + } + + if (!found) + syntaxLeaf.fUserValue += "r0"; + } + + syntaxLeaf.fUserValue += "\n\tblr"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + break; + } + } + + if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') + { + auto expr = textBuffer.substr(text_index + 2); + textBuffer.erase(text_index, 2); + + if (expr.find("{") != std::string::npos) + { + expr.erase(expr.find("{")); + } + + if (expr.find("(") != std::string::npos) + expr.erase(expr.find("(")); + + if (expr.find(")") != std::string::npos) + expr.erase(expr.find(")")); + + kIfFunction = "__MPCC_IF_PROC_"; + kIfFunction += std::to_string(time_off._Raw); + + syntaxLeaf.fUserValue = + "\tcmpw " + "r10, r11"; + + syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + + " \ndword export .code64 " + kIfFunction + "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + kIfFound = true; + } + + // Parse expressions and instructions here. + // what does this mean? + // we encounter an assignment, or we reached the end of an expression. + if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') + { + if (fnFound) + continue; + if (kIfFound) + continue; + + if (textBuffer[text_index] == ';' && kInStruct) + continue; + + if (textBuffer.find("typedef ") != std::string::npos) + continue; + + if (textBuffer[text_index] == '=' && kInStruct) + { + detail::print_error( + "assignement of value inside a struct " + textBuffer, file); + continue; + } + + if (textBuffer[text_index] == ';' && kInStruct) + { + bool space_found_ = false; + std::string sym; + + for (auto& ch : textBuffer) + { + if (ch == ' ') + { + space_found_ = true; + } + + if (ch == ';') + break; + + if (space_found_) + sym.push_back(ch); + } + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( + std::make_pair( + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, + sym)); + + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = + kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; + + continue; + } + + if (textBuffer[text_index] == '=' && kInStruct) + { + continue; + } + + if (textBuffer[text_index + 1] == '=' || + textBuffer[text_index - 1] == '!' || + textBuffer[text_index - 1] == '<' || + textBuffer[text_index - 1] == '>') + { + continue; + } + + std::string substr; + + if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) + { + if (textBuffer.find("*") != std::string::npos) + { + if (textBuffer.find("=") > textBuffer.find("*")) + substr += "\tli "; + else + substr += "\tli "; + } + else + { + substr += "\tli "; + } + } + else if (textBuffer.find('=') != std::string::npos && !kInBraces) + { + substr += "stw export .data64 "; + } + + int first_encountered = 0; + + std::string str_name; + + for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); + ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + { + ++text_index_2; + + // want to add this, so that the parser recognizes that this is a + // string. + substr += '"'; + + for (; text_index_2 < textBuffer.size(); ++text_index_2) + { + if (textBuffer[text_index_2] == '\"') + break; + + substr += textBuffer[text_index_2]; + } + } + + if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') + continue; + + if (textBuffer[text_index_2] == ';') + { + break; + } + + if (textBuffer[text_index_2] == ' ' || + textBuffer[text_index_2] == '\t') + { + if (first_encountered != 2) + { + if (textBuffer[text_index] != '=' && + substr.find("export .data64") == std::string::npos && + !kInStruct) + substr += "export .data64 "; + } + + ++first_encountered; + + continue; + } + + if (textBuffer[text_index_2] == '=') + { + if (!kInBraces) + { + substr.replace(substr.find("export .data64"), + strlen("export .data64"), "export .zero64 "); + } + + substr += ","; + continue; + } + + substr += textBuffer[text_index_2]; + } + + for (auto& clType : kCompilerTypes) + { + if (substr.find(clType.fName) != std::string::npos) + { + if (substr.find(clType.fName) > substr.find('"')) + continue; + + substr.erase(substr.find(clType.fName), clType.fName.size()); + } + else if (substr.find(clType.fValue) != std::string::npos) + { + if (substr.find(clType.fValue) > substr.find('"')) + continue; + + if (clType.fName == "const") + continue; + + substr.erase(substr.find(clType.fValue), clType.fValue.size()); + } + } + + if (substr.find("extern") != std::string::npos) + { + substr.replace(substr.find("extern"), strlen("extern"), "import "); + + if (substr.find("export .data64") != std::string::npos) + substr.erase(substr.find("export .data64"), strlen("export .data64")); + } + + auto var_to_find = + std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), + [&](detail::CompilerType type) { + return type.fName.find(substr) != std::string::npos; + }); + + kCompilerVariables.push_back({.fName = substr}); + + if (textBuffer[text_index] == ';') + break; + + std::string reg = kAsmRegisterPrefix; + + ++kRegisterCounter; + reg += std::to_string(kRegisterCounter); + + auto newSubstr = substr.substr(substr.find(" ")); + + std::string symbol; + + for (size_t start = 0; start < newSubstr.size(); ++start) + { + if (newSubstr[start] == ',') + break; + + if (newSubstr[start] == ' ') + continue; + + symbol += (newSubstr[start]); + } + + kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); + + syntaxLeaf.fUserValue += + "\n\tli " + reg + substr.substr(substr.find(',')); + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + // function handler. + + if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) + { + std::string substr; + std::string args_buffer; + std::string args; + + bool type_crossed = false; + + for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); + ++idx) + { + if (textBuffer[idx] == ',') + continue; + + if (textBuffer[idx] == ' ') + continue; + + if (textBuffer[idx] == ')') + break; + } + + for (char substr_first_index : textBuffer) + { + if (substr_first_index != ',') + args_buffer += substr_first_index; + else + args_buffer += '$'; + + if (substr_first_index == ';') + { + args_buffer = args_buffer.erase(0, args_buffer.find('(')); + args_buffer = args_buffer.erase(args_buffer.find(';'), 1); + args_buffer = args_buffer.erase(args_buffer.find(')'), 1); + args_buffer = args_buffer.erase(args_buffer.find('('), 1); + + if (!args_buffer.empty()) + args += "\tldw r6, "; + + std::string register_type; + std::size_t index = 7UL; + + while (args_buffer.find("$") != std::string::npos) + { + register_type = kRegisterPrefix; + register_type += std::to_string(index); + + ++index; + + args_buffer.replace(args_buffer.find('$'), 1, + "\n\tldw " + register_type + ","); + } + + args += args_buffer; + args += "\n\tli r31, "; + } + } + + for (char _text_i : textBuffer) + { + if (_text_i == '\t' || _text_i == ' ') + { + if (!type_crossed) + { + substr.clear(); + type_crossed = true; + } + + continue; + } + + if (_text_i == '(') + break; + + substr += _text_i; + } + + if (kInBraces) + { + syntaxLeaf.fUserValue = args; + syntaxLeaf.fUserValue += substr; + + syntaxLeaf.fUserValue += "\n\tblr\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + else + { + syntaxLeaf.fUserValue.clear(); + + syntaxLeaf.fUserValue += "export .code64 "; + + syntaxLeaf.fUserValue += substr; + syntaxLeaf.fUserValue += "\n"; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + fnFound = true; + } + + kCompilerFunctions.push_back(textBuffer); + } + + if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') + { + textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); + + for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) + { + if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') + textBuffer.erase(_text_i, 1); + } + + syntaxLeaf.fUserValue += "dec "; + syntaxLeaf.fUserValue += textBuffer; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + break; + } + + if (textBuffer[text_index] == '}') + { + kRegisterCounter = kStartUsable; + + --kBracesCount; + + if (kBracesCount < 1) + { + kInBraces = false; + kBracesCount = 0; + } + + if (kIfFound) + kIfFound = false; + + if (kInStruct) + kInStruct = false; + + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + } + + syntaxLeaf.fUserValue.clear(); + } + + auto syntaxLeaf = CompilerKit::SyntaxLeafList::SyntaxLeaf(); + syntaxLeaf.fUserValue = "\n"; + kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); + + return true; +} + +static bool kShouldHaveBraces = false; +static std::string kFnName; + +std::string CompilerBackendCLang::Check(const char* text, const char* file) +{ + std::string err_str; + std::string ln = text; + + if (ln.empty()) + { + return err_str; + } + + bool non_ascii_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (isalnum(ln[i])) + { + non_ascii_found = true; + break; + } + } + + if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + + if (!non_ascii_found) + return err_str; + + size_t string_index = 1UL; + + if (ln.find('\'') != std::string::npos) + { + string_index = ln.find('\'') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '\'') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + + return err_str; + } + } + } + else if (ln.find('"') != std::string::npos) + { + string_index = ln.find('"') + 1; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == '"') + { + if (ln[string_index + 1] != ';') + { + ln.erase(string_index, 1); + } + else + { + break; + } + } + } + } + else if (ln.find('"') == std::string::npos && + ln.find('\'') == std::string::npos) + { + std::vector<std::string> forbidden_words; + + forbidden_words.push_back("\\"); + forbidden_words.push_back("?"); + forbidden_words.push_back("@"); + forbidden_words.push_back("~"); + forbidden_words.push_back("::"); + forbidden_words.push_back("/*"); + forbidden_words.push_back("*/"); + + // add them to avoid stupid mistakes. + forbidden_words.push_back("namespace"); + forbidden_words.push_back("class"); + forbidden_words.push_back("extern \"C\""); + + for (auto& forbidden : forbidden_words) + { + if (ln.find(forbidden) != std::string::npos) + { + err_str += "\nForbidden character detected: "; + err_str += forbidden; + + return err_str; + } + } + } + + struct CompilerVariableRange final + { + std::string fBegin; + std::string fEnd; + }; + + const std::vector<CompilerVariableRange> variables_list = { + {.fBegin = "static ", .fEnd = "="}, + {.fBegin = "=", .fEnd = ";"}, + {.fBegin = "if(", .fEnd = "="}, + {.fBegin = "if (", .fEnd = "="}, + {.fBegin = "if(", .fEnd = "<"}, + {.fBegin = "if (", .fEnd = "<"}, + {.fBegin = "if(", .fEnd = ">"}, + {.fBegin = "if (", .fEnd = ">"}, + {.fBegin = "if(", .fEnd = ")"}, + {.fBegin = "if (", .fEnd = ")"}, + + {.fBegin = "else(", .fEnd = "="}, + {.fBegin = "else (", .fEnd = "="}, + {.fBegin = "else(", .fEnd = "<"}, + {.fBegin = "else (", .fEnd = "<"}, + {.fBegin = "else(", .fEnd = ">"}, + {.fBegin = "else (", .fEnd = ">"}, + {.fBegin = "else(", .fEnd = ")"}, + {.fBegin = "else (", .fEnd = ")"}, + }; + + for (auto& variable : variables_list) + { + if (ln.find(variable.fBegin) != std::string::npos) + { + string_index = ln.find(variable.fBegin) + variable.fBegin.size(); + + while (ln[string_index] == ' ') + ++string_index; + + std::string keyword; + + for (; string_index < ln.size(); ++string_index) + { + if (ln[string_index] == variable.fEnd[0]) + { + std::string varname = ""; + + for (size_t index_keyword = ln.find(' '); + ln[index_keyword] != variable.fBegin[0]; ++index_keyword) + { + if (ln[index_keyword] == ' ') + { + continue; + } + + if (isdigit(ln[index_keyword])) + { + goto cc_next_loop; + } + + varname += ln[index_keyword]; + } + + if (varname.find(' ') != std::string::npos) + { + varname.erase(0, varname.find(' ')); + + if (variable.fBegin == "extern") + { + varname.erase(0, varname.find(' ')); + } + } + + if (kRegisterCounter == 5 || kRegisterCounter == 6) + ++kRegisterCounter; + + std::string reg = kAsmRegisterPrefix; + reg += std::to_string(kRegisterCounter); + + kCompilerVariables.push_back({.fValue = varname}); + goto cc_check_done; + } + + keyword.push_back(ln[string_index]); + } + + goto cc_next_loop; + + cc_check_done: + + // skip digit value. + if (isdigit(keyword[0]) || keyword[0] == '"') + { + goto cc_next_loop; + } + + while (keyword.find(' ') != std::string::npos) + keyword.erase(keyword.find(' '), 1); + + for (auto& var : kCompilerVariables) + { + if (var.fValue.find(keyword) != std::string::npos) + { + err_str.clear(); + goto cc_next; + } + } + + for (auto& fn : kCompilerFunctions) + { + if (fn.find(keyword[0]) != std::string::npos) + { + auto where_begin = fn.find(keyword[0]); + auto keyword_begin = 0UL; + auto failed = false; + + for (; where_begin < keyword.size(); ++where_begin) + { + if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') + break; + + if (fn[where_begin] != keyword[keyword_begin]) + { + failed = true; + break; + } + + ++keyword_begin; + } + + if (!failed) + { + err_str.clear(); + goto cc_next; + } + else + { + continue; + } + } + } + + cc_error_value: + if (keyword.find("->") != std::string::npos) + return err_str; + + if (keyword.find(".") != std::string::npos) + return err_str; + + if (isalnum(keyword[0])) + err_str += "\nUndefined value: " + keyword; + + return err_str; + } + + cc_next_loop: + continue; + } + +cc_next: + + // extern does not declare anything, it imports a variable. + // so that's why it's not declare upper. + if (CompilerKit::find_word(ln, "extern")) + { + auto substr = ln.substr(ln.find("extern") + strlen("extern")); + kCompilerVariables.push_back({.fValue = substr}); + } + + if (kShouldHaveBraces && ln.find('{') == std::string::npos) + { + err_str += "Missing '{' for function "; + err_str += kFnName; + err_str += "\n"; + + kShouldHaveBraces = false; + kFnName.clear(); + } + else if (kShouldHaveBraces && ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + kFnName.clear(); + } + + bool type_not_found = true; + + if (ln.find('\'') != std::string::npos) + { + ln.replace(ln.find('\''), 3, "0"); + } + + auto first = ln.find('"'); + if (first != std::string::npos) + { + auto second = 0UL; + bool found_second_quote = false; + + for (size_t i = first + 1; i < ln.size(); ++i) + { + if (ln[i] == '\"') + { + found_second_quote = true; + second = i; + + break; + } + } + + if (!found_second_quote) + { + err_str += "Missing terminating \"."; + err_str += " here -> " + ln.substr(ln.find('"'), second); + } + } + + if (ln.find(')') != std::string::npos && ln.find(';') == std::string::npos) + { + if (ln.find('{') == std::string::npos) + { + kFnName = ln; + kShouldHaveBraces = true; + + goto skip_braces_check; + } + else if (ln.find('{') != std::string::npos) + { + kShouldHaveBraces = false; + } + } + +skip_braces_check: + + for (auto& key : kCompilerTypes) + { + if (CompilerKit::find_word(ln, key.fName)) + { + if (isdigit(ln[ln.find(key.fName) + key.fName.size() + 1])) + { + err_str += "\nNumber cannot be set for "; + err_str += key.fName; + err_str += "'s name. here -> "; + err_str += ln; + } + + if (ln.find(key.fName) == 0 || ln[ln.find(key.fName) - 1] == ' ' || + ln[ln.find(key.fName) - 1] == '\t') + { + type_not_found = false; + + if (ln[ln.find(key.fName) + key.fName.size()] != ' ') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == '\t') + type_not_found = false; + + goto next; + } + else if (ln[ln.find(key.fName) + key.fName.size()] != '\t') + { + type_not_found = true; + + if (ln[ln.find(key.fName) + key.fName.size()] == ' ') + type_not_found = false; + } + } + + next: + + if (ln.find(';') == std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find('=') == std::string::npos) + continue; + } + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + else + { + continue; + } + + if (ln.find('=') != std::string::npos) + { + if (ln.find('(') != std::string::npos) + { + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + } + } + } + + if (kInBraces && ln.find("struct") != std::string::npos && + ln.find("union") != std::string::npos && + ln.find("enum") != std::string::npos && + ln.find('=') != std::string::npos) + { + if (ln.find(';') == std::string::npos) + { + err_str += "\nMissing ';' after struct/union/enum declaration, here -> "; + err_str += ln; + } + } + + if (ln.find(';') != std::string::npos && + ln.find("for") == std::string::npos) + { + if (ln.find(';') + 1 != ln.size()) + { + for (int i = 0; i < ln.substr(ln.find(';') + 1).size(); ++i) + { + if ((ln.substr(ln.find(';') + 1)[i] != ' ') || + (ln.substr(ln.find(';') + 1)[i] != '\t')) + { + if (auto err = this->Check(ln.substr(ln.find(';') + 1).c_str(), file); + !err.empty()) + { + err_str += "\nUnexpected text after ';' -> "; + err_str += ln.substr(ln.find(';')); + err_str += err; + } + } + } + } + } + + if (ln.find('(') != std::string::npos) + { + if (ln.find(';') == std::string::npos && !CompilerKit::find_word(ln, "|") && + !CompilerKit::find_word(ln, "||") && !CompilerKit::find_word(ln, "&") && + !CompilerKit::find_word(ln, "&&") && !CompilerKit::find_word(ln, "~")) + { + bool found_func = false; + size_t i = ln.find('('); + std::vector<char> opens; + std::vector<char> closes; + + for (; i < ln.size(); ++i) + { + if (ln[i] == ')') + { + closes.push_back(1); + } + + if (ln[i] == '(') + { + opens.push_back(1); + } + } + + if (closes.size() != opens.size()) + err_str += "Unterminated (), here -> " + ln; + + bool space_found = false; + + for (int i = 0; i < ln.size(); ++i) + { + if (ln[i] == ')' && !space_found) + { + space_found = true; + continue; + } + + if (space_found) + { + if (ln[i] == ' ' && isalnum(ln[i + 1])) + { + err_str += "\nBad function format here -> "; + err_str += ln; + } + } + } + } + + if (ln.find('(') < 1) + { + err_str += "\nMissing identifier before '(' here -> "; + err_str += ln; + } + else + { + if (type_not_found && ln.find(';') == std::string::npos && + ln.find("if") == std::string::npos && + ln.find("|") == std::string::npos && + ln.find("&") == std::string::npos && + ln.find("(") == std::string::npos && + ln.find(")") == std::string::npos) + { + err_str += "\n Missing ';' or type, here -> "; + err_str += ln; + } + } + + if (ln.find(')') == std::string::npos) + { + err_str += "\nMissing ')', after '(' here -> "; + err_str += ln.substr(ln.find('(')); + } + } + else + { + if (ln.find("for") != std::string::npos || + ln.find("while") != std::string::npos) + { + err_str += "\nMissing '(', after \"for\", here -> "; + err_str += ln; + } + } + + if (ln.find('}') != std::string::npos && !kInBraces) + { + if (!kInStruct && ln.find(';') == std::string::npos) + { + err_str += "\nMismatched '}', here -> "; + err_str += ln; + } + } + + if (!ln.empty()) + { + if (ln.find(';') == std::string::npos && + ln.find('{') == std::string::npos && + ln.find('}') == std::string::npos && + ln.find(')') == std::string::npos && + ln.find('(') == std::string::npos && + ln.find(',') == std::string::npos) + { + if (ln.size() <= 2) + return err_str; + + err_str += "\nMissing ';', here -> "; + err_str += ln; + } + } + + return err_str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +/** + * @brief C To Assembly mount-point. + */ + +///////////////////////////////////////////////////////////////////////////////////////// + +class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface +{ +public: + explicit AssemblyMountpointCLang() = default; + ~AssemblyMountpointCLang() override = default; + + MPCC_COPY_DEFAULT(AssemblyMountpointCLang); + + [[maybe_unused]] static Int32 Arch() noexcept + { + return CompilerKit::AssemblyFactory::kArchPowerPC; + } + + Int32 CompileToFormat(std::string& src, Int32 arch) override + { + if (arch != AssemblyMountpointCLang::Arch()) + return -1; + + if (kCompilerBackend == nullptr) + return -1; + + /* @brief copy contents wihtout extension */ + std::string src_file = src.data(); + std::ifstream src_fp = std::ifstream(src_file, std::ios::in); + std::string dest; + + for (auto& ch : src_file) + { + if (ch == '.') + { + break; + } + + dest += ch; + } + + /* According to PEF ABI. */ + std::vector<const char*> exts = kAsmFileExts; + dest += exts[4]; + + kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); + + auto fmt = CompilerKit::current_date(); + + (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; + (*kState.fOutputAssembly) + << "# Language: POWER Assembly (Generated from C)\n"; + (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; + + CompilerKit::SyntaxLeafList syntax; + + kState.fSyntaxTreeList.push_back(syntax); + kState.fSyntaxTree = + &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; + + std::string line_src; + + while (std::getline(src_fp, line_src)) + { + if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); + err.empty()) + { + kCompilerBackend->Compile(line_src, src.data()); + } + else + { + detail::print_error(err, src.data()); + } + } + + if (kAcceptableErrors > 0) + return -1; + + std::vector<std::string> keywords = {"ld", "stw", "add", "sub", "or"}; + + /// + /// Replace, optimize, fix assembly output. + /// + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + std::vector<std::string> access_keywords = {"->", "."}; + + for (auto& access_ident : access_keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, access_ident)) + { + for (auto& struc : kState.kStructMap) + { + /// TODO: + } + } + } + + for (auto& keyword : keywords) + { + if (CompilerKit::find_word(leaf.fUserValue, keyword)) + { + std::size_t cnt = 0UL; + + for (auto& reg : kState.kStackFrame) + { + std::string needle; + + for (size_t i = 0; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ' ') + { + ++i; + + for (; i < reg.fName.size(); i++) + { + if (reg.fName[i] == ',') + { + break; + } + + if (reg.fName[i] == ' ') + continue; + + needle += reg.fName[i]; + } + + break; + } + } + + if (CompilerKit::find_word(leaf.fUserValue, needle)) + { + if (leaf.fUserValue.find("import ") != std::string::npos) + { + std::string range = "import "; + leaf.fUserValue.replace(leaf.fUserValue.find(range), + range.size(), ""); + } + + if (leaf.fUserValue.find("ldw r6") != std::string::npos) + { + std::string::difference_type countComma = std::count( + leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); + + if (countComma == 1) + { + leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), + strlen("ldw"), "mr"); + } + } + + leaf.fUserValue.replace(leaf.fUserValue.find(needle), + needle.size(), reg.fReg); + + ++cnt; + } + } + + if (cnt > 1 && keyword != "mr" && keyword != "add" && + keyword != "dec") + { + leaf.fUserValue.replace(leaf.fUserValue.find(keyword), + keyword.size(), "mr"); + } + } + } + } + + for (auto& leaf : kState.fSyntaxTree->fLeafList) + { + (*kState.fOutputAssembly) << leaf.fUserValue; + } + + kState.fSyntaxTree = nullptr; + + kState.fOutputAssembly->flush(); + kState.fOutputAssembly.reset(); + + return kOk; + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#include <Version.hpp> + +#define kPrintF printf +#define kSplashCxx() \ + kPrintF(kWhite "cc, %s, (c) ZKA Technologies\n", kDistVersion) + +static void cc_print_help() +{ + kSplashCxx(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +#define kExt ".c" + +NDK_MODULE(NewOSCompilerCLangPowerPC) +{ + kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); + kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); + kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); + kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); + kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); + kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); + + bool skip = false; + + kFactory.Mount(new AssemblyMountpointCLang()); + kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; + kCompilerBackend = new CompilerBackendCLang(); + + for (auto index = 1UL; index < argc; ++index) + { + if (skip) + { + skip = false; + continue; + } + + if (argv[index][0] == '-') + { + if (strcmp(argv[index], "-v") == 0 || + strcmp(argv[index], "-version") == 0) + { + kSplashCxx(); + return kOk; + } + + if (strcmp(argv[index], "-verbose") == 0) + { + kState.fVerbose = true; + + continue; + } + + if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) + { + cc_print_help(); + + return kOk; + } + + if (strcmp(argv[index], "-dialect") == 0) + { + if (kCompilerBackend) + std::cout << kCompilerBackend->Language() << "\n"; + + return kOk; + } + + if (strcmp(argv[index], "-fmax-exceptions") == 0) + { + try + { + kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); + } + // catch anything here + catch (...) + { + kErrorLimit = 0; + } + + skip = true; + + continue; + } + + std::string err = "Unknown command: "; + err += argv[index]; + + detail::print_error(err, "cc"); + + continue; + } + + kFileList.emplace_back(argv[index]); + + std::string srcFile = argv[index]; + + if (strstr(argv[index], kExt) == nullptr) + { + if (kState.fVerbose) + { + detail::print_error(srcFile + " is not a valid C source.\n", "cc"); + } + + return 1; + } + + if (kFactory.Compile(srcFile, kMachine) != kOk) + return -1; + } + + return kOk; +} + +// Last rev 8-1-24 diff --git a/Headers/UUID.hpp b/NDKKit/UUID.hpp index 00b153b..00b153b 100644 --- a/Headers/UUID.hpp +++ b/NDKKit/UUID.hpp diff --git a/NDKKit/Version.hpp b/NDKKit/Version.hpp new file mode 100644 index 0000000..38fd537 --- /dev/null +++ b/NDKKit/Version.hpp @@ -0,0 +1,4 @@ +#pragma once + +#define kDistVersion "v1.22" +#define kDistRelease "Havok"
\ No newline at end of file diff --git a/Documentation/ASM_SPECS.TXT b/Notes/ASM specs.txt index a0c42bf..a0c42bf 100644 --- a/Documentation/ASM_SPECS.TXT +++ b/Notes/ASM specs.txt diff --git a/Documentation/HAVP.TXT b/Notes/HAVP DSP.txt index 12fcec5..12fcec5 100644 --- a/Documentation/HAVP.TXT +++ b/Notes/HAVP DSP.txt diff --git a/Documentation/Inside 64x0.pdf b/Notes/Inside 64x0.pdf Binary files differindex bcd6782..bcd6782 100644 --- a/Documentation/Inside 64x0.pdf +++ b/Notes/Inside 64x0.pdf diff --git a/Documentation/NOTICE.TXT b/Notes/Notice.txt index 23691da..23691da 100644 --- a/Documentation/NOTICE.TXT +++ b/Notes/Notice.txt diff --git a/Documentation/VNRP.TXT b/Notes/RISC CPU.txt index e17b494..e17b494 100644 --- a/Documentation/VNRP.TXT +++ b/Notes/RISC CPU.txt @@ -1,17 +1,21 @@ -# CodeTools +# NDKKit, C++ SDK for ZKA. -Start by cloning the repo: +## Installing: + +Start by cloning the repo. ``` git clone git@bitbucket.org:mahrouss/codetools.git ``` -and +## Running makefiles: + +And then run the makefile according to your platform. ``` -make all +make -f <platform>.make all ``` -Author: Amlal El Mahrouss +You can now use the programs. -##### Copyright Mahrouss Logic, all rights reserved. +###### Copyright ZKA Technologies, all rights reserved. diff --git a/SDK/__mpcc_exception.hxx b/SDK/__mpcc_exception.hxx deleted file mode 100644 index 0cd439d..0000000 --- a/SDK/__mpcc_exception.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/* ------------------------------------------- - - Copyright Mahrouss Logic - -------------------------------------------- */ - -#pragma once - -/// This file is an implementation of __throw* family of functions. - -#include <exception> -#include <iostream> -#include <stdexcept> - -namespace std -{ - inline void __throw_general(void) - { - throw std::runtime_error("MPCC C++ Runtime error."); - } - - inline void __throw_domain_error(const char* error) - { - std::cout << "MPCC C++: Domain error: " << error << "\r"; - __throw_general(); - } -} diff --git a/SDK/__mpcc_malloc.hxx b/SDK/__mpcc_malloc.hxx deleted file mode 100644 index b1ee2a7..0000000 --- a/SDK/__mpcc_malloc.hxx +++ /dev/null @@ -1,29 +0,0 @@ -/* ------------------------------------------- - - Copyright Mahrouss Logic - -------------------------------------------- */ - -#pragma once - -#include <algorithm> - -namespace stdx -{ -/// @brief allocate a new class. -/// @tparam KindClass the class type to allocate. -template <typename KindClass, typename... Args> -inline void* allocate(Args&&... args) -{ - return new KindClass(std::forward(args)...); -} - -/// @brief free a class. -/// @tparam KindClass the class type to allocate. -template <typename KindClass> -inline void release(KindClass ptr) -{ - if (!ptr) return; - delete ptr; -} -} // namespace stdx diff --git a/Sources/64x0-cc.cc b/Sources/64x0-cc.cc deleted file mode 100644 index c23e3c1..0000000 --- a/Sources/64x0-cc.cc +++ /dev/null @@ -1,1354 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright Mahrouss Logic, all rights reserved. - * - * ======================================================== - */ - -/// BUGS: ? -/// TODO: - -#include <Headers/AsmKit/CPU/64x0.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/UUID.hpp> -#include <cstdio> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -#define kOk 0 - -/* C driver */ -/* This is part of CodeTools C SDK. */ -/* (c) Mahrouss Logic */ - -/// @author Amlal El Mahrouss (amlel) -/// @file 64x0-cc.cc -/// @brief 64x0 C Compiler. - -/// TODO: support structures, else if, else, . and -> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlel -struct CompilerStructMap final { - // 'my_foo' - std::string fName; - - // if instance: stores a valid register. - std::string fReg; - - // offset count - std::size_t fOffsetsCnt; - - // offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - ParserKit::SyntaxLeafList *fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char *text, const char *file); - bool Compile(const std::string &text, const char *file) override; - - const char *Language() override { return "64k C"; } -}; - -static CompilerBackendCLang *kCompilerBackend = nullptr; -static std::vector<detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; -static std::vector<detail::CompilerType> kCompilerTypes; - -namespace detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string &text, const char *file) { - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto &clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (textBuffer.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) { - if (textBuffer[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) { - if (textBuffer[value_index] == ';') break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tldw r19, "; - - // make it pretty. - if (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - syntaxLeaf.fUserValue += value + "\n"; - } - - syntaxLeaf.fUserValue += "\tjlr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = "\tlda r12, import "; - syntaxLeaf.fUserValue += - kIfFunction + - "\n\t#r12 = Code to jump on, r11 right cond, r10 left cond.\n\tbeq " - "r10, r11, r12\ndword export .code64 " + - kIfFunction + "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (textBuffer[text_index] == ';' && kInStruct) continue; - - if (textBuffer.find("typedef ") != std::string::npos) continue; - - if (textBuffer[text_index] == '=' && kInStruct) { - detail::print_error("assignement of value in struct " + textBuffer, - file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto &ch : textBuffer) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (textBuffer.find("*") != std::string::npos) { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tlda "; - else - substr += "\tldw "; - } else { - substr += "\tldw "; - } - } else if (textBuffer.find('=') != std::string::npos && !kInBraces) { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) { - if (textBuffer[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) { - if (textBuffer[text_index_2] == '\"') break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') { - if (first_encountered != 2) { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto &clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - if (kRegisterCounter == 5 || kRegisterCounter == 6) ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - if (var_to_find == kCompilerVariables.cend()) { - ++kRegisterCounter; - - kState.kStackFrame.push_back({.fName = substr, .fReg = reg}); - kCompilerVariables.push_back({.fName = substr}); - } - - syntaxLeaf.fUserValue += substr; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - if (textBuffer[text_index] == '=') break; - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) { - if (textBuffer[idx] == ',') continue; - - if (textBuffer[idx] == ' ') continue; - - if (textBuffer[idx] == ')') break; - } - - for (char substr_first_index : textBuffer) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tlda r19, "; - } - } - - for (char _text_i : textBuffer) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n\tjrl\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char *text, const char *file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) { - std::vector<std::string> forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto &forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector<CompilerVariableRange> variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto &variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto &var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto &fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::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 (ParserKit::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 && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArch64x0; - } - - Int32 CompileToFormat(std::string &src, Int32 arch) override { - if (arch != AssemblyMountpointCLang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto &ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char *> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: 64x0 Assembly (Generated from ANSI C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) { - kCompilerBackend->Compile(line_src, src.data()); - } else { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return -1; - - std::vector<std::string> keywords = {"ldw", "stw", "lda", "sta", - "add", "dec", "mv"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto &access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) { - for (auto &struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto &keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto ® : 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 (ParserKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("import " + needle) != - std::string::npos) { - std::string range = "import " + needle; - leaf.fUserValue.replace( - leaf.fUserValue.find("import " + needle), range.size(), - needle); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mv"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mv" && keyword != "add" && - keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mv"); - } - } - } - } - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <Version.hxx> - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion) - -static void cc_print_help() { kSplashCxx(); } - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -MPCC_MODULE(NewOSCompilerCLang64x0) { - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArch64x0; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/AsmKit.cc b/Sources/AsmKit.cc deleted file mode 100644 index b4af817..0000000 --- a/Sources/AsmKit.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* ------------------------------------------- - - Copyright Mahrouss Logic - -------------------------------------------- */ - -#include <Headers/AsmKit/AsmKit.hpp> -#include <Headers/StdKit/ErrorID.hpp> - -/** - * @file AsmKit.cc - * @author Amlal El Mahrouss (amlal@mahrouss.com) - * @brief Assembler Kit - * @version 0.1 - * @date 2024-01-27 - * - * @copyright Copyright (c) 2024, Mahrouss Logic - * - */ - -#include <iostream> - -//! @file AsmKit.cpp -//! @brief AssemblyKit source implementation. - -namespace CompilerKit { -//! @brief Compile for specific format (ELF, PEF, ZBIN) -Int32 AssemblyFactory::Compile(std::string& sourceFile, - const Int32& arch) noexcept { - if (sourceFile.length() < 1 || !fMounted) return MPCC_UNIMPLEMENTED; - - return fMounted->CompileToFormat(sourceFile, arch); -} - -//! @brief mount assembly backend. -void AssemblyFactory::Mount(AssemblyInterface* mountPtr) noexcept { - if (mountPtr) { - fMounted = mountPtr; - } -} - -AssemblyInterface* AssemblyFactory::Unmount() noexcept { - auto mount_prev = fMounted; - - if (mount_prev) { - fMounted = nullptr; - } - - return mount_prev; -} -} // namespace CompilerKit diff --git a/Sources/amd64-cplusplus.cc b/Sources/amd64-cplusplus.cc deleted file mode 100644 index 60e6435..0000000 --- a/Sources/amd64-cplusplus.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * ======================================================== - * - * ccplus - * Copyright Mahrouss Logic, all rights reserved. - * - * ======================================================== - */ - -/// bugs: 0 - -#define __PK_USE_STRUCT_INSTEAD__ 1 - -#define kPrintF printf - -#define kSplashCxx() \ - kPrintF(kWhite "%s\n", "Mahrouss C++ Compiler, Copyright Mahrouss Logic.") - -#include <Headers/AsmKit/CPU/amd64.hpp> -#include <Headers/ParserKit.hpp> -#include <cstdio> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#define kOk 0 - -/* Mahrouss Logic C++ driver */ -/* This is part of CodeTools C++ compiler. */ -/* (c) Mahrouss Logic */ - -// @author Amlal El Mahrouss (amlel) -// @file cc.cc -// @brief Optimized C++ Compiler. - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -// INTERNAL STUFF OF THE C COMPILER - -///////////////////////////////////// - -namespace detail { -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Offset based struct/class -struct CompilerStructMap final { - std::string fName; - std::string fReg; - - // offset counter - std::size_t fOffsetsCnt; - - // offset array - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - ParserKit::SyntaxLeafList* fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; - -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) { - file.erase(file.find(".pp"), 3); - } - - if (kState.fLastFile != file) { - std::cout << kRed << "[ ccplus ] " << kWhite - << ((file == "ccplus") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ ccplus ] " << kWhite << reason << kBlank - << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ ccplus ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType { - std::string fName; - std::string fValue; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = CompilerKit::AssemblyFactory::kArchAMD64; - -///////////////////////////////////////// - -// ARGUMENTS REGISTERS (R8, R15) - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 8; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::vector<ParserKit::CompilerKeyword> kKeywords; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static size_t kBracesCount = 0UL; - -/* @brief C++ compiler backend for Mahrouss Logic C++ */ -class CompilerBackendCPlusPlus final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCPlusPlus() = default; - ~CompilerBackendCPlusPlus() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCPlusPlus); - - bool Compile(const std::string& text, const char* file) override; - - const char* Language() override; -}; - -/// compiler variables - -static CompilerBackendCPlusPlus* kCompilerBackend = nullptr; -static std::vector<detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; - -/// detail namespaces - -namespace detail { -union number_cast final { - number_cast(UInt64 raw) : raw(raw) {} - - char number[8]; - UInt64 raw; -}; -} // namespace detail - -const char* CompilerBackendCPlusPlus::Language() { return "C++"; } - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C++ source. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCPlusPlus::Compile(const std::string& text, - const char* file) { - if (text.empty()) return false; - - // if (expr) - // int name = expr; - // expr; - - std::size_t index = 0UL; - - std::vector<std::pair<ParserKit::CompilerKeyword, std::size_t>> keywords_list; - - for (auto& keyword : kKeywords) { - while (text.find(keyword.keyword_name) != std::string::npos) { - keywords_list.emplace_back(std::make_pair(keyword, index)); - ++index; - } - } - - // TODO: sort keywords - - for (auto& keyword : keywords_list) { - auto syntax_tree = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - syntax_tree.fUserData = keyword.first; - kState.fSyntaxTree->fLeafList.emplace_back(syntax_tree); - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointClang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointClang() = default; - ~AssemblyMountpointClang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointClang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArchAMD64; - } - - Int32 CompileToFormat(std::string& src, Int32 arch) override { - if (arch != AssemblyMountpointClang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto& ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - - std::vector<const char*> exts = kAsmFileExts; - dest += exts[3]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "; Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "; Language: CodeTools assembly. (Generated from C++)\n"; - (*kState.fOutputAssembly) << "; Date: " << fmt << "\n\n"; - (*kState.fOutputAssembly) << "#bits 64\n\n#org 0x1000000" - << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.emplace_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string source; - - while (std::getline(src_fp, source)) { - // Compile into an AST format. - kCompilerBackend->Compile(source.c_str(), src.data()); - } - - if (kAcceptableErrors > 0) return -1; - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -static void cxx_print_help() { - kSplashCxx(); - kPrintF("%s", "No help available, see:\r\n"); - kPrintF("%s", "www.el-mahrouss-logic.com/developer/newos/cplusplus\r\n"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExtListCxx \ - { ".cpp", ".cxx", ".cc", ".c++", ".cp" } - -MPCC_MODULE(CompilerCPlusPlus) { - bool skip = false; - - kFactory.Mount(new AssemblyMountpointClang()); - kCompilerBackend = new CompilerBackendCPlusPlus(); - - for (auto index = 1UL; index < argc; ++index) { - if (argv[index][0] == '-') { - if (skip) { - skip = false; - continue; - } - - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cxx_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-max-errors") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown option: "; - err += argv[index]; - - detail::print_error(err, "ccplus"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string argv_i = argv[index]; - - std::vector exts = kExtListCxx; - bool found = false; - - for (std::string ext : exts) { - if (argv_i.find(ext) != std::string::npos) { - found = true; - break; - } - } - - if (!found) { - if (kState.fVerbose) { - detail::print_error(argv_i + " is not a valid C++ source.\n", "ccplus"); - } - - return 1; - } - - if (kFactory.Compile(argv_i, kMachine) != kOk) return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc deleted file mode 100644 index 4f5d885..0000000 --- a/Sources/i64asm.cc +++ /dev/null @@ -1,1247 +0,0 @@ -/* ------------------------------------------- - - Copyright Mahrouss Logic - -------------------------------------------- */ - -///////////////////////////////////////////////////////////////////////////////////////// - -/// @file i64asm.cxx -/// @author Amlal El Mahrouss -/// @brief AMD64 Assembler. - -/// REMINDER: when dealing with an undefined symbol use (string -/// size):LinkerFindSymbol:(string) so that ld will look for it. - -///////////////////////////////////////////////////////////////////////////////////////// - -/// bugs: 0 - -/// feature request: 1 -/// Encode registers in mov, add, xor... - -///////////////////////////////////////////////////////////////////////////////////////// - -#define __ASM_NEED_AMD64__ 1 - -#define kAssemblerPragmaSymStr "#" -#define kAssemblerPragmaSym '#' - -#include <Headers/AsmKit/CPU/amd64.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/StdKit/AE.hpp> -#include <Headers/StdKit/PEF.hpp> -#include <algorithm> -#include <cstdlib> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <vector> - -///////////////////// - -// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" -#define kYellow "\e[0;33m" - -#define kStdOut (std::cout << kWhite) -#define kStdErr (std::cout << kRed) - -static char kOutputArch = CompilerKit::kPefArchAMD64; -static Boolean kOutputAsBinary = false; - -static UInt32 kErrorLimit = 10; -static UInt32 kAcceptableErrors = 0; - -constexpr auto cAMD64IPAlignment = 0x4U; - -static std::size_t kCounter = 1UL; - -static std::uintptr_t kOrigin = kPefBaseOrigin; -static std::vector<std::pair<std::string, std::uintptr_t>> kOriginLabel; - -/// @brief keep it simple by default. -static std::int32_t kRegisterBitWidth = 16U; - -static bool kVerbose = false; - -static std::vector<i64_byte_t> kAppBytes; - -static CompilerKit::AERecordHeader kCurrentRecord{ - .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; - -static std::vector<CompilerKit::AERecordHeader> kRecords; -static std::vector<std::string> kDefinedSymbols; -static std::vector<std::string> kUndefinedSymbols; - -static const std::string kUndefinedSymbol = ":UndefinedSymbol:"; -static const std::string kRelocSymbol = ":RuntimeSymbol:"; - -// \brief forward decl. -static bool asm_read_attributes(std::string &line); - -namespace detail { -void print_error(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - kStdErr << kRed << "[ i64asm ] " << kWhite - << ((file == "i64asm") ? "internal assembler error " - : ("in file, " + file)) - << kBlank << std::endl; - kStdErr << kRed << "[ i64asm ] " << kWhite << reason << kBlank << std::endl; - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -void print_warning(std::string reason, const std::string &file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (!file.empty()) { - kStdOut << kYellow << "[ file ] " << kWhite << file << kBlank << std::endl; - } - - kStdOut << kYellow << "[ i64asm ] " << kWhite << reason << kBlank - << std::endl; -} -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief AMD64 assembler entrypoint, the program/module starts here. - -///////////////////////////////////////////////////////////////////////////////////////// - -MPCC_MODULE(NewOSAssemblerAMD64) { - //////////////// CPU OPCODES BEGIN //////////////// - - std::string opcodes_jump[kJumpLimit] = { - "ja", "jae", "jb", "jbe", "jc", "je", "jg", "jge", "jl", "jle", - "jna", "jnae", "jnb", "jnbe", "jnc", "jne", "jng", "jnge", "jnl", "jnle", - "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; - - for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuOpcodeAMD64 code{ - .fName = opcodes_jump[i], - .fOpcode = static_cast<i64_hword_t>(kAsmJumpOpcode + i)}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; - kOpcodesAMD64.push_back(code); - - for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; - kOpcodesAMD64.push_back(code); - } - - CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; - kOpcodesAMD64.push_back(lahf); - - CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; - kOpcodesAMD64.push_back(lds); - - CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; - kOpcodesAMD64.push_back(lea); - - CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; - kOpcodesAMD64.push_back(nop); - - //////////////// CPU OPCODES END //////////////// - - for (size_t i = 1; i < argc; ++i) { - if (argv[i][0] == '-') { - if (strcmp(argv[i], "-version") == 0 || strcmp(argv[i], "-v") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: v1.10\ni64asm: Copyright " - "(c) 2024 Mahrouss Logic.\n"; - return 0; - } else if (strcmp(argv[i], "-h") == 0) { - kStdOut << "i64asm: AMD64 Assembler.\ni64asm: 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"; - - return 0; - } else if (strcmp(argv[i], "-binary") == 0) { - kOutputAsBinary = true; - continue; - } else if (strcmp(argv[i], "-verbose") == 0) { - kVerbose = true; - continue; - } - - kStdOut << "i64asm: ignore " << argv[i] << "\n"; - continue; - } - - if (!std::filesystem::exists(argv[i])) { - kStdOut << "i64asm: can't open: " << argv[i] << std::endl; - goto asm_fail_exit; - } - - std::string object_output(argv[i]); - - for (auto &ext : kAsmFileExts) { - if (object_output.find(ext) != std::string::npos) { - object_output.erase(object_output.find(ext), std::strlen(ext)); - } - } - - object_output += kOutputAsBinary ? kBinaryFileExt : kObjectFileExt; - - std::ifstream file_ptr(argv[i]); - std::ofstream file_ptr_out(object_output, std::ofstream::binary); - - if (file_ptr_out.bad()) { - if (kVerbose) { - kStdOut << "i64asm: error: " << strerror(errno) << "\n"; - } - } - - std::string line; - - CompilerKit::AEHeader hdr{0}; - - memset(hdr.fPad, kAEInvalidOpcode, kAEPad); - - hdr.fMagic[0] = kAEMag0; - hdr.fMagic[1] = kAEMag1; - hdr.fSize = sizeof(CompilerKit::AEHeader); - hdr.fArch = kOutputArch; - - ///////////////////////////////////////////////////////////////////////////////////////// - - // COMPILATION LOOP - - ///////////////////////////////////////////////////////////////////////////////////////// - - CompilerKit::EncoderAMD64 asm64; - - while (std::getline(file_ptr, line)) { - if (auto ln = asm64.CheckLine(line, argv[i]); !ln.empty()) { - detail::print_error(ln, argv[i]); - continue; - } - - try { - asm_read_attributes(line); - asm64.WriteLine(line, argv[i]); - } catch (const std::exception &e) { - if (kVerbose) { - std::string what = e.what(); - detail::print_warning("exit because of: " + what, "i64asm"); - } - - try { - std::filesystem::remove(object_output); - } catch (...) { - } - - goto asm_fail_exit; - } - } - - if (!kOutputAsBinary) { - if (kVerbose) { - kStdOut << "i64asm: Writing object file...\n"; - } - - // this is the final step, write everything to the file. - - auto pos = file_ptr_out.tellp(); - - hdr.fCount = kRecords.size() + kUndefinedSymbols.size(); - - file_ptr_out << hdr; - - if (kRecords.empty()) { - kStdErr << "i64asm: At least one record is needed to write an object " - "file.\ni64asm: Make one using `export .code64 foo_bar`.\n"; - - std::filesystem::remove(object_output); - return -1; - } - - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - std::size_t record_count = 0UL; - - for (auto &rec : kRecords) { - if (kVerbose) - kStdOut << "i64asm: Wrote record " << rec.fName << " to file...\n"; - - rec.fFlags |= CompilerKit::kKindRelocationAtRuntime; - rec.fOffset = record_count; - ++record_count; - - file_ptr_out << rec; - } - - // increment once again, so that we won't lie about the kUndefinedSymbols. - ++record_count; - - for (auto &sym : kUndefinedSymbols) { - CompilerKit::AERecordHeader _record_hdr{0}; - - if (kVerbose) - kStdOut << "i64asm: Wrote symbol " << sym << " to file...\n"; - - _record_hdr.fKind = kAEInvalidOpcode; - _record_hdr.fSize = sym.size(); - _record_hdr.fOffset = record_count; - - ++record_count; - - memset(_record_hdr.fPad, kAEInvalidOpcode, kAEPad); - memcpy(_record_hdr.fName, sym.c_str(), sym.size()); - - file_ptr_out << _record_hdr; - - ++kCounter; - } - - auto pos_end = file_ptr_out.tellp(); - - file_ptr_out.seekp(pos); - - hdr.fStartCode = pos_end; - hdr.fCodeSize = kAppBytes.size(); - - file_ptr_out << hdr; - - file_ptr_out.seekp(pos_end); - } else { - if (kVerbose) { - kStdOut << "i64asm: Write raw binary...\n"; - } - } - - // byte from byte, we write this. - for (auto &byte : kAppBytes) { - if (byte == 0) continue; - - if (byte == 0xFF) { - byte = 0; - } - - file_ptr_out << reinterpret_cast<const char *>(&byte)[0]; - } - - if (kVerbose) kStdOut << "i64asm: Wrote file with program in it.\n"; - - file_ptr_out.flush(); - file_ptr_out.close(); - - if (kVerbose) kStdOut << "i64asm: Exit succeeded.\n"; - - return 0; - } - -asm_fail_exit: - - if (kVerbose) kStdOut << "i64asm: Exit failed.\n"; - - return -1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for attributes -// returns true if any was found. - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool asm_read_attributes(std::string &line) { - // import is the opposite of export, it signals to the ld - // that we need this symbol. - if (ParserKit::find_word(line, "import")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_import_bin"); - } - - auto name = line.substr(line.find("import") + strlen("import") + 1); - - if (name.size() == 0) { - detail::print_error("Invalid import", "ppcasm"); - throw std::runtime_error("invalid_import"); - } - - std::string result = std::to_string(name.size()); - result += kUndefinedSymbol; - - // mangle this - for (char &j : name) { - if (j == ' ' || j == ',') j = '$'; - } - - result += name; - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, result.c_str(), result.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - // export is a special keyword used by i64asm to tell the AE output stage to - // mark this section as a header. it currently supports .code64, .data64 and - // .zero64. - else if (ParserKit::find_word(line, "export")) { - if (kOutputAsBinary) { - detail::print_error("Invalid directive in flat binary mode.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - auto name = line.substr(line.find("export") + strlen("export") + 1); - - std::string name_copy = name; - - for (char &j : name) { - if (j == ' ') j = '$'; - } - - if (std::find(kDefinedSymbols.begin(), kDefinedSymbols.end(), name) != - kDefinedSymbols.end()) { - detail::print_error("Symbol already defined.", "i64asm"); - throw std::runtime_error("invalid_export_bin"); - } - - kDefinedSymbols.push_back(name); - - if (name.find(".code64") != std::string::npos) { - // data is treated as code. - - name_copy.erase(name_copy.find(".code64"), strlen(".code64")); - kCurrentRecord.fKind = CompilerKit::kPefCode; - } else if (name.find(".data64") != std::string::npos) { - // no code will be executed from here. - - name_copy.erase(name_copy.find(".data64"), strlen(".data64")); - kCurrentRecord.fKind = CompilerKit::kPefData; - } else if (name.find(".zero64") != std::string::npos) { - // this is a bss section. - - name_copy.erase(name_copy.find(".zero64"), strlen(".zero64")); - kCurrentRecord.fKind = CompilerKit::kPefZero; - } - - // this is a special case for the start stub. - // we want this so that ld can find it. - - if (name == kPefStart) { - kCurrentRecord.fKind = CompilerKit::kPefCode; - } - - while (name_copy.find(" ") != std::string::npos) - name_copy.erase(name_copy.find(" "), 1); - - kOriginLabel.push_back(std::make_pair(name_copy, kOrigin)); - ++kOrigin; - - // now we can tell the code size of the previous kCurrentRecord. - - if (!kRecords.empty()) - kRecords[kRecords.size() - 1].fSize = kAppBytes.size(); - - memset(kCurrentRecord.fName, 0, kAESymbolLen); - memcpy(kCurrentRecord.fName, name.c_str(), name.size()); - - ++kCounter; - - memset(kCurrentRecord.fPad, kAEInvalidOpcode, kAEPad); - - kRecords.emplace_back(kCurrentRecord); - - return true; - } - - return false; -} - -// \brief algorithms and helpers. - -namespace detail::algorithm { -// \brief authorize a brief set of characters. -static inline bool is_not_alnum_space(char c) { - return !(isalpha(c) || isdigit(c) || (c == ' ') || (c == '\t') || - (c == ',') || (c == '(') || (c == ')') || (c == '"') || - (c == '\'') || (c == '[') || (c == ']') || (c == '+') || - (c == '_') || (c == ':') || (c == '@') || (c == '.') || (c == '#')); -} - -bool is_valid(const std::string &str) { - return std::find_if(str.begin(), str.end(), is_not_alnum_space) == str.end(); -} -} // namespace detail::algorithm - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Check for line (syntax check) - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string CompilerKit::EncoderAMD64::CheckLine(std::string &line, - const std::string &file) { - std::string err_str; - - if (line.empty() || ParserKit::find_word(line, "import") || - ParserKit::find_word(line, "export") || - ParserKit::find_word(line, kAssemblerPragmaSymStr) || - ParserKit::find_word(line, ";") || line[0] == kAssemblerPragmaSym) { - if (line.find(';') != std::string::npos) { - line.erase(line.find(';')); - } else { - // now check the line for validity - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non valid characters.\nhere -> "; - err_str += line; - } - } - - return err_str; - } - - if (!detail::algorithm::is_valid(line)) { - err_str = "Line contains non alphanumeric characters.\nHere -> "; - err_str += line; - - return err_str; - } - - // check for a valid instruction format. - - if (line.find(',') != std::string::npos) { - if (line.find(',') + 1 == line.size()) { - err_str += "\nInstruction lacks right register, here -> "; - err_str += line.substr(line.find(',')); - - return err_str; - } else { - bool nothing_on_right = true; - - if (line.find(',') + 1 > line.size()) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - - auto substr = line.substr(line.find(',') + 1); - - for (auto &ch : substr) { - if (ch != ' ' && ch != '\t') { - nothing_on_right = false; - } - } - - // this means we found nothing after that ',' . - if (nothing_on_right) { - err_str += "\nInstruction not complete, here -> "; - err_str += line; - - return err_str; - } - } - } - for (auto &opcodeAMD64 : kOpcodesAMD64) { - if (ParserKit::find_word(line, opcodeAMD64.fName)) { - return err_str; - } - } - - err_str += "\nUnrecognized instruction -> " + line; - - return err_str; -} - -bool CompilerKit::EncoderAMD64::WriteNumber(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast64 num = CompilerKit::NumberCast64( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber32(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 10); - res += kOrigin; - - if (errno != 0) { - return false; - } - - CompilerKit::NumberCast32 num = CompilerKit::NumberCast32(res); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber16(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast16 num = CompilerKit::NumberCast16( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - for (char &i : num.number) { - if (i == 0) i = 0xFF; - - kAppBytes.push_back(i); - } - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -bool CompilerKit::EncoderAMD64::WriteNumber8(const std::size_t &pos, - std::string &jump_label) { - if (!isdigit(jump_label[pos])) return false; - - switch (jump_label[pos + 1]) { - case 'x': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16); - !res) { - if (errno != 0) { - detail::print_error("invalid hex number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_hex"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 16)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 16 number here: " - << jump_label.substr(pos) << "\n"; - } - - return true; - } - case 'b': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2); - !res) { - if (errno != 0) { - detail::print_error("invalid binary number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_bin"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 2)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 2 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - case 'o': { - if (auto res = strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7); - !res) { - if (errno != 0) { - detail::print_error("invalid octal number: " + jump_label, "i64asm"); - throw std::runtime_error("invalid_octal"); - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos + 2).c_str(), nullptr, 7)); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 8 number here: " - << jump_label.substr(pos) << "\n"; - } - - kAppBytes.push_back(num.number); - - return true; - } - default: { - break; - } - } - - /* check for errno and stuff like that */ - if (auto res = strtol(jump_label.substr(pos).c_str(), nullptr, 10); !res) { - if (errno != 0) { - return false; - } - } - - CompilerKit::NumberCast8 num = CompilerKit::NumberCast8( - strtol(jump_label.substr(pos).c_str(), nullptr, 10)); - - kAppBytes.push_back(num.number); - - if (kVerbose) { - kStdOut << "i64asm: Found a base 10 number here: " << jump_label.substr(pos) - << "\n"; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -// @brief Read and write an instruction to the output array. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerKit::EncoderAMD64::WriteLine(std::string &line, - const std::string &file) { - if (ParserKit::find_word(line, "export ")) return true; - - struct RegMapAMD64 { - std::string fName; - i64_byte_t fModRM; - }; - - std::vector<RegMapAMD64> REGISTER_LIST{ - {.fName = "ax", .fModRM = 0x0}, {.fName = "cx", .fModRM = 1}, - {.fName = "dx", .fModRM = 0x2}, {.fName = "bx", .fModRM = 3}, - {.fName = "sp", .fModRM = 0x4}, {.fName = "bp", .fModRM = 5}, - {.fName = "si", .fModRM = 0x6}, {.fName = "di", .fModRM = 7}, - {.fName = "r8", .fModRM = 8}, {.fName = "r13", .fModRM = 9}, - {.fName = "r9", .fModRM = 10}, {.fName = "r14", .fModRM = 11}, - {.fName = "r10", .fModRM = 12}, {.fName = "r15", .fModRM = 13}, - {.fName = "r11", .fModRM = 14}, - }; - - bool foundInstruction = false; - - for (auto &opcodeAMD64 : kOpcodesAMD64) { - // strict check here - if (ParserKit::find_word(line, opcodeAMD64.fName) && - detail::algorithm::is_valid(line)) { - foundInstruction = true; - std::string name(opcodeAMD64.fName); - - /// Move instruction handler. - if (name.find("mov") != std::string::npos) { - std::string substr = line.substr(line.find(name) + name.size()); - - uint64_t bits = kRegisterBitWidth; - - if (substr.find(",") == std::string::npos) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - bool onlyOneReg = true; - - std::vector<RegMapAMD64> currentRegList; - - for (auto ® : REGISTER_LIST) { - std::vector<char> regExt = {'e', 'r'}; - - for (auto &ext : regExt) { - std::string registerName; - - if (bits > 16) registerName.push_back(ext); - - registerName += reg.fName; - - while (line.find(registerName) != std::string::npos) { - line.erase(line.find(registerName), registerName.size()); - - if (bits == 16) { - if (registerName[0] == 'r') { - detail::print_error( - "invalid size for register, current bit width is: " + - std::to_string(kRegisterBitWidth), - file); - throw std::runtime_error("invalid_reg_size"); - } - } - - currentRegList.push_back( - {.fName = registerName, .fModRM = reg.fModRM}); - } - } - } - - if (currentRegList.size() > 1) onlyOneReg = false; - - bool hasRBasedRegs = false; - - if (!onlyOneReg) { - /// very tricky to understand. - /// this checks for a r8 through r15 register. - if (currentRegList[0].fName[0] == 'r' || - currentRegList[1].fName[0] == 'r') { - if (isdigit(currentRegList[0].fName[1]) && - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4d); - hasRBasedRegs = true; - } else if (isdigit(currentRegList[0].fName[1]) || - isdigit(currentRegList[1].fName[1])) { - kAppBytes.emplace_back(0x4c); - hasRBasedRegs = true; - } - } - } - - if (bits == 64 || bits == 32) { - if (!hasRBasedRegs && bits >= 32) { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - } - - kAppBytes.emplace_back(0x89); - } else if (bits == 16) { - if (hasRBasedRegs) { - detail::print_error( - "Invalid combination of operands and registers.", "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - kAppBytes.emplace_back(0x66); - kAppBytes.emplace_back(0x89); - } - - if (currentRegList[1].fName[0] == 'r' && - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[0].fName[0] == 'r' && - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (bits == 16) { - if (currentRegList[0].fName[0] == 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] == 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } else { - if (currentRegList[0].fName[0] != 'r' || - currentRegList[0].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - - if (currentRegList[1].fName[0] != 'r' || - currentRegList[1].fName[0] == 'e') { - detail::print_error("Invalid combination of operands and registers.", - "i64asm"); - throw std::runtime_error("comb_op_reg"); - } - } - - /// encode register using the modrm encoding. - - auto modrm = (0x3 << 6 | currentRegList[1].fModRM << 3 | - currentRegList[0].fModRM); - - kAppBytes.emplace_back(modrm); - - break; - } else if (name == "int" || name == "into" || name == "intd") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - this->WriteNumber8(line.find(name) + name.size() + 1, line); - - break; - } else if (name == "jmp" || name == "call") { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - if (!this->WriteNumber32(line.find(name) + name.size() + 1, line)) { - throw std::runtime_error("BUG: WriteNumber32"); - } - - break; - } else { - kAppBytes.emplace_back(opcodeAMD64.fOpcode); - - break; - } - } - } - - if (line[0] == kAssemblerPragmaSym) { - if (foundInstruction) { - detail::print_error("Syntax error.", "i64asm"); - throw std::runtime_error("syntax_err"); - } - - if (line.find("bits 64") != std::string::npos) { - kRegisterBitWidth = 64U; - } else if (line.find("bits 32") != std::string::npos) { - kRegisterBitWidth = 32U; - } else if (line.find("bits 16") != std::string::npos) { - kRegisterBitWidth = 16U; - } else if (line.find("org") != std::string::npos) { - size_t base[] = {10, 16, 2, 7}; - - for (size_t i = 0; i < 4; i++) { - if (kOrigin = strtol( - (line.substr(line.find("org") + strlen("org") + 1)).c_str(), - nullptr, base[i]); - kOrigin) { - if (errno != 0) { - continue; - } else { - if (kVerbose) { - kStdOut << "i64asm: origin set: " << kOrigin << std::endl; - } - - break; - } - } - } - } - } - /// write a dword - else if (line.find(".dword") != std::string::npos) { - this->WriteNumber32(line.find(".dword") + strlen(".dword") + 1, line); - } - /// write a long - else if (line.find(".long") != std::string::npos) { - this->WriteNumber(line.find(".long") + strlen(".long") + 1, line); - } - /// write a 16-bit number - else if (line.find(".word") != std::string::npos) { - this->WriteNumber16(line.find(".word") + strlen(".word") + 1, line); - } - - kOrigin += cAMD64IPAlignment; - - return true; -} - -// Last rev 13-1-24 diff --git a/Sources/link.cc b/Sources/link.cc deleted file mode 100644 index c44350a..0000000 --- a/Sources/link.cc +++ /dev/null @@ -1,641 +0,0 @@ -/* ------------------------------------------- - - Copyright Mahrouss Logic - -------------------------------------------- */ - -/// @file link.cc -/// @author Amlal El Mahrouss (amlel) -/// @brief Mahrouss Linker. - -/// Last Rev: Sat Feb 24 CET 2024 - -/// note: Do not look up for anything with .code64/.data64/.zero64! -/// It will be loaded when program will start up! - -#include <Headers/StdKit/ErrorID.hpp> - -//! Assembler Kit -#include <Headers/AsmKit/AsmKit.hpp> - -//! Preferred Executable Format -#include <Headers/StdKit/PEF.hpp> -#include <Headers/UUID.hpp> -#include <filesystem> -#include <random> -#include <vector> - -//! Dist version -#include <Headers/Version.hxx> - -//! Advanced Executable Object Format -#include <Headers/StdKit/AE.hpp> - -//! C++ I/O headers. -#include <fstream> -#include <iostream> - -#define kLinkerVersion "Mahrouss Linker %s, (c) Mahrouss Logic 2024\n" - -#define StringCompare(DST, SRC) strcmp(DST, SRC) - -#define kPefNoCpu 0U -#define kPefNoSubCpu 0U - -#define kWhite "\e[0;97m" -#define kStdOut (std::cout << kWhite) - -#define kLinkerDefaultOrigin kPefBaseOrigin -#define kLinkerId 0x5046FF -#define kLinkerAbiContainer "Container:Abi:" - -enum { kStandardAbi = 0x5046 /* PF */ }; - -static std::string kOutput; -static Int32 kAbi = kStandardAbi; -static Int32 kSubArch = kPefNoSubCpu; -static Int32 kArch = CompilerKit::kPefArch64000; -static Bool kFatBinaryEnable = false; -static Bool kStartFound = false; -static Bool kDuplicateSymbols = false; -static Bool kVerbose = false; - -/* link is to be found, mld is to be found at runtime. */ -static const char *kLdDefineSymbol = ":UndefinedSymbol:"; -static const char *kLdDynamicSym = ":RuntimeSymbol:"; - -/* object code and list. */ -static std::vector<std::string> kObjectList; -static std::vector<char> kObjectBytes; - -#define kPrintF printf -#define kLinkerSplash() kPrintF(kWhite kLinkerVersion, kDistVersion) - -MPCC_MODULE(NewOSLinker) { - bool is_executable = true; - - /** - * @brief parse flags and such. - * - */ - for (size_t i = 1; i < argc; ++i) { - if (StringCompare(argv[i], "-h") == 0) { - kLinkerSplash(); - kStdOut << "-version: Show program version.\n"; - kStdOut << "-verbose: Enable program trace.\n"; - kStdOut << "-shared: Output as a shared PEF.\n"; - kStdOut << "-fat-bin: Output as FAT PEF.\n"; - kStdOut << "-32x0: Output as 32x0 PEF.\n"; - kStdOut << "-64x0: Output as 64x0 PEF.\n"; - kStdOut << "-amd64: Output as AMD64 PEF.\n"; - kStdOut << "-rv64: Output as RISC-V 64 PEF.\n"; - kStdOut << "-ppc64: Output as POWER 64 PEF.\n"; - kStdOut << "-output-file: Select output file name.\n"; - - return 0; - } else if (StringCompare(argv[i], "-v") == 0) { - kLinkerSplash(); - return 0; - } else if (StringCompare(argv[i], "-fat-bin") == 0) { - kFatBinaryEnable = true; - - continue; - } else if (StringCompare(argv[i], "-64x0") == 0) { - kArch = CompilerKit::kPefArch64000; - - continue; - } else if (StringCompare(argv[i], "-amd64") == 0) { - kArch = CompilerKit::kPefArchAMD64; - - continue; - } else if (StringCompare(argv[i], "-32x0") == 0) { - kArch = CompilerKit::kPefArch32000; - - continue; - } else if (StringCompare(argv[i], "-power64") == 0) { - kArch = CompilerKit::kPefArchPowerPC; - - continue; - } else if (StringCompare(argv[i], "-verbose") == 0) { - kVerbose = true; - - continue; - } else if (StringCompare(argv[i], "-shared") == 0) { - if (kOutput.empty()) { - continue; - } - - if (kOutput.find(kPefExt) != std::string::npos) - kOutput.erase(kOutput.find(kPefExt), strlen(kPefExt)); - - kOutput += kPefDylibExt; - - is_executable = false; - - continue; - } else if (StringCompare(argv[i], "-output-file") == 0) { - kOutput = argv[i + 1]; - ++i; - - continue; - } else { - if (argv[i][0] == '-') { - kStdOut << "link: unknown flag: " << argv[i] << "\n"; - return -MPCC_EXEC_ERROR; - } - - kObjectList.emplace_back(argv[i]); - - continue; - } - } - - if (kOutput.empty()) { - kStdOut << "link: no output filename set." << std::endl; - return MPCC_EXEC_ERROR; - } - - // sanity check. - if (kObjectList.empty()) { - kStdOut << "link: no input files." << std::endl; - return MPCC_EXEC_ERROR; - } else { - // check for existing files, if they don't throw an error. - for (auto &obj : kObjectList) { - if (!std::filesystem::exists(obj)) { - // if filesystem doesn't find file - // -> throw error. - kStdOut << "link: no such file: " << obj << std::endl; - return MPCC_EXEC_ERROR; - } - } - } - - // PEF expects a valid architecture when outputing a binary. - if (kArch == 0) { - kStdOut << "link: no target architecture set, can't continue." << std::endl; - return MPCC_EXEC_ERROR; - } - - CompilerKit::PEFContainer pef_container{}; - - int32_t archs = kArch; - - pef_container.Count = 0UL; - pef_container.Kind = CompilerKit::kPefKindExec; - pef_container.SubCpu = kSubArch; - pef_container.Linker = kLinkerId; // Mahrouss Logic Linker - pef_container.Abi = kAbi; // Multi-Processor UX ABI - pef_container.Magic[0] = kPefMagic[kFatBinaryEnable ? 2 : 0]; - pef_container.Magic[1] = kPefMagic[1]; - pef_container.Magic[2] = kPefMagic[kFatBinaryEnable ? 0 : 2]; - pef_container.Magic[3] = kPefMagic[3]; - pef_container.Version = kPefVersion; - - // specify the start address, can be 0x10000 - pef_container.Start = kLinkerDefaultOrigin; - pef_container.HdrSz = sizeof(CompilerKit::PEFContainer); - - std::ofstream outputFc(kOutput, std::ofstream::binary); - - if (outputFc.bad()) { - if (kVerbose) { - kStdOut << "link: error: " << strerror(errno) << "\n"; - } - - return -MPCC_FILE_NOT_FOUND; - } - - //! Read AE to convert as PEF. - - std::vector<CompilerKit::PEFCommandHeader> commandHdrsList; - CompilerKit::Utils::AEReadableProtocol readProto{}; - - for (const auto &i : kObjectList) { - if (!std::filesystem::exists(i)) continue; - - CompilerKit::AEHeader hdr{}; - - readProto.FP = std::ifstream(i, std::ifstream::binary); - readProto.FP >> hdr; - - auto ae_header = hdr; - - if (ae_header.fMagic[0] == kAEMag0 && ae_header.fMagic[1] == kAEMag1 && - ae_header.fSize == sizeof(CompilerKit::AEHeader)) { - if (ae_header.fArch != kArch) { - if (kVerbose) kStdOut << "link: info: is this a FAT binary? : "; - - if (!kFatBinaryEnable) { - if (kVerbose) kStdOut << "No.\n"; - - kStdOut << "link: error: object " << i - << " is a different kind of architecture and output isn't " - "treated as a FAT binary." - << std::endl; - - std::remove(kOutput.c_str()); - return -MPCC_FAT_ERROR; - } else { - if (kVerbose) { - kStdOut << "Yes.\n"; - } - } - } - - // append arch type to archs varaible. - archs |= ae_header.fArch; - std::size_t cnt = ae_header.fCount; - - if (kVerbose) - kStdOut << "link: object header found, record count: " << cnt << "\n"; - - pef_container.Count = cnt; - - char_type *raw_ae_records = - new char_type[cnt * sizeof(CompilerKit::AERecordHeader)]; - memset(raw_ae_records, 0, cnt * sizeof(CompilerKit::AERecordHeader)); - - auto *ae_records = readProto.Read(raw_ae_records, cnt); - for (size_t ae_record_index = 0; ae_record_index < cnt; - ++ae_record_index) { - CompilerKit::PEFCommandHeader command_header{0}; - size_t offsetOfData = ae_records[ae_record_index].fOffset + ae_header.fSize; - - memcpy(command_header.Name, ae_records[ae_record_index].fName, - kPefNameLen); - - // check this header if it's any valid. - if (std::string(command_header.Name).find(".code64") == - std::string::npos && - std::string(command_header.Name).find(".data64") == - std::string::npos && - std::string(command_header.Name).find(".zero64") == - std::string::npos) { - if (std::string(command_header.Name).find(kPefStart) == - std::string::npos && - *command_header.Name == 0) { - if (std::string(command_header.Name).find(kLdDefineSymbol) != - std::string::npos) { - goto ld_mark_header; - } else { - continue; - } - } - } - - if (std::string(command_header.Name).find(kPefStart) != - std::string::npos && - std::string(command_header.Name).find(".code64") != - std::string::npos) { - kStartFound = true; - } - - ld_mark_header: - command_header.Offset = offsetOfData; - command_header.Kind = ae_records[ae_record_index].fKind; - command_header.Size = ae_records[ae_record_index].fSize; - command_header.Cpu = ae_header.fArch; - command_header.SubCpu = ae_header.fSubArch; - - if (kVerbose) { - kStdOut << "link: object record: " - << ae_records[ae_record_index].fName << " was marked.\n"; - - kStdOut << "link: object record offset: " << command_header.Offset << "\n"; - } - - commandHdrsList.emplace_back(command_header); - } - - delete[] raw_ae_records; - - std::vector<char> bytes; - bytes.resize(ae_header.fCodeSize); - - readProto.FP.seekg(std::streamsize(ae_header.fStartCode)); - readProto.FP.read(bytes.data(), std::streamsize(ae_header.fCodeSize)); - - for (auto &byte : bytes) { - kObjectBytes.push_back(byte); - } - - readProto.FP.close(); - - continue; - } - - kStdOut << "link: not an object: " << i << std::endl; - std::remove(kOutput.c_str()); - - // don't continue, it is a fatal error. - return -MPCC_EXEC_ERROR; - } - - pef_container.Cpu = archs; - - outputFc << pef_container; - - if (kVerbose) { - kStdOut << "link: wrote container header.\n"; - } - - outputFc.seekp(std::streamsize(pef_container.HdrSz)); - - std::vector<std::string> not_found; - std::vector<std::string> symbols; - - // step 2: check for errors (multiple symbols, undefined ones) - - for (auto &commandHdr : commandHdrsList) { - // check if this symbol needs to be resolved. - if (std::string(commandHdr.Name).find(kLdDefineSymbol) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDynamicSym) == std::string::npos) { - if (kVerbose) - kStdOut << "link: found undefined symbol: " << commandHdr.Name << "\n"; - - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it == not_found.end()) { - not_found.emplace_back(commandHdr.Name); - } - } - - symbols.emplace_back(commandHdr.Name); - } - - // Now try to solve these symbols. - - for (size_t not_found_idx = 0; not_found_idx < commandHdrsList.size(); - ++not_found_idx) { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdrsList[not_found_idx].Name)); - it != not_found.end()) { - std::string symbol_imp = *it; - - if (symbol_imp.find(kLdDefineSymbol) == std::string::npos) continue; - - // erase the lookup prefix. - symbol_imp.erase( - 0, symbol_imp.find(kLdDefineSymbol) + strlen(kLdDefineSymbol)); - - // demangle everything. - while (symbol_imp.find('$') != std::string::npos) - symbol_imp.erase(symbol_imp.find('$'), 1); - - // the reason we do is because, this may not match the symbol, and we need - // to look for other matching symbols. - for (auto &commandHdr : commandHdrsList) { - if (std::string(commandHdr.Name).find(symbol_imp) != - std::string::npos && - std::string(commandHdr.Name).find(kLdDefineSymbol) == - std::string::npos) { - std::string undefined_symbol = commandHdr.Name; - auto result_of_sym = - undefined_symbol.substr(undefined_symbol.find(symbol_imp)); - - for (int i = 0; result_of_sym[i] != 0; ++i) { - if (result_of_sym[i] != symbol_imp[i]) goto ld_continue_search; - } - - not_found.erase(it); - - if (kVerbose) - kStdOut << "link: found symbol: " << commandHdr.Name << "\n"; - - break; - } - } - - ld_continue_search: - continue; - } - } - - // step 3: check for errors (recheck if we have those symbols.) - - if (!kStartFound && is_executable) { - if (kVerbose) - kStdOut - << "link: undefined entrypoint: " << kPefStart << ", you may have forget to link " - "against your compiler's runtime library.\n"; - - kStdOut << "link: undefined entrypoint " << kPefStart - << " for executable: " << kOutput << "\n"; - } - - // step 4: write all PEF commands. - - CompilerKit::PEFCommandHeader dateHeader{}; - - time_t timestamp = time(nullptr); - - std::string timeStampStr = "Container:BuildEpoch:"; - timeStampStr += std::to_string(timestamp); - - strcpy(dateHeader.Name, timeStampStr.c_str()); - - dateHeader.Flags = 0; - dateHeader.Kind = CompilerKit::kPefZero; - dateHeader.Offset = outputFc.tellp(); - dateHeader.Size = timeStampStr.size(); - - commandHdrsList.push_back(dateHeader); - - CompilerKit::PEFCommandHeader abiHeader{}; - - std::string abi = kLinkerAbiContainer; - - switch (kArch) { - case CompilerKit::kPefArchAMD64: { - abi += "MSFT"; - break; - } - case CompilerKit::kPefArchPowerPC: { - abi += "SYSV"; - break; - } - case CompilerKit::kPefArch32000: - case CompilerKit::kPefArch64000: { - abi += "MHRA"; - break; - } - default: { - abi += " IDK"; - break; - } - } - - memcpy(abiHeader.Name, abi.c_str(), abi.size()); - - abiHeader.Size = abi.size(); - abiHeader.Offset = outputFc.tellp(); - abiHeader.Flags = 0; - abiHeader.Kind = CompilerKit::kPefLinkerID; - - commandHdrsList.push_back(abiHeader); - - CompilerKit::PEFCommandHeader uuidHeader{}; - - std::random_device rd; - - auto seedData = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seedData), std::end(seedData), std::ref(rd)); - std::seed_seq seq(std::begin(seedData), std::end(seedData)); - std::mt19937 generator(seq); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid id = gen(); - auto uuidStr = uuids::to_string(id); - - memcpy(uuidHeader.Name, "Container:GUID:4:", strlen("Container:GUID:4:")); - memcpy(uuidHeader.Name + strlen("Container:GUID:4:"), uuidStr.c_str(), - uuidStr.size()); - - uuidHeader.Size = 16; - uuidHeader.Offset = outputFc.tellp(); - uuidHeader.Flags = 0; - uuidHeader.Kind = CompilerKit::kPefZero; - - commandHdrsList.push_back(uuidHeader); - - // prepare a symbol vector. - std::vector<std::string> undefSymbols; - std::vector<std::string> duplSymbols; - std::vector<std::string> resolveSymbols; - - constexpr Int32 cPaddingOffset = 16; - - size_t previousOffset = (commandHdrsList.size() * sizeof(CompilerKit::PEFCommandHeader)) + cPaddingOffset; - - // Finally write down the command headers. - // And check for any duplications - for (size_t commandHeaderIndex = 0UL; - commandHeaderIndex < commandHdrsList.size(); ++commandHeaderIndex) { - if (std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[commandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) { - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - std::string symbolName = commandHdrsList[commandHeaderIndex].Name; - - if (!symbolName.empty()) { - undefSymbols.emplace_back(symbolName); - } - - commandHdrsList[commandHeaderIndex].Offset += previousOffset; - previousOffset += commandHdrsList[commandHeaderIndex].Size; - - std::string name = commandHdrsList[commandHeaderIndex].Name; - - /// so this is valid when we get to the entrypoint. - /// it is always a code64 container. And should equal to kPefStart as well. - /// this chunk of code updates the pef_container.Start with the updated offset. - if (name.find(kPefStart) != std::string::npos && - name.find(".code64") != std::string::npos) { - pef_container.Start = commandHdrsList[commandHeaderIndex].Offset; - auto tellCurPos = outputFc.tellp(); - - outputFc.seekp(0); - outputFc << pef_container; - - outputFc.seekp(tellCurPos); - } - - if (kVerbose) { - kStdOut << "link: command header name: " << - name << "\n"; - kStdOut << "link: real address of command header content: " << - commandHdrsList[commandHeaderIndex].Offset << "\n"; - } - - outputFc << commandHdrsList[commandHeaderIndex]; - - for (size_t subCommandHeaderIndex = 0UL; - subCommandHeaderIndex < commandHdrsList.size(); - ++subCommandHeaderIndex) { - if (subCommandHeaderIndex == commandHeaderIndex) continue; - - if (std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDefineSymbol) != std::string::npos && - std::string(commandHdrsList[subCommandHeaderIndex].Name) - .find(kLdDynamicSym) == std::string::npos) { - if (kVerbose) { - kStdOut << "link: ignore :UndefinedSymbol: command header...\n"; - } - - // ignore :UndefinedSymbol: headers, they do not contain code. - continue; - } - - auto &commandHdr = commandHdrsList[subCommandHeaderIndex]; - - if (commandHdr.Name == - std::string(commandHdrsList[commandHeaderIndex].Name)) { - if (std::find(duplSymbols.cbegin(), duplSymbols.cend(), - commandHdr.Name) == duplSymbols.cend()) { - duplSymbols.emplace_back(commandHdr.Name); - } - - if (kVerbose) - kStdOut << "link: found duplicate symbol: " << commandHdr.Name - << "\n"; - - kDuplicateSymbols = true; - } - } - } - - if (!duplSymbols.empty()) { - for (auto &symbol : duplSymbols) { - kStdOut << "link: multiple symbols of " << symbol << ".\n"; - } - - std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; - } - - // step 2.5: write program bytes. - - for (auto byte : kObjectBytes) { - outputFc << byte; - } - - if (kVerbose) kStdOut << "link: wrote contents of: " << kOutput << "\n"; - - // step 3: check if we have those symbols - - std::vector<std::string> unrefSyms; - - for (auto &commandHdr : commandHdrsList) { - if (auto it = std::find(not_found.begin(), not_found.end(), - std::string(commandHdr.Name)); - it != not_found.end()) { - unrefSyms.emplace_back(commandHdr.Name); - } - } - - if (!unrefSyms.empty()) { - for (auto &unreferenced_symbol : unrefSyms) { - kStdOut << "link: undefined symbol " << unreferenced_symbol << "\n"; - } - } - - if (!kStartFound || kDuplicateSymbols && std::filesystem::exists(kOutput) || - !unrefSyms.empty()) { - if (kVerbose) - kStdOut << "link: file: " << kOutput - << ", is corrupt, removing file...\n"; - - std::remove(kOutput.c_str()); - return -MPCC_EXEC_ERROR; - } - - return 0; -} - -// Last rev 13-1-24 diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc deleted file mode 100644 index 44489da..0000000 --- a/Sources/ppc-cc.cc +++ /dev/null @@ -1,1368 +0,0 @@ -/* - * ======================================================== - * - * cc - * Copyright Mahrouss Logic, all rights reserved. - * - * ======================================================== - */ - -#include <Headers/AsmKit/CPU/ppc.hpp> -#include <Headers/ParserKit.hpp> -#include <Headers/UUID.hpp> -#include <cstdio> -#include <filesystem> -#include <fstream> -#include <iostream> -#include <memory> -#include <random> -#include <string> -#include <utility> -#include <vector> - -#define kOk 0 - -/// @author Amlal El Mahrouss (amlel) -/// @file cc.cc -/// @brief POWER C Compiler. - -///////////////////// - -/// ANSI ESCAPE CODES - -///////////////////// - -#define kBlank "\e[0;30m" -#define kRed "\e[0;31m" -#define kWhite "\e[0;97m" - -///////////////////////////////////// - -/// INTERNAL STRUCT OF THE C COMPILER - -///////////////////////////////////// - -namespace detail { -// \brief name to register struct. -struct CompilerRegisterMap final { - std::string fName; - std::string fReg; -}; - -// \brief Map for C structs -// \author amlel -struct CompilerStructMap final { - /// 'struct::my_foo' - std::string fName; - - /// if instance: stores a valid register. - std::string fReg; - - /// offset count - std::size_t fOffsetsCnt; - - /// offset array. - std::vector<std::pair<Int32, std::string>> fOffsets; -}; - -struct CompilerState final { - std::vector<ParserKit::SyntaxLeafList> fSyntaxTreeList; - std::vector<CompilerRegisterMap> kStackFrame; - std::vector<CompilerStructMap> kStructMap; - ParserKit::SyntaxLeafList *fSyntaxTree{nullptr}; - std::unique_ptr<std::ofstream> fOutputAssembly; - std::string fLastFile; - std::string fLastError; - bool fVerbose; -}; -} // namespace detail - -static detail::CompilerState kState; -static SizeType kErrorLimit = 100; -static std::string kIfFunction = ""; -static Int32 kAcceptableErrors = 0; - -namespace detail { -void print_error(std::string reason, std::string file) noexcept { - if (reason[0] == '\n') reason.erase(0, 1); - - if (file.find(".pp") != std::string::npos) file.erase(file.find(".pp"), 3); - - if (kState.fLastFile != file) { - std::cout << kRed << "[ cc ] " << kWhite - << ((file == "cc") ? "internal compiler error " - : ("in file, " + file)) - << kBlank << std::endl; - std::cout << kRed << "[ cc ] " << kWhite << reason << kBlank << std::endl; - - kState.fLastFile = file; - } else { - std::cout << kRed << "[ cc ] [ " << kState.fLastFile << " ] " << kWhite - << reason << kBlank << std::endl; - } - - if (kAcceptableErrors > kErrorLimit) std::exit(3); - - ++kAcceptableErrors; -} - -struct CompilerType final { - std::string fName; - std::string fValue; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// Target architecture. -static int kMachine = 0; - -///////////////////////////////////////// - -// REGISTERS ACCORDING TO USED ASSEMBLER - -///////////////////////////////////////// - -static size_t kRegisterCnt = kAsmRegisterLimit; -static size_t kStartUsable = 2; -static size_t kUsableLimit = 15; -static size_t kRegisterCounter = kStartUsable; -static std::string kRegisterPrefix = kAsmRegisterPrefix; - -///////////////////////////////////////// - -// COMPILER PARSING UTILITIES/STATES. - -///////////////////////////////////////// - -static std::vector<std::string> kFileList; -static CompilerKit::AssemblyFactory kFactory; -static bool kInStruct = false; -static bool kOnWhileLoop = false; -static bool kOnForLoop = false; -static bool kInBraces = false; -static bool kIfFound = false; -static size_t kBracesCount = 0UL; - -/* @brief C compiler backend for C */ -class CompilerBackendCLang final : public ParserKit::CompilerBackend { - public: - explicit CompilerBackendCLang() = default; - ~CompilerBackendCLang() override = default; - - MPCC_COPY_DEFAULT(CompilerBackendCLang); - - std::string Check(const char *text, const char *file); - bool Compile(const std::string &text, const char *file) override; - - const char *Language() override { return "POWER C"; } -}; - -static CompilerBackendCLang *kCompilerBackend = nullptr; -static std::vector<detail::CompilerType> kCompilerVariables; -static std::vector<std::string> kCompilerFunctions; -static std::vector<detail::CompilerType> kCompilerTypes; - -namespace detail { -union number_cast final { - public: - number_cast(UInt64 _Raw) : _Raw(_Raw) {} - - public: - char _Num[8]; - UInt64 _Raw; -}; - -union double_cast final { - public: - double_cast(float _Raw) : _Raw(_Raw) {} - - public: - char _Sign; - char _Lh[8]; - char _Rh[23]; - - float _Raw; -}; -} // namespace detail - -///////////////////////////////////////////////////////////////////////////////////////// - -// @name Compile -// @brief Generate MASM from a C assignement. - -///////////////////////////////////////////////////////////////////////////////////////// - -bool CompilerBackendCLang::Compile(const std::string &text, const char *file) { - std::string textBuffer = text; - - bool typeFound = false; - bool fnFound = false; - - // setup generator. - std::random_device rd; - - auto seed_data = std::array<int, std::mt19937::state_size>{}; - std::generate(std::begin(seed_data), std::end(seed_data), std::ref(rd)); - std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); - std::mt19937 generator(seq); - - // start parsing - for (size_t text_index = 0; text_index < textBuffer.size(); ++text_index) { - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - - auto gen = uuids::uuid_random_generator{generator}; - uuids::uuid out = gen(); - - detail::number_cast time_off = (UInt64)out.as_bytes().data(); - - if (!typeFound) { - auto substr = textBuffer.substr(text_index); - std::string match_type; - - for (size_t y = 0; y < substr.size(); ++y) { - if (substr[y] == ' ') { - while (match_type.find(' ') != std::string::npos) { - match_type.erase(match_type.find(' ')); - } - - for (auto &clType : kCompilerTypes) { - if (clType.fName == match_type) { - match_type.clear(); - - std::string buf; - - buf += clType.fValue; - buf += ' '; - - if (substr.find('=') != std::string::npos) { - break; - } - - if (textBuffer.find('(') != std::string::npos) { - syntaxLeaf.fUserValue = buf; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - typeFound = true; - break; - } - } - - break; - } - - match_type += substr[y]; - } - } - - if (textBuffer[text_index] == '{') { - if (kInStruct) { - continue; - } - - kInBraces = true; - ++kBracesCount; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // return keyword handler - if (textBuffer[text_index] == 'r') { - std::string return_keyword; - return_keyword += "return"; - - std::size_t index = 0UL; - - std::string value; - - for (size_t return_index = text_index; return_index < textBuffer.size(); - ++return_index) { - if (textBuffer[return_index] != return_keyword[index]) { - for (size_t value_index = return_index; - value_index < textBuffer.size(); ++value_index) { - if (textBuffer[value_index] == ';') break; - - value += textBuffer[value_index]; - } - - break; - } - - ++index; - } - - if (index == return_keyword.size()) { - if (!value.empty()) { - if (value.find('(') != std::string::npos) { - value.erase(value.find('(')); - } - - if (!isdigit(value[value.find('(') + 2])) { - std::string tmp = value; - bool reg_to_reg = false; - - value.clear(); - - value += " import"; - value += tmp; - } - - syntaxLeaf.fUserValue = "\tmr r31, "; - - // make it pretty. - while (value.find('\t') != std::string::npos) - value.erase(value.find('\t'), 1); - - while (value.find(' ') != std::string::npos) - value.erase(value.find(' '), 1); - - while (value.find("import") != std::string::npos) - value.erase(value.find("import"), strlen("import")); - - bool found = false; - - for (auto ® : kState.kStackFrame) { - if (value.find(reg.fName) != std::string::npos) { - found = true; - syntaxLeaf.fUserValue += reg.fReg; - break; - } - } - - if (!found) syntaxLeaf.fUserValue += "r0"; - } - - syntaxLeaf.fUserValue += "\n\tblr"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - break; - } - } - - if (textBuffer[text_index] == 'i' && textBuffer[text_index + 1] == 'f') { - auto expr = textBuffer.substr(text_index + 2); - textBuffer.erase(text_index, 2); - - if (expr.find("{") != std::string::npos) { - expr.erase(expr.find("{")); - } - - if (expr.find("(") != std::string::npos) expr.erase(expr.find("(")); - - if (expr.find(")") != std::string::npos) expr.erase(expr.find(")")); - - kIfFunction = "__MPCC_IF_PROC_"; - kIfFunction += std::to_string(time_off._Raw); - - syntaxLeaf.fUserValue = - "\tcmpw " - "r10, r11"; - - syntaxLeaf.fUserValue += "\n\tbeq import " + kIfFunction + - " \ndword export .code64 " + kIfFunction + "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - kIfFound = true; - } - - // Parse expressions and instructions here. - // what does this mean? - // we encounter an assignment, or we reached the end of an expression. - if (textBuffer[text_index] == '=' || textBuffer[text_index] == ';') { - if (fnFound) continue; - if (kIfFound) continue; - - if (textBuffer[text_index] == ';' && kInStruct) continue; - - if (textBuffer.find("typedef ") != std::string::npos) continue; - - if (textBuffer[text_index] == '=' && kInStruct) { - detail::print_error( - "assignement of value inside a struct " + textBuffer, file); - continue; - } - - if (textBuffer[text_index] == ';' && kInStruct) { - bool space_found_ = false; - std::string sym; - - for (auto &ch : textBuffer) { - if (ch == ' ') { - space_found_ = true; - } - - if (ch == ';') break; - - if (space_found_) sym.push_back(ch); - } - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsets.push_back( - std::make_pair( - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4, - sym)); - - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt = - kState.kStructMap[kState.kStructMap.size() - 1].fOffsetsCnt + 4; - - continue; - } - - if (textBuffer[text_index] == '=' && kInStruct) { - continue; - } - - if (textBuffer[text_index + 1] == '=' || - textBuffer[text_index - 1] == '!' || - textBuffer[text_index - 1] == '<' || - textBuffer[text_index - 1] == '>') { - continue; - } - - std::string substr; - - if (textBuffer.find('=') != std::string::npos && kInBraces && !kIfFound) { - if (textBuffer.find("*") != std::string::npos) { - if (textBuffer.find("=") > textBuffer.find("*")) - substr += "\tli "; - else - substr += "\tli "; - } else { - substr += "\tli "; - } - } else if (textBuffer.find('=') != std::string::npos && !kInBraces) { - substr += "stw export .data64 "; - } - - int first_encountered = 0; - - std::string str_name; - - for (size_t text_index_2 = 0; text_index_2 < textBuffer.size(); - ++text_index_2) { - if (textBuffer[text_index_2] == '\"') { - ++text_index_2; - - // want to add this, so that the parser recognizes that this is a - // string. - substr += '"'; - - for (; text_index_2 < textBuffer.size(); ++text_index_2) { - if (textBuffer[text_index_2] == '\"') break; - - substr += textBuffer[text_index_2]; - } - } - - if (textBuffer[text_index_2] == '{' || textBuffer[text_index_2] == '}') - continue; - - if (textBuffer[text_index_2] == ';') { - break; - } - - if (textBuffer[text_index_2] == ' ' || - textBuffer[text_index_2] == '\t') { - if (first_encountered != 2) { - if (textBuffer[text_index] != '=' && - substr.find("export .data64") == std::string::npos && - !kInStruct) - substr += "export .data64 "; - } - - ++first_encountered; - - continue; - } - - if (textBuffer[text_index_2] == '=') { - if (!kInBraces) { - substr.replace(substr.find("export .data64"), - strlen("export .data64"), "export .zero64 "); - } - - substr += ","; - continue; - } - - substr += textBuffer[text_index_2]; - } - - for (auto &clType : kCompilerTypes) { - if (substr.find(clType.fName) != std::string::npos) { - if (substr.find(clType.fName) > substr.find('"')) continue; - - substr.erase(substr.find(clType.fName), clType.fName.size()); - } else if (substr.find(clType.fValue) != std::string::npos) { - if (substr.find(clType.fValue) > substr.find('"')) continue; - - if (clType.fName == "const") continue; - - substr.erase(substr.find(clType.fValue), clType.fValue.size()); - } - } - - if (substr.find("extern") != std::string::npos) { - substr.replace(substr.find("extern"), strlen("extern"), "import "); - - if (substr.find("export .data64") != std::string::npos) - substr.erase(substr.find("export .data64"), strlen("export .data64")); - } - - auto var_to_find = - std::find_if(kCompilerVariables.cbegin(), kCompilerVariables.cend(), - [&](detail::CompilerType type) { - return type.fName.find(substr) != std::string::npos; - }); - - kCompilerVariables.push_back({.fName = substr}); - - if (textBuffer[text_index] == ';') break; - - std::string reg = kAsmRegisterPrefix; - - ++kRegisterCounter; - reg += std::to_string(kRegisterCounter); - - auto newSubstr = substr.substr(substr.find(" ")); - - std::string symbol; - - for (size_t start = 0; start < newSubstr.size(); ++start) { - if (newSubstr[start] == ',') break; - - if (newSubstr[start] == ' ') continue; - - symbol += (newSubstr[start]); - } - - kState.kStackFrame.push_back({.fName = symbol, .fReg = reg}); - - syntaxLeaf.fUserValue += - "\n\tli " + reg + substr.substr(substr.find(',')); - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - // function handler. - - if (textBuffer[text_index] == '(' && !fnFound && !kIfFound) { - std::string substr; - std::string args_buffer; - std::string args; - - bool type_crossed = false; - - for (size_t idx = textBuffer.find('(') + 1; idx < textBuffer.size(); - ++idx) { - if (textBuffer[idx] == ',') continue; - - if (textBuffer[idx] == ' ') continue; - - if (textBuffer[idx] == ')') break; - } - - for (char substr_first_index : textBuffer) { - if (substr_first_index != ',') - args_buffer += substr_first_index; - else - args_buffer += '$'; - - if (substr_first_index == ';') { - args_buffer = args_buffer.erase(0, args_buffer.find('(')); - args_buffer = args_buffer.erase(args_buffer.find(';'), 1); - args_buffer = args_buffer.erase(args_buffer.find(')'), 1); - args_buffer = args_buffer.erase(args_buffer.find('('), 1); - - if (!args_buffer.empty()) args += "\tldw r6, "; - - std::string register_type; - std::size_t index = 7UL; - - while (args_buffer.find("$") != std::string::npos) { - register_type = kRegisterPrefix; - register_type += std::to_string(index); - - ++index; - - args_buffer.replace(args_buffer.find('$'), 1, - "\n\tldw " + register_type + ","); - } - - args += args_buffer; - args += "\n\tli r31, "; - } - } - - for (char _text_i : textBuffer) { - if (_text_i == '\t' || _text_i == ' ') { - if (!type_crossed) { - substr.clear(); - type_crossed = true; - } - - continue; - } - - if (_text_i == '(') break; - - substr += _text_i; - } - - if (kInBraces) { - syntaxLeaf.fUserValue = args; - syntaxLeaf.fUserValue += substr; - - syntaxLeaf.fUserValue += "\n\tblr\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } else { - syntaxLeaf.fUserValue.clear(); - - syntaxLeaf.fUserValue += "export .code64 "; - - syntaxLeaf.fUserValue += substr; - syntaxLeaf.fUserValue += "\n"; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - fnFound = true; - } - - kCompilerFunctions.push_back(textBuffer); - } - - if (textBuffer[text_index] == '-' && textBuffer[text_index + 1] == '-') { - textBuffer = textBuffer.replace(textBuffer.find("--"), strlen("--"), ""); - - for (int _text_i = 0; _text_i < textBuffer.size(); ++_text_i) { - if (textBuffer[_text_i] == '\t' || textBuffer[_text_i] == ' ') - textBuffer.erase(_text_i, 1); - } - - syntaxLeaf.fUserValue += "dec "; - syntaxLeaf.fUserValue += textBuffer; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - break; - } - - if (textBuffer[text_index] == '}') { - kRegisterCounter = kStartUsable; - - --kBracesCount; - - if (kBracesCount < 1) { - kInBraces = false; - kBracesCount = 0; - } - - if (kIfFound) kIfFound = false; - - if (kInStruct) kInStruct = false; - - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - } - - syntaxLeaf.fUserValue.clear(); - } - - auto syntaxLeaf = ParserKit::SyntaxLeafList::SyntaxLeaf(); - syntaxLeaf.fUserValue = "\n"; - kState.fSyntaxTree->fLeafList.push_back(syntaxLeaf); - - return true; -} - -static bool kShouldHaveBraces = false; -static std::string kFnName; - -std::string CompilerBackendCLang::Check(const char *text, const char *file) { - std::string err_str; - std::string ln = text; - - if (ln.empty()) { - return err_str; - } - - bool non_ascii_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (isalnum(ln[i])) { - non_ascii_found = true; - break; - } - } - - if (kShouldHaveBraces && ln.find('{') != std::string::npos) { - kShouldHaveBraces = false; - } - - if (!non_ascii_found) return err_str; - - size_t string_index = 1UL; - - if (ln.find('\'') != std::string::npos) { - string_index = ln.find('\'') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '\'') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } - - return err_str; - } - } - } else if (ln.find('"') != std::string::npos) { - string_index = ln.find('"') + 1; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == '"') { - if (ln[string_index + 1] != ';') { - ln.erase(string_index, 1); - } else { - break; - } - } - } - } else if (ln.find('"') == std::string::npos && - ln.find('\'') == std::string::npos) { - std::vector<std::string> forbidden_words; - - forbidden_words.push_back("\\"); - forbidden_words.push_back("?"); - forbidden_words.push_back("@"); - forbidden_words.push_back("~"); - forbidden_words.push_back("::"); - forbidden_words.push_back("/*"); - forbidden_words.push_back("*/"); - - // add them to avoid stupid mistakes. - forbidden_words.push_back("namespace"); - forbidden_words.push_back("class"); - forbidden_words.push_back("extern \"C\""); - - for (auto &forbidden : forbidden_words) { - if (ln.find(forbidden) != std::string::npos) { - err_str += "\nForbidden character detected: "; - err_str += forbidden; - - return err_str; - } - } - } - - struct CompilerVariableRange final { - std::string fBegin; - std::string fEnd; - }; - - const std::vector<CompilerVariableRange> variables_list = { - {.fBegin = "static ", .fEnd = "="}, {.fBegin = "=", .fEnd = ";"}, - {.fBegin = "if(", .fEnd = "="}, {.fBegin = "if (", .fEnd = "="}, - {.fBegin = "if(", .fEnd = "<"}, {.fBegin = "if (", .fEnd = "<"}, - {.fBegin = "if(", .fEnd = ">"}, {.fBegin = "if (", .fEnd = ">"}, - {.fBegin = "if(", .fEnd = ")"}, {.fBegin = "if (", .fEnd = ")"}, - - {.fBegin = "else(", .fEnd = "="}, {.fBegin = "else (", .fEnd = "="}, - {.fBegin = "else(", .fEnd = "<"}, {.fBegin = "else (", .fEnd = "<"}, - {.fBegin = "else(", .fEnd = ">"}, {.fBegin = "else (", .fEnd = ">"}, - {.fBegin = "else(", .fEnd = ")"}, {.fBegin = "else (", .fEnd = ")"}, - }; - - for (auto &variable : variables_list) { - if (ln.find(variable.fBegin) != std::string::npos) { - string_index = ln.find(variable.fBegin) + variable.fBegin.size(); - - while (ln[string_index] == ' ') ++string_index; - - std::string keyword; - - for (; string_index < ln.size(); ++string_index) { - if (ln[string_index] == variable.fEnd[0]) { - std::string varname = ""; - - for (size_t index_keyword = ln.find(' '); - ln[index_keyword] != variable.fBegin[0]; ++index_keyword) { - if (ln[index_keyword] == ' ') { - continue; - } - - if (isdigit(ln[index_keyword])) { - goto cc_next_loop; - } - - varname += ln[index_keyword]; - } - - if (varname.find(' ') != std::string::npos) { - varname.erase(0, varname.find(' ')); - - if (variable.fBegin == "extern") { - varname.erase(0, varname.find(' ')); - } - } - - if (kRegisterCounter == 5 || kRegisterCounter == 6) - ++kRegisterCounter; - - std::string reg = kAsmRegisterPrefix; - reg += std::to_string(kRegisterCounter); - - kCompilerVariables.push_back({.fValue = varname}); - goto cc_check_done; - } - - keyword.push_back(ln[string_index]); - } - - goto cc_next_loop; - - cc_check_done: - - // skip digit value. - if (isdigit(keyword[0]) || keyword[0] == '"') { - goto cc_next_loop; - } - - while (keyword.find(' ') != std::string::npos) - keyword.erase(keyword.find(' '), 1); - - for (auto &var : kCompilerVariables) { - if (var.fValue.find(keyword) != std::string::npos) { - err_str.clear(); - goto cc_next; - } - } - - for (auto &fn : kCompilerFunctions) { - if (fn.find(keyword[0]) != std::string::npos) { - auto where_begin = fn.find(keyword[0]); - auto keyword_begin = 0UL; - auto failed = false; - - for (; where_begin < keyword.size(); ++where_begin) { - if (fn[where_begin] == '(' && keyword[keyword_begin] == '(') break; - - if (fn[where_begin] != keyword[keyword_begin]) { - failed = true; - break; - } - - ++keyword_begin; - } - - if (!failed) { - err_str.clear(); - goto cc_next; - } else { - continue; - } - } - } - - cc_error_value: - if (keyword.find("->") != std::string::npos) return err_str; - - if (keyword.find(".") != std::string::npos) return err_str; - - if (isalnum(keyword[0])) err_str += "\nUndefined value: " + keyword; - - return err_str; - } - - cc_next_loop: - continue; - } - -cc_next: - - // extern does not declare anything, it imports a variable. - // so that's why it's not declare upper. - if (ParserKit::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 (ParserKit::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 && !ParserKit::find_word(ln, "|") && - !ParserKit::find_word(ln, "||") && !ParserKit::find_word(ln, "&") && - !ParserKit::find_word(ln, "&&") && !ParserKit::find_word(ln, "~")) { - bool found_func = false; - size_t i = ln.find('('); - std::vector<char> opens; - std::vector<char> closes; - - for (; i < ln.size(); ++i) { - if (ln[i] == ')') { - closes.push_back(1); - } - - if (ln[i] == '(') { - opens.push_back(1); - } - } - - if (closes.size() != opens.size()) - err_str += "Unterminated (), here -> " + ln; - - bool space_found = false; - - for (int i = 0; i < ln.size(); ++i) { - if (ln[i] == ')' && !space_found) { - space_found = true; - continue; - } - - if (space_found) { - if (ln[i] == ' ' && isalnum(ln[i + 1])) { - err_str += "\nBad function format here -> "; - err_str += ln; - } - } - } - } - - if (ln.find('(') < 1) { - err_str += "\nMissing identifier before '(' here -> "; - err_str += ln; - } else { - if (type_not_found && ln.find(';') == std::string::npos && - ln.find("if") == std::string::npos && - ln.find("|") == std::string::npos && - ln.find("&") == std::string::npos && - ln.find("(") == std::string::npos && - ln.find(")") == std::string::npos) { - err_str += "\n Missing ';' or type, here -> "; - err_str += ln; - } - } - - if (ln.find(')') == std::string::npos) { - err_str += "\nMissing ')', after '(' here -> "; - err_str += ln.substr(ln.find('(')); - } - } else { - if (ln.find("for") != std::string::npos || - ln.find("while") != std::string::npos) { - err_str += "\nMissing '(', after \"for\", here -> "; - err_str += ln; - } - } - - if (ln.find('}') != std::string::npos && !kInBraces) { - if (!kInStruct && ln.find(';') == std::string::npos) { - err_str += "\nMismatched '}', here -> "; - err_str += ln; - } - } - - if (!ln.empty()) { - if (ln.find(';') == std::string::npos && - ln.find('{') == std::string::npos && - ln.find('}') == std::string::npos && - ln.find(')') == std::string::npos && - ln.find('(') == std::string::npos && - ln.find(',') == std::string::npos) { - if (ln.size() <= 2) return err_str; - - err_str += "\nMissing ';', here -> "; - err_str += ln; - } - } - - return err_str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -/** - * @brief C To Assembly mount-point. - */ - -///////////////////////////////////////////////////////////////////////////////////////// - -class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { - public: - explicit AssemblyMountpointCLang() = default; - ~AssemblyMountpointCLang() override = default; - - MPCC_COPY_DEFAULT(AssemblyMountpointCLang); - - [[maybe_unused]] static Int32 Arch() noexcept { - return CompilerKit::AssemblyFactory::kArchPowerPC; - } - - Int32 CompileToFormat(std::string &src, Int32 arch) override { - if (arch != AssemblyMountpointCLang::Arch()) return -1; - - if (kCompilerBackend == nullptr) return -1; - - /* @brief copy contents wihtout extension */ - std::string src_file = src.data(); - std::ifstream src_fp = std::ifstream(src_file, std::ios::in); - std::string dest; - - for (auto &ch : src_file) { - if (ch == '.') { - break; - } - - dest += ch; - } - - /* According to PEF ABI. */ - std::vector<const char *> exts = kAsmFileExts; - dest += exts[4]; - - kState.fOutputAssembly = std::make_unique<std::ofstream>(dest); - - auto fmt = CompilerKit::current_date(); - - (*kState.fOutputAssembly) << "# Path: " << src_file << "\n"; - (*kState.fOutputAssembly) - << "# Language: POWER Assembly (Generated from C)\n"; - (*kState.fOutputAssembly) << "# Date: " << fmt << "\n\n"; - - ParserKit::SyntaxLeafList syntax; - - kState.fSyntaxTreeList.push_back(syntax); - kState.fSyntaxTree = - &kState.fSyntaxTreeList[kState.fSyntaxTreeList.size() - 1]; - - std::string line_src; - - while (std::getline(src_fp, line_src)) { - if (auto err = kCompilerBackend->Check(line_src.c_str(), src.data()); - err.empty()) { - kCompilerBackend->Compile(line_src, src.data()); - } else { - detail::print_error(err, src.data()); - } - } - - if (kAcceptableErrors > 0) return -1; - - std::vector<std::string> keywords = {"ld", "stw", "add", "sub", "or"}; - - /// - /// Replace, optimize, fix assembly output. - /// - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - std::vector<std::string> access_keywords = {"->", "."}; - - for (auto &access_ident : access_keywords) { - if (ParserKit::find_word(leaf.fUserValue, access_ident)) { - for (auto &struc : kState.kStructMap) { - /// TODO: - } - } - } - - for (auto &keyword : keywords) { - if (ParserKit::find_word(leaf.fUserValue, keyword)) { - std::size_t cnt = 0UL; - - for (auto ® : 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 (ParserKit::find_word(leaf.fUserValue, needle)) { - if (leaf.fUserValue.find("import ") != std::string::npos) { - std::string range = "import "; - leaf.fUserValue.replace(leaf.fUserValue.find(range), - range.size(), ""); - } - - if (leaf.fUserValue.find("ldw r6") != std::string::npos) { - std::string::difference_type countComma = std::count( - leaf.fUserValue.begin(), leaf.fUserValue.end(), ','); - - if (countComma == 1) { - leaf.fUserValue.replace(leaf.fUserValue.find("ldw"), - strlen("ldw"), "mr"); - } - } - - leaf.fUserValue.replace(leaf.fUserValue.find(needle), - needle.size(), reg.fReg); - - ++cnt; - } - } - - if (cnt > 1 && keyword != "mr" && keyword != "add" && - keyword != "dec") { - leaf.fUserValue.replace(leaf.fUserValue.find(keyword), - keyword.size(), "mr"); - } - } - } - } - - for (auto &leaf : kState.fSyntaxTree->fLeafList) { - (*kState.fOutputAssembly) << leaf.fUserValue; - } - - kState.fSyntaxTree = nullptr; - - kState.fOutputAssembly->flush(); - kState.fOutputAssembly.reset(); - - return kOk; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#include <Version.hxx> - -#define kPrintF printf -#define kSplashCxx() \ - kPrintF(kWhite "cc, %s, (c) Mahrouss Logic\n", kDistVersion) - -static void cc_print_help() { kSplashCxx(); } - -///////////////////////////////////////////////////////////////////////////////////////// - -#define kExt ".c" - -MPCC_MODULE(NewOSCompilerCLangPowerPC) { - kCompilerTypes.push_back({.fName = "void", .fValue = "void"}); - kCompilerTypes.push_back({.fName = "char", .fValue = "byte"}); - kCompilerTypes.push_back({.fName = "short", .fValue = "hword"}); - kCompilerTypes.push_back({.fName = "int", .fValue = "dword"}); - kCompilerTypes.push_back({.fName = "long", .fValue = "qword"}); - kCompilerTypes.push_back({.fName = "*", .fValue = "offset"}); - - bool skip = false; - - kFactory.Mount(new AssemblyMountpointCLang()); - kMachine = CompilerKit::AssemblyFactory::kArchPowerPC; - kCompilerBackend = new CompilerBackendCLang(); - - for (auto index = 1UL; index < argc; ++index) { - if (skip) { - skip = false; - continue; - } - - if (argv[index][0] == '-') { - if (strcmp(argv[index], "-v") == 0 || - strcmp(argv[index], "-version") == 0) { - kSplashCxx(); - return kOk; - } - - if (strcmp(argv[index], "-verbose") == 0) { - kState.fVerbose = true; - - continue; - } - - if (strcmp(argv[index], "-h") == 0 || strcmp(argv[index], "-help") == 0) { - cc_print_help(); - - return kOk; - } - - if (strcmp(argv[index], "-dialect") == 0) { - if (kCompilerBackend) std::cout << kCompilerBackend->Language() << "\n"; - - return kOk; - } - - if (strcmp(argv[index], "-fmax-exceptions") == 0) { - try { - kErrorLimit = std::strtol(argv[index + 1], nullptr, 10); - } - // catch anything here - catch (...) { - kErrorLimit = 0; - } - - skip = true; - - continue; - } - - std::string err = "Unknown command: "; - err += argv[index]; - - detail::print_error(err, "cc"); - - continue; - } - - kFileList.emplace_back(argv[index]); - - std::string srcFile = argv[index]; - - if (strstr(argv[index], kExt) == nullptr) { - if (kState.fVerbose) { - detail::print_error(srcFile + " is not a valid C source.\n", "cc"); - } - - return 1; - } - - if (kFactory.Compile(srcFile, kMachine) != kOk) return -1; - } - - return kOk; -} - -// Last rev 8-1-24 diff --git a/bpp.rsrc b/bpp.rsrc deleted file mode 100644 index 255f805..0000000 --- a/bpp.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS Assembler Preprocessor." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewPreprocessor" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "bpp.exe" - VALUE "ProductName", "NewPreprocessor" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/i64asm.rsrc b/i64asm.rsrc deleted file mode 100644 index 0a76070..0000000 --- a/i64asm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS AMD64 assembler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "i64asm.exe" - VALUE "ProductName", "NewAssembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/link.rsrc b/link.rsrc deleted file mode 100644 index 4a0ad5d..0000000 --- a/link.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS linker." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewLinker" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "link.exe" - VALUE "ProductName", "NewLinker" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END @@ -1,48 +1,49 @@ # # ======================================================== # - # MPCC - # Copyright Mahrouss Logic, all rights reserved. + # NDK + # Copyright ZKA Technologies, all rights reserved. # # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail -LINK_CC=g++ -std=c++20 -LINK_SRC=Sources/link.cc -LINK_OUTPUT=Output/link.exec -LINK_ALT_OUTPUT=Output/64link.exec -LINK_ALT_3_OUTPUT=Output/i64link.exec -LINK_ALT_2_OUTPUT=Output/32link.exec +COMMON_INC=-I./NDKKit -I./ -I./NDKKit/Sources/Detail +LINK_CC=clang++ -std=c++20 +LINK_SRC=NDKKit/Sources/link.cxx +LINK_OUTPUT=Output/link +LINK_ALT_OUTPUT=Output/64link +LINK_ALT_3_OUTPUT=Output/i64link +LINK_ALT_2_OUTPUT=Output/32link +LINK_ALT_4_OUTPUT=Output/ppclink -PP_SRC=Sources/bpp.cc -PP_OUTPUT=Output/bpp.exec +PP_SRC=NDKKit/Sources/bpp.cxx +PP_OUTPUT=Output/bpp -SRC_COMMON=Sources/String.cc Sources/AsmKit.cc +SRC_COMMON=NDKKit/Sources/String.cxx NDKKit/Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/amd64-cplusplus.cc $(SRC_COMMON) -AMD64_CXX_OUTPUT=Output/amd64-cplusplus.exec +AMD64_CXX_SRC=NDKKit/Sources/cplusplus.cxx $(SRC_COMMON) +AMD64_CXX_OUTPUT=Output/cplusplus # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cc $(SRC_COMMON) -64X0_CC_OUTPUT=Output/64x0-cc.exec +64X0_CC_SRC=NDKKit/Sources/64x0-cc.cxx $(SRC_COMMON) +64X0_CC_OUTPUT=Output/64x0-cc # C Compiler (Our own RISC) -PPC_CC_SRC=Sources/ppc-cc.cc $(SRC_COMMON) -PPC_CC_OUTPUT=Output/ppc-cc.exec +PPC_CC_SRC=NDKKit/Sources/power-cc.cxx $(SRC_COMMON) +PPC_CC_OUTPUT=Output/power-cc # 64x0 Assembler (Our Own RISC) -ASM_SRC=Sources/64asm.cc $(SRC_COMMON) -ASM_OUTPUT=Output/64asm.exec +ASM_SRC=NDKKit/Sources/64asm.cxx $(SRC_COMMON) +ASM_OUTPUT=Output/64asm # AMD64 Assembler (Intel CISC) -IASM_SRC=Sources/i64asm.cc $(SRC_COMMON) -IASM_OUTPUT=Output/i64asm.exec +IASM_SRC=NDKKit/Sources/i64asm.cxx $(SRC_COMMON) +IASM_OUTPUT=Output/i64asm # Power4 Assembler (IBM RISC) -PPCASM_SRC=Sources/ppcasm.cc $(SRC_COMMON) -PPCASM_OUTPUT=Output/ppcasm.exec +PPCASM_SRC=NDKKit/Sources/power-as.cxx $(SRC_COMMON) +PPCASM_OUTPUT=Output/power-as .PHONY: all all: pre-processor compiler linker @@ -67,12 +68,13 @@ linker: cp $(LINK_OUTPUT) $(LINK_ALT_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_2_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_3_OUTPUT) + cp $(LINK_OUTPUT) $(LINK_ALT_4_OUTPUT) .PHONY: help help: - @echo "Compiler - Mahrouss Compilers." - @echo "Preprocessor - Mahrouss Preprocessors." - @echo "linker - Mahrouss Linkers." + @echo "compiler - ZKA Technologies Compiler Suite." + @echo "pre-processor - ZKA Technologies Preprocessor Suite." + @echo "linker - ZKA Technologies Linkers." @echo "clean - Clean objects and executables." .PHONY: clean @@ -84,6 +86,5 @@ clean: rm -f $(IASM_OUTPUT) rm -f $(LINK_OUTPUT) rm -rf *.obj - rm -rf *.exec - + # Last rev 8-1-24 diff --git a/ppc-cc.rsrc b/ppc-cc.rsrc deleted file mode 100644 index ea941f1..0000000 --- a/ppc-cc.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS POWER C compiler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewC" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "ppc-cc.exe" - VALUE "ProductName", "NewC" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END diff --git a/ppcasm.rsrc b/ppcasm.rsrc deleted file mode 100644 index 552479f..0000000 --- a/ppcasm.rsrc +++ /dev/null @@ -1,27 +0,0 @@ -#include "Headers/Version.hxx" - -1 ICON "Icons/app-logo.ico" - -1 VERSIONINFO -FILEVERSION 1,0,0,0 -PRODUCTVERSION 1,0,0,0 -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "080904E4" - BEGIN - VALUE "CompanyName", "Mahrouss-Logic" - VALUE "FileDescription", "NewOS POWER assembler." - VALUE "FileVersion", kDistVersion - VALUE "InternalName", "NewAssembler" - VALUE "LegalCopyright", "Mahrouss-Logic" - VALUE "OriginalFilename", "ppcasm.exe" - VALUE "ProductName", "NewAssembler" - VALUE "ProductVersion", kDistVersion - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x809, 1252 - END -END @@ -1,49 +1,48 @@ # # ======================================================== # - # MPCC - # Copyright Mahrouss Logic, all rights reserved. + # NDK + # Copyright ZKA Technologies, all rights reserved. # # ======================================================== # -COMMON_INC=-I./Headers -I./ -I./Sources/Detail -LINK_CC=x86_64-w64-mingw32-g++.exe -std=c++20 -Xlinker -s -WINRES=x86_64-w64-mingw32-windres -LINK_SRC=Sources/link.cc +COMMON_INC=-I./NDKKit -I./ -I./NDKKit/Sources/Detail +LINK_CC=clang++ -std=c++20 -Xlinker -s +LINK_SRC=NDKKit/Sources/link.cxx LINK_OUTPUT=Output/link.exe LINK_ALT_OUTPUT=Output/64link.exe LINK_ALT_3_OUTPUT=Output/i64link.exe LINK_ALT_2_OUTPUT=Output/32link.exe -PP_SRC=Sources/bpp.cc +PP_SRC=NDKKit/Sources/bpp.cxx PP_OUTPUT=Output/bpp.exe -SRC_COMMON=Sources/String.cc Sources/AsmKit.cc +SRC_COMMON=NDKKit/Sources/String.cxx NDKKit/Sources/AssemblyFactory.cxx # C++ Compiler (AMD64) -AMD64_CXX_SRC=Sources/amd64-cplusplus.cc $(SRC_COMMON) -AMD64_CXX_OUTPUT=Output/amd64-cplusplus.exe +AMD64_CXX_SRC=NDKKit/Sources/cplusplus.cxx $(SRC_COMMON) +AMD64_CXX_OUTPUT=Output/cplusplus.exe # C Compiler (POWER) -64X0_CC_SRC=Sources/64x0-cc.cc $(SRC_COMMON) +64X0_CC_SRC=NDKKit/Sources/64x0-cc.cxx $(SRC_COMMON) 64X0_CC_OUTPUT=Output/64x0-cc.exe # C Compiler -PPC_CC_SRC=Sources/ppc-cc.cc $(SRC_COMMON) -PPC_CC_OUTPUT=Output/ppc-cc.exe +PPC_CC_SRC=NDKKit/Sources/power-cc.cxx $(SRC_COMMON) +PPC_CC_OUTPUT=Output/power-cc.exe # 64x0 Assembler -ASM_SRC=Sources/64asm.cc $(SRC_COMMON) +ASM_SRC=NDKKit/Sources/64asm.cxx $(SRC_COMMON) ASM_OUTPUT=Output/64asm.exe # AMD64 Assembler -IASM_SRC=Sources/i64asm.cc $(SRC_COMMON) +IASM_SRC=NDKKit/Sources/i64asm.cxx $(SRC_COMMON) IASM_OUTPUT=Output/i64asm.exe # POWER Assembler -PPCASM_SRC=Sources/ppcasm.cc $(SRC_COMMON) -PPCASM_OUTPUT=Output/ppcasm.exe +PPCASM_SRC=NDKKit/Sources/power-as.cxx $(SRC_COMMON) +PPCASM_OUTPUT=Output/power-as.exe .PHONY: all all: pre-processor compiler linker @@ -51,36 +50,29 @@ all: pre-processor compiler linker .PHONY: pre-processor pre-processor: - $(WINRES) bpp.rsrc -O coff -o bpp.obj - $(LINK_CC) $(COMMON_INC) $(PP_SRC) bpp.obj -o $(PP_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(PP_SRC) -o $(PP_OUTPUT) .PHONY: compiler compiler: - $(WINRES) i64asm.rsrc -O coff -o i64asm.obj - $(WINRES) 64asm.rsrc -O coff -o 64asm.obj - $(WINRES) ppcasm.rsrc -O coff -o ppcasm.obj - $(WINRES) 64x0-cc.rsrc -O coff -o 64x0-cc.obj - $(WINRES) ppc-cc.rsrc -O coff -o ppc-cc.obj - $(LINK_CC) $(COMMON_INC) 64x0-cc.obj $(64X0_CC_SRC) -o $(64X0_CC_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(64X0_CC_SRC) -o $(64X0_CC_OUTPUT) $(LINK_CC) $(COMMON_INC) $(AMD64_CXX_SRC) -o $(AMD64_CXX_OUTPUT) - $(LINK_CC) $(COMMON_INC) ppc-cc.obj $(PPC_CC_SRC) -o $(PPC_CC_OUTPUT) - $(LINK_CC) $(COMMON_INC) i64asm.obj $(IASM_SRC) -o $(IASM_OUTPUT) - $(LINK_CC) $(COMMON_INC) 64asm.obj $(ASM_SRC) -o $(ASM_OUTPUT) - $(LINK_CC) $(COMMON_INC) ppcasm.obj $(PPCASM_SRC) -o $(PPCASM_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(PPC_CC_SRC) -o $(PPC_CC_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(IASM_SRC) -o $(IASM_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(ASM_SRC) -o $(ASM_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(PPCASM_SRC) -o $(PPCASM_OUTPUT) .PHONY: linker linker: - $(WINRES) link.rsrc -O coff -o link.obj - $(LINK_CC) $(COMMON_INC) link.obj $(LINK_SRC) -o $(LINK_OUTPUT) + $(LINK_CC) $(COMMON_INC) $(LINK_SRC) -o $(LINK_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_2_OUTPUT) cp $(LINK_OUTPUT) $(LINK_ALT_3_OUTPUT) .PHONY: help help: - @echo "Compiler - Mahrouss Compilers." - @echo "Preprocessor - Mahrouss Preprocessors." - @echo "linker - Mahrouss Linkers." + @echo "compiler - ZKA Compiler Suite." + @echo "pre-processor - ZKA Preprocessor Suite." + @echo "linker - ZKA Linkers." @echo "clean - Clean objects and executables." .PHONY: clean |
