Compare commits
5 Commits
cf5ed7b601
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf724a8d13 | ||
| 5397965319 | |||
| 7876210be6 | |||
| 17baabbd95 | |||
| 72f8e196a7 |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "dependencies/tlibc"]
|
||||||
|
path = dependencies/tlibc
|
||||||
|
url = https://timerix.ddns.net/git/Timerix/tlibc.git
|
||||||
15
.vscode/c_cpp_properties.json
vendored
Normal file
15
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "all",
|
||||||
|
"defines": [],
|
||||||
|
"includePath": [
|
||||||
|
"dependencies/tlibc/include",
|
||||||
|
"src",
|
||||||
|
"${default}"
|
||||||
|
],
|
||||||
|
"cStandard": "c11"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@@ -2,16 +2,20 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "(gdb) Debug",
|
"name": "gdb_debug",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/tcpu",
|
"program": "${workspaceFolder}/bin/tcpu",
|
||||||
"windows": { "program": "${workspaceFolder}/bin/tcpu.exe" },
|
"windows": { "program": "${workspaceFolder}/bin/tcpu.exe" },
|
||||||
"args": [ "-c", "../examples/loop.tasm", "o.bin", "--debug", "-i", "o.bin" ],
|
"args": [
|
||||||
|
"-c", "../examples/video.tasm", "o.bin",
|
||||||
|
"-i", "o.bin", "--debug", "--video"
|
||||||
|
],
|
||||||
"cwd": "${workspaceFolder}/bin",
|
"cwd": "${workspaceFolder}/bin",
|
||||||
"preLaunchTask": "build_exec_dbg",
|
"preLaunchTask": "build_exec_dbg",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
|
"internalConsoleOptions": "neverOpen",
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
"miDebuggerPath": "gdb",
|
"miDebuggerPath": "gdb",
|
||||||
"setupCommands": [
|
"setupCommands": [
|
||||||
@@ -26,4 +30,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,12 @@
|
|||||||
Machine code interpreter written in pure C. Can execute programs up to 1 MEGABYTE (1048576 bytes) in size!!!
|
Machine code interpreter written in pure C. Can execute programs up to 1 MEGABYTE (1048576 bytes) in size!!!
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
1. Install [cbuild](https://timerix.ddns.net:3322/Timerix/cbuild.git)
|
1. Clone repo
|
||||||
2. Install [SDL3](https://github.com/libsdl-org/SDL) and [SDL3_image](https://github.com/libsdl-org/SDL_image) from package manager or source.
|
```
|
||||||
|
git clone --recurse-submodules https://timerix.ddns.net/git/Timerix/tcpu.git
|
||||||
|
```
|
||||||
|
2. Install [cbuild](https://timerix.ddns.net/git/Timerix/cbuild.git)
|
||||||
|
3. Install [SDL3](https://github.com/libsdl-org/SDL) and [SDL3_image](https://github.com/libsdl-org/SDL_image) from package manager or source.
|
||||||
3. ```sh
|
3. ```sh
|
||||||
cbuild build_exec_dbg
|
cbuild build_exec_dbg
|
||||||
```
|
```
|
||||||
|
|||||||
1
dependencies/tlibc
vendored
Submodule
1
dependencies/tlibc
vendored
Submodule
Submodule dependencies/tlibc added at 6a7f0a8715
19
dependencies/tlibc.config
vendored
Normal file
19
dependencies/tlibc.config
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This is a dependency config.
|
||||||
|
# You can copy it to another project to add tlibc dependency.
|
||||||
|
|
||||||
|
DEP_WORKING_DIR="$DEPENDENCIES_DIR/tlibc"
|
||||||
|
if [[ "$TASK" = *_dbg ]]; then
|
||||||
|
dep_build_target="build_static_lib_dbg"
|
||||||
|
else
|
||||||
|
dep_build_target="build_static_lib"
|
||||||
|
fi
|
||||||
|
DEP_PRE_BUILD_COMMAND=""
|
||||||
|
DEP_BUILD_COMMAND="cbuild $dep_build_target"
|
||||||
|
DEP_POST_BUILD_COMMAND=""
|
||||||
|
DEP_CLEAN_COMMAND="cbuild clean"
|
||||||
|
DEP_DYNAMIC_OUT_FILES=""
|
||||||
|
DEP_STATIC_OUT_FILES="bin/tlibc.a"
|
||||||
|
DEP_OTHER_OUT_FILES=""
|
||||||
|
PRESERVE_OUT_DIRECTORY_STRUCTURE=false
|
||||||
@@ -3,5 +3,5 @@ Example of graphical application
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.main:
|
.main:
|
||||||
//TODO: write code here
|
//TODO: add a way to access Event struct's fields
|
||||||
exit
|
exit
|
||||||
105
project.config
105
project.config
@@ -1,22 +1,30 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
CBUILD_VERSION=2.1.4
|
CBUILD_VERSION=2.3.2
|
||||||
CONFIG_VERSION=1
|
|
||||||
|
|
||||||
PROJECT="tcpu"
|
PROJECT="tcpu"
|
||||||
CMP_C="gcc"
|
CMP_C="gcc"
|
||||||
CMP_CPP="g++"
|
CMP_CPP="g++"
|
||||||
STD_C="c11"
|
STD_C="c99"
|
||||||
STD_CPP="c++11"
|
STD_CPP="c++11"
|
||||||
WARN_C="-Wall -Wextra -Wno-unused-parameter"
|
WARN_C="-Wall -Wextra
|
||||||
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
|
-Wduplicated-branches
|
||||||
|
-Wduplicated-cond
|
||||||
|
-Wformat=2
|
||||||
|
-Wmissing-include-dirs
|
||||||
|
-Wshadow
|
||||||
|
-Werror=return-type
|
||||||
|
-Werror=pointer-arith
|
||||||
|
-Werror=init-self
|
||||||
|
-Werror=incompatible-pointer-types"
|
||||||
|
WARN_CPP="$WARN_C"
|
||||||
SRC_C="$(find src -name '*.c')"
|
SRC_C="$(find src -name '*.c')"
|
||||||
SRC_CPP="$(find src -name '*.cpp')"
|
SRC_CPP="$(find src -name '*.cpp')"
|
||||||
|
|
||||||
# Directory with dependency configs.
|
# Directory with dependency configs.
|
||||||
# See cbuild/example_dependency_configs
|
# See cbuild/example_dependency_configs
|
||||||
DEPENDENCY_CONFIGS_DIR='.'
|
DEPENDENCY_CONFIGS_DIR='dependencies'
|
||||||
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
||||||
ENABLED_DEPENDENCIES=''
|
ENABLED_DEPENDENCIES='tlibc'
|
||||||
|
|
||||||
# OBJDIR structure:
|
# OBJDIR structure:
|
||||||
# ├── objects/ - Compiled object files. Cleans on each call of build task
|
# ├── objects/ - Compiled object files. Cleans on each call of build task
|
||||||
@@ -25,7 +33,9 @@ ENABLED_DEPENDENCIES=''
|
|||||||
# └── profile/ - gcc *.gcda profiling info files
|
# └── profile/ - gcc *.gcda profiling info files
|
||||||
OBJDIR="obj"
|
OBJDIR="obj"
|
||||||
OUTDIR="bin"
|
OUTDIR="bin"
|
||||||
STATIC_LIB_FILE="lib$PROJECT.a"
|
STATIC_LIB_FILE="$PROJECT.a"
|
||||||
|
|
||||||
|
INCLUDE="-Isrc -I$DEPENDENCIES_DIR/tlibc/include"
|
||||||
|
|
||||||
# OS-specific options
|
# OS-specific options
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
@@ -33,13 +43,11 @@ case "$OS" in
|
|||||||
EXEC_FILE="$PROJECT.exe"
|
EXEC_FILE="$PROJECT.exe"
|
||||||
SHARED_LIB_FILE="$PROJECT.dll"
|
SHARED_LIB_FILE="$PROJECT.dll"
|
||||||
LINKER_LIBS="-lSDL3_image -lSDL3"
|
LINKER_LIBS="-lSDL3_image -lSDL3"
|
||||||
INCLUDE=""
|
|
||||||
;;
|
;;
|
||||||
LINUX)
|
LINUX)
|
||||||
EXEC_FILE="$PROJECT"
|
EXEC_FILE="$PROJECT"
|
||||||
SHARED_LIB_FILE="$PROJECT.so"
|
SHARED_LIB_FILE="$PROJECT.so"
|
||||||
LINKER_LIBS="-lSDL3_image -lSDL3"
|
LINKER_LIBS="-lSDL3_image -lSDL3"
|
||||||
INCLUDE=""
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
error "operating system $OS has no configuration variants"
|
error "operating system $OS has no configuration variants"
|
||||||
@@ -59,61 +67,61 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects -fdata-sections -ffunction-sections -Wl,--gc-sections"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT="@cbuild/default_tasks/strip_exec.sh"
|
||||||
;;
|
;;
|
||||||
# creates executable with debug info and no optimizations
|
# creates executable with debug info and no optimizations
|
||||||
build_exec_dbg)
|
build_exec_dbg)
|
||||||
C_ARGS="-O0 -g3"
|
C_ARGS="-O0 -g3"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# creates shared library
|
# creates shared library
|
||||||
build_shared_lib)
|
build_shared_lib)
|
||||||
C_ARGS="-O2 -fpic -flto -shared"
|
C_ARGS="-O2 -fpic -flto -shared"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# creates shared library with debug symbols and no optimizations
|
# creates shared library with debug symbols and no optimizations
|
||||||
build_shared_lib_dbg)
|
build_shared_lib_dbg)
|
||||||
C_ARGS="-O0 -g3 -fpic -shared"
|
C_ARGS="-O0 -g3 -fpic -shared"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# creates static library
|
# creates static library
|
||||||
build_static_lib)
|
build_static_lib)
|
||||||
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections"
|
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# creates static library with debug symbols and no optimizations
|
# creates static library with debug symbols and no optimizations
|
||||||
build_static_lib_dbg)
|
build_static_lib_dbg)
|
||||||
C_ARGS="-O0 -g3"
|
C_ARGS="-O0 -g3"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=""
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# executes $EXEC_FILE
|
# executes $EXEC_FILE
|
||||||
exec)
|
exec)
|
||||||
TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
|
||||||
;;
|
;;
|
||||||
# executes $EXEC_FILE with valgrind memory checker
|
# executes $EXEC_FILE with valgrind memory checker
|
||||||
valgrind)
|
valgrind)
|
||||||
VALGRIND_ARGS="-s --read-var-info=yes --track-origins=yes --fullpath-after=$(pwd) --leak-check=full --show-leak-kinds=all"
|
VALGRIND_ARGS="-s --read-var-info=yes --track-origins=yes --fullpath-after=$(pwd)/ --leak-check=full --show-leak-kinds=all"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/valgrind.sh
|
TASK_SCRIPT="@cbuild/default_tasks/valgrind.sh"
|
||||||
;;
|
;;
|
||||||
# generates profiling info
|
# generates profiling info
|
||||||
profile)
|
profile)
|
||||||
@@ -127,22 +135,25 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/profile.sh
|
TASK_SCRIPT="@cbuild/default_tasks/profile.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# compiles program with -pg and runs it with gprof
|
# compiles program with -pg and runs it with gprof
|
||||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
# requires graphviz (https://www.graphviz.org/download/source/)
|
# requires graphviz (https://www.graphviz.org/download/source/)
|
||||||
gprof)
|
gprof)
|
||||||
OUTDIR="$OUTDIR/gprof"
|
OUTDIR="$OUTDIR/gprof"
|
||||||
# -pg adds code to executable, that generates file containing function call info (gmon.out)
|
# arguments that emit some call counter code and disable optimizations to see function names
|
||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -pg"
|
# https://github.com/msys2/MINGW-packages/issues/8503#issuecomment-1365475205
|
||||||
|
C_ARGS="-O0 -g -pg -no-pie -fno-omit-frame-pointer
|
||||||
|
-fno-inline-functions -fno-inline-functions-called-once
|
||||||
|
-fno-optimize-sibling-calls -fopenmp"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/gprof.sh
|
TASK_SCRIPT="@cbuild/default_tasks/gprof.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# compiles program and runs it with callgrind (part of valgrind)
|
# compiles program and runs it with callgrind (part of valgrind)
|
||||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
@@ -154,9 +165,9 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/callgrind.sh
|
TASK_SCRIPT="@cbuild/default_tasks/callgrind.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# compiles executable with sanitizers and executes it to find errors and warnings
|
# compiles executable with sanitizers and executes it to find errors and warnings
|
||||||
sanitize)
|
sanitize)
|
||||||
@@ -164,19 +175,19 @@ case "$TASK" in
|
|||||||
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
|
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
|
||||||
POST_TASK_SCRIPT=
|
POST_TASK_SCRIPT=""
|
||||||
;;
|
;;
|
||||||
# rebuilds specified dependencies
|
# rebuilds specified dependencies
|
||||||
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
|
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
|
||||||
# 'all' can be specified to rebuild all dependencies
|
# 'all' can be specified to rebuild all dependencies
|
||||||
rebuild_dependencies)
|
rebuild_dependencies)
|
||||||
TASK_SCRIPT=cbuild/default_tasks/rebuild_dependencies.sh
|
TASK_SCRIPT="@cbuild/default_tasks/rebuild_dependencies.sh"
|
||||||
;;
|
;;
|
||||||
# deletes generated files
|
# deletes generated files
|
||||||
clean)
|
clean)
|
||||||
TASK_SCRIPT=cbuild/default_tasks/clean.sh
|
TASK_SCRIPT="@cbuild/default_tasks/clean.sh"
|
||||||
;;
|
;;
|
||||||
# nothing to do
|
# nothing to do
|
||||||
"" | no_task)
|
"" | no_task)
|
||||||
|
|||||||
11
project.config.user.default
Normal file
11
project.config.user.default
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Project user config is ignored by git.
|
||||||
|
# Here you can add variables that users might want to change
|
||||||
|
# on their local machine, without commiting to the repository.
|
||||||
|
|
||||||
|
# Directory where you install dependencies.
|
||||||
|
# Do not confuse with DEPENDENCY_CONFIGS_DIR
|
||||||
|
# Example:
|
||||||
|
# libexample source code is at `../libexample`, and dependency config
|
||||||
|
# that specifies how to build this lib is at `dependencies/libexample.config`
|
||||||
|
DEPENDENCIES_DIR="dependencies"
|
||||||
@@ -1,71 +1,72 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <SDL3_image/SDL_image.h>
|
#include <SDL3_image/SDL_image.h>
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
|
#include "tcpu_version.h"
|
||||||
|
|
||||||
typedef struct Display {
|
typedef struct Display {
|
||||||
str name;
|
|
||||||
i32 width;
|
i32 width;
|
||||||
i32 height;
|
i32 height;
|
||||||
SDL_Window* window;
|
SDL_Window* window;
|
||||||
SDL_Renderer* renderer;
|
SDL_Renderer* renderer;
|
||||||
} Display;
|
} Display;
|
||||||
|
|
||||||
static SDL_InitState sdl_init_state = {0};
|
static SDL_InitState _sdl_init_state = {0};
|
||||||
|
static Display _d = {0};
|
||||||
|
static cstr _title = "TCPU v" TCPU_VERSION_CSTR;
|
||||||
|
|
||||||
|
bool Display_init(i32 w, i32 h, DisplayFlags flags){
|
||||||
Display* Display_create(str name, i32 w, i32 h, DisplayFlags flags){
|
(void)flags;
|
||||||
Display* d = malloc(sizeof(Display));
|
|
||||||
|
_d.width = w;
|
||||||
d->name = str_copy(name);
|
_d.height = h;
|
||||||
d->width = w;
|
_d.window = NULL;
|
||||||
d->height = h;
|
_d.renderer = NULL;
|
||||||
d->window = NULL;
|
|
||||||
d->renderer = NULL;
|
if (SDL_ShouldInit(&_sdl_init_state)) {
|
||||||
|
|
||||||
if (SDL_ShouldInit(&sdl_init_state)) {
|
|
||||||
bool sdl_initialized = SDL_Init(SDL_INIT_VIDEO);
|
bool sdl_initialized = SDL_Init(SDL_INIT_VIDEO);
|
||||||
SDL_SetInitialized(&sdl_init_state, sdl_initialized);
|
SDL_SetInitialized(&_sdl_init_state, sdl_initialized);
|
||||||
if(!sdl_initialized)
|
if(!sdl_initialized)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_WindowFlags window_flags = SDL_WINDOW_ALWAYS_ON_TOP;
|
SDL_WindowFlags window_flags = SDL_WINDOW_ALWAYS_ON_TOP;
|
||||||
if(!SDL_CreateWindowAndRenderer(d->name.data, d->width, d->height, window_flags, &d->window, &d->renderer)){
|
if(!SDL_CreateWindowAndRenderer(_title, _d.width, _d.height, window_flags, &_d.window, &_d.renderer)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return d;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display_destroy(Display* d){
|
void Display_destroy(){
|
||||||
free(d->name.data);
|
SDL_DestroyRenderer(_d.renderer);
|
||||||
SDL_DestroyRenderer(d->renderer);
|
SDL_DestroyWindow(_d.window);
|
||||||
SDL_DestroyWindow(d->window);
|
|
||||||
free(d);
|
|
||||||
|
|
||||||
// if (SDL_ShouldQuit(&sdl_init_state)) {
|
// if (SDL_ShouldQuit(&_sdl_init_state)) {
|
||||||
// SDL_Quit();
|
// SDL_Quit();
|
||||||
// SDL_SetInitialized(&sdl_init_state, false);
|
// SDL_SetInitialized(&_sdl_init_state, false);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_setName(Display* d, str name){
|
NULLABLE(cstr) Display_getError(){
|
||||||
d->name = str_copy(name);
|
return SDL_GetError();
|
||||||
return SDL_SetWindowTitle(d->window, name.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_setSize(Display* d, u32 w, u32 h){
|
bool Display_setSize(u32 w, u32 h){
|
||||||
d->width = w;
|
_d.width = w;
|
||||||
d->height = h;
|
_d.height = h;
|
||||||
return SDL_SetWindowSize(d->window, w, h);
|
return SDL_SetWindowSize(_d.window, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_setDrawingColor(Display* d, ColorRGBA color){
|
bool Display_setFullScreenMode(bool value){
|
||||||
return SDL_SetRenderDrawColor(d->renderer, color.r, color.g, color.b, color.a);
|
return SDL_SetWindowFullscreen(_d.window, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_clear(Display* d){
|
bool Display_setDrawingColor(ColorRGBA color){
|
||||||
return SDL_RenderClear(d->renderer);
|
return SDL_SetRenderDrawColor(_d.renderer, color.r, color.g, color.b, color.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Display_clear(){
|
||||||
|
return SDL_RenderClear(_d.renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define Rect_copy(DST, SRC) {\
|
#define Rect_copy(DST, SRC) {\
|
||||||
@@ -75,16 +76,12 @@ bool Display_clear(Display* d){
|
|||||||
DST.h = SRC.h;\
|
DST.h = SRC.h;\
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_fillRect(Display* d, Rect rect) {
|
bool Display_fillRect(Rect rect) {
|
||||||
SDL_FRect sdl_rect;
|
SDL_FRect sdl_rect;
|
||||||
Rect_copy(sdl_rect, rect);
|
Rect_copy(sdl_rect, rect);
|
||||||
return SDL_RenderFillRect(d->renderer, &sdl_rect);
|
return SDL_RenderFillRect(_d.renderer, &sdl_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Display_swapBuffers(Display* d){
|
bool Display_swapBuffers(){
|
||||||
return SDL_RenderPresent(d->renderer);
|
return SDL_RenderPresent(_d.renderer);
|
||||||
}
|
|
||||||
|
|
||||||
NULLABLE(cstr) Display_getError(){
|
|
||||||
return SDL_GetError();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
|
|
||||||
typedef struct Rect {
|
typedef struct Rect {
|
||||||
i32 x, y;
|
i32 x, y;
|
||||||
@@ -18,15 +18,13 @@ typedef enum DisplayFlags {
|
|||||||
DisplayFlags_Default = 0
|
DisplayFlags_Default = 0
|
||||||
} DisplayFlags;
|
} DisplayFlags;
|
||||||
|
|
||||||
typedef struct Display Display;
|
bool Display_init(i32 w, i32 h, DisplayFlags flags);
|
||||||
|
void Display_destroy();
|
||||||
Display* Display_create(str name, i32 w, i32 h, DisplayFlags flags);
|
|
||||||
void Display_destroy(Display* d);
|
|
||||||
|
|
||||||
bool Display_setName(Display* d, str name);
|
|
||||||
bool Display_setSize(Display* d, u32 w, u32 h);
|
|
||||||
bool Display_setDrawingColor(Display* d, ColorRGBA color);
|
|
||||||
bool Display_clear(Display* d);
|
|
||||||
bool Display_fillRect(Display* d, Rect rect);
|
|
||||||
bool Display_swapBuffers(Display* d);
|
|
||||||
NULLABLE(cstr) Display_getError();
|
NULLABLE(cstr) Display_getError();
|
||||||
|
|
||||||
|
bool Display_setSize(u32 w, u32 h);
|
||||||
|
bool Display_setFullScreenMode(bool value);
|
||||||
|
bool Display_setDrawingColor(ColorRGBA color);
|
||||||
|
bool Display_clear();
|
||||||
|
bool Display_fillRect(Rect rect);
|
||||||
|
bool Display_swapBuffers();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "VM.h"
|
#include "VM.h"
|
||||||
#include "../instructions/instructions.h"
|
#include "instructions/instructions.h"
|
||||||
|
|
||||||
void VM_init(VM* vm){
|
void VM_construct(VM* vm){
|
||||||
memset(vm, 0, sizeof(VM));
|
memset(vm, 0, sizeof(VM));
|
||||||
vm->state = VMState_Initialized;
|
vm->state = VMState_Initialized;
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ void _VM_setError(VM* vm, cstr context, cstr format, ...){
|
|||||||
sprintf(position_str, "[at 0x%x][", (u32)vm->current_pos);
|
sprintf(position_str, "[at 0x%x][", (u32)vm->current_pos);
|
||||||
char* real_format = strcat_malloc(position_str, context, "] ", format);
|
char* real_format = strcat_malloc(position_str, context, "] ", format);
|
||||||
va_start(argv, format);
|
va_start(argv, format);
|
||||||
char* NULLABLE(buf) = vsprintf_malloc(256, real_format, argv);
|
char* NULLABLE(buf) = vsprintf_malloc(real_format, argv);
|
||||||
va_end(argv);
|
va_end(argv);
|
||||||
free(real_format);
|
free(real_format);
|
||||||
if(buf == NULL){
|
if(buf == NULL){
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "../instructions/registers.h"
|
#include "instructions/registers.h"
|
||||||
|
|
||||||
typedef union Register {
|
typedef union Register {
|
||||||
u64 rx;
|
u64 rx;
|
||||||
@@ -43,7 +43,7 @@ typedef struct VM {
|
|||||||
size_t current_pos;
|
size_t current_pos;
|
||||||
} VM;
|
} VM;
|
||||||
|
|
||||||
void VM_init(VM* vm);
|
void VM_construct(VM* vm);
|
||||||
|
|
||||||
/// @brief Loads a program from the buffer.
|
/// @brief Loads a program from the buffer.
|
||||||
/// @param data buffer starting with machine code
|
/// @param data buffer starting with machine code
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#include <SDL3/SDL_timer.h>
|
|
||||||
#include "time.h"
|
|
||||||
|
|
||||||
void time_sleepMS(u32 ms){
|
|
||||||
SDL_Delay(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
void time_sleepNS(u64 ns){
|
|
||||||
SDL_DelayNS(ns);
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 time_getMonotonicMS(){
|
|
||||||
return SDL_GetTicks();
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 time_getMonotonicNS(){
|
|
||||||
return SDL_GetTicksNS();
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../std.h"
|
|
||||||
|
|
||||||
void time_sleepMS(u32 ms);
|
|
||||||
void time_sleepNS(u64 ns);
|
|
||||||
u64 time_getMonotonicMS();
|
|
||||||
u64 time_getMonotonicNS();
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../std.h"
|
|
||||||
|
|
||||||
#define Array_construct(T, DATA, LEN) ((Array_##T){ .data = DATA, .len = LEN })
|
|
||||||
|
|
||||||
/// creates Array_##T from a const array
|
|
||||||
#define ARRAY(T, A...) Array_construct(T, ((T[])A), ARRAY_SIZE(((T[])A)))
|
|
||||||
|
|
||||||
#define Array_declare(T)\
|
|
||||||
typedef struct Array_##T {\
|
|
||||||
T* data;\
|
|
||||||
u32 len;\
|
|
||||||
} Array_##T;\
|
|
||||||
\
|
|
||||||
static inline Array_##T Array_##T##_alloc(u32 len){\
|
|
||||||
return Array_construct(T, (T*)malloc(len * sizeof(T)), len);\
|
|
||||||
}\
|
|
||||||
static inline void Array_##T##_realloc(Array_##T* ptr, u32 new_len){\
|
|
||||||
ptr->data = (T*)realloc(ptr->data, new_len * sizeof(T));\
|
|
||||||
ptr->len = new_len;\
|
|
||||||
}
|
|
||||||
|
|
||||||
Array_declare(u8)
|
|
||||||
Array_declare(u32)
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../std.h"
|
|
||||||
#include "../string/str.h"
|
|
||||||
#include "Array.h"
|
|
||||||
#include "List.h"
|
|
||||||
|
|
||||||
//TODO: sorting of bucket and binary search
|
|
||||||
//TODO: delayed deletion
|
|
||||||
|
|
||||||
#define __HashMap_HASH_FUNC str_hash32
|
|
||||||
#define __HashMapBucket_MAX_LEN 16
|
|
||||||
|
|
||||||
#define HashMap_DESTROY_VALUE_FUNC_NULL ((void (*)(void*))NULL)
|
|
||||||
|
|
||||||
/// call this in a header file
|
|
||||||
///@param T Value type
|
|
||||||
#define HashMap_declare(T)\
|
|
||||||
typedef struct KeyValue_##T {\
|
|
||||||
str key;\
|
|
||||||
T value;\
|
|
||||||
u32 hash;\
|
|
||||||
} KeyValue_##T;\
|
|
||||||
\
|
|
||||||
List_declare(KeyValue_##T);\
|
|
||||||
\
|
|
||||||
typedef struct HashMapBucket_##T {\
|
|
||||||
List_KeyValue_##T kvs;\
|
|
||||||
} HashMapBucket_##T;\
|
|
||||||
\
|
|
||||||
typedef struct HashMap_##T {\
|
|
||||||
HashMapBucket_##T* table;\
|
|
||||||
u32 height;\
|
|
||||||
u16 height_n;\
|
|
||||||
} HashMap_##T;\
|
|
||||||
\
|
|
||||||
void HashMap_##T##_alloc(HashMap_##T* ptr);\
|
|
||||||
void HashMap_##T##_free(HashMap_##T* ptr);\
|
|
||||||
T* NULLABLE(HashMap_##T##_tryGetPtr)(HashMap_##T* ptr, str key);\
|
|
||||||
bool HashMap_##T##_tryPush(HashMap_##T* ptr, str key, T value);\
|
|
||||||
bool HashMap_##T##_tryDelete(HashMap_##T* ptr, str key);\
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// call this in a source code file
|
|
||||||
///@param T Value type
|
|
||||||
///@param DESTROY_VALUE_FUNC `void foo (T*)` or HashMap_DESTROY_VALUE_FUNC_NULL
|
|
||||||
#define HashMap_define(T, DESTROY_VALUE_FUNC)\
|
|
||||||
List_define(KeyValue_##T);\
|
|
||||||
\
|
|
||||||
static const Array_u32 __HashMap_##T##_heights = ARRAY(u32, {\
|
|
||||||
17, 31, 61, 127, 257, 521, 1021, 2053, 4099, 8191, 16381, 32771,\
|
|
||||||
65521, 131071, 262147, 524287, 1048583, 2097169, 4194319,\
|
|
||||||
8388617, 16777213, 33554467, 67108859, 134217757, 268435493\
|
|
||||||
});\
|
|
||||||
\
|
|
||||||
void HashMap_##T##_alloc(HashMap_##T* ptr){\
|
|
||||||
ptr->height_n = 0;\
|
|
||||||
ptr->height = __HashMap_##T##_heights.data[0];\
|
|
||||||
ptr->table = (HashMapBucket_##T*)malloc(ptr->height * sizeof(HashMapBucket_##T));\
|
|
||||||
memset(ptr->table, 0, ptr->height * sizeof(HashMapBucket_##T));\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
void HashMap_##T##_free(HashMap_##T* ptr){\
|
|
||||||
for(u32 i = 0; i < ptr->height; i++){\
|
|
||||||
for(u32 j = 0; j < ptr->table[i].kvs.len; j++){\
|
|
||||||
KeyValue_##T* kv_ptr = &ptr->table[i].kvs.data[j];\
|
|
||||||
if(DESTROY_VALUE_FUNC){\
|
|
||||||
DESTROY_VALUE_FUNC(&kv_ptr->value);\
|
|
||||||
}\
|
|
||||||
free(kv_ptr->key.data);\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
free(ptr->table[i].kvs.data);\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
free(ptr->table);\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
T* NULLABLE(HashMap_##T##_tryGetPtr)(HashMap_##T* ptr, str key){\
|
|
||||||
u32 hash = __HashMap_HASH_FUNC(key);\
|
|
||||||
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
|
||||||
for(u32 i = 0; i < bu->kvs.len; i++){\
|
|
||||||
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
|
||||||
return &bu->kvs.data[i].value;\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
return NULL;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
bool HashMap_##T##_tryPush(HashMap_##T* ptr, str key, T value){\
|
|
||||||
u32 hash = __HashMap_HASH_FUNC(key);\
|
|
||||||
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
|
||||||
for(u32 i = 0; i < bu->kvs.len; i++){\
|
|
||||||
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
|
||||||
return false;\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
if(bu->kvs.len >= __HashMapBucket_MAX_LEN){\
|
|
||||||
u32 height_expanded_n = ptr->height_n + 1;\
|
|
||||||
if(height_expanded_n >= __HashMap_##T##_heights.len){\
|
|
||||||
printf("ERROR: HashMap_" #T " IS FULL\n");\
|
|
||||||
return false;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
u32 height_expanded = __HashMap_##T##_heights.data[height_expanded_n];\
|
|
||||||
HashMapBucket_##T* table_expanded = (HashMapBucket_##T*)malloc(height_expanded * sizeof(HashMapBucket_##T));\
|
|
||||||
memset(table_expanded, 0, height_expanded * sizeof(HashMapBucket_##T));\
|
|
||||||
for(u32 i = 0; i < height_expanded; i++){\
|
|
||||||
for(u32 j = 0; j < ptr->table[i].kvs.len; j++){\
|
|
||||||
KeyValue_##T kv = ptr->table[i].kvs.data[j];\
|
|
||||||
List_KeyValue_##T##_push(&table_expanded[kv.hash % height_expanded].kvs, kv);\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
free(ptr->table[i].kvs.data);\
|
|
||||||
}\
|
|
||||||
free(ptr->table);\
|
|
||||||
ptr->table = table_expanded;\
|
|
||||||
ptr->height = height_expanded;\
|
|
||||||
ptr->height_n = height_expanded_n;\
|
|
||||||
bu = &ptr->table[hash % ptr->height];\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
KeyValue_##T kv = { .key = str_copy(key), .value = value, .hash = hash };\
|
|
||||||
List_KeyValue_##T##_push(&bu->kvs, kv);\
|
|
||||||
return true;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
bool HashMap_##T##_tryDelete(HashMap_##T* ptr, str key){\
|
|
||||||
u32 hash = __HashMap_HASH_FUNC(key);\
|
|
||||||
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
|
||||||
for(u32 i = 0; i < bu->kvs.len; i++){\
|
|
||||||
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
|
||||||
return List_KeyValue_##T##_tryRemoveAt(&bu->kvs, i);\
|
|
||||||
}\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
return false;\
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#include "List.h"
|
|
||||||
|
|
||||||
List_define(u32);
|
|
||||||
List_define(u8);
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../std.h"
|
|
||||||
|
|
||||||
// minimal max_len after initial (0)
|
|
||||||
#define __List_min_size 16
|
|
||||||
|
|
||||||
#define List_declare(T)\
|
|
||||||
typedef struct List_##T {\
|
|
||||||
T* data;\
|
|
||||||
u32 len;\
|
|
||||||
u32 max_len;\
|
|
||||||
} List_##T;\
|
|
||||||
\
|
|
||||||
static inline List_##T List_##T##_construct(T* data_ptr, u32 len, u32 max_len) {\
|
|
||||||
return (List_##T){ .data = data_ptr, .len = len, .max_len = max_len };\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
List_##T List_##T##_alloc(u32 initial_len);\
|
|
||||||
\
|
|
||||||
T* List_##T##_expand(List_##T* ptr, u32 count);\
|
|
||||||
void List_##T##_push(List_##T* ptr, T value);\
|
|
||||||
void List_##T##_pushMany(List_##T* ptr, T* values, u32 count);\
|
|
||||||
bool List_##T##_tryRemoveAt(List_##T* ptr, u32 i);\
|
|
||||||
|
|
||||||
|
|
||||||
#define List_define(T)\
|
|
||||||
List_##T List_##T##_alloc(u32 initial_len){\
|
|
||||||
if(initial_len == 0)\
|
|
||||||
return List_##T##_construct((T*)NULL, 0, 0);\
|
|
||||||
u32 max_len = ALIGN_TO(initial_len, sizeof(void*)/sizeof(T));\
|
|
||||||
/* branchless version of max(max_len, __List_min_size) */\
|
|
||||||
max_len += (max_len < __List_min_size) * (__List_min_size - max_len);\
|
|
||||||
return List_##T##_construct((T*)malloc(max_len * sizeof(T)), 0, max_len);\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
T* List_##T##_expand(List_##T* ptr, u32 count){\
|
|
||||||
u32 occupied_len = ptr->len;\
|
|
||||||
u32 expanded_max_len = ptr->max_len;\
|
|
||||||
expanded_max_len += (expanded_max_len < __List_min_size) * (__List_min_size - expanded_max_len);\
|
|
||||||
ptr->len += count;\
|
|
||||||
while(ptr->len > expanded_max_len){\
|
|
||||||
expanded_max_len *= 2;\
|
|
||||||
}\
|
|
||||||
u32 alloc_size = expanded_max_len * sizeof(T);\
|
|
||||||
if(ptr->data == NULL)\
|
|
||||||
ptr->data = (T*)malloc(alloc_size);\
|
|
||||||
else ptr->data = (T*)realloc(ptr->data, alloc_size);\
|
|
||||||
ptr->max_len = expanded_max_len;\
|
|
||||||
return ptr->data + occupied_len;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
void List_##T##_push(List_##T* ptr, T value){\
|
|
||||||
T* empty_cell_ptr = List_##T##_expand(ptr, 1);\
|
|
||||||
*empty_cell_ptr = value;\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
void List_##T##_pushMany(List_##T* ptr, T* values, u32 count){\
|
|
||||||
T* empty_cell_ptr = List_##T##_expand(ptr, count);\
|
|
||||||
memcpy(empty_cell_ptr, values, count * sizeof(T));\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
bool List_##T##_tryRemoveAt(List_##T* ptr, u32 i){\
|
|
||||||
if(ptr->len == 0 || i >= ptr->len)\
|
|
||||||
return false;\
|
|
||||||
\
|
|
||||||
ptr->len--;\
|
|
||||||
for(; i < ptr->len; i++){\
|
|
||||||
ptr->data[i] = ptr->data[i + 1];\
|
|
||||||
}\
|
|
||||||
return true;\
|
|
||||||
}\
|
|
||||||
|
|
||||||
|
|
||||||
List_declare(u32);
|
|
||||||
List_declare(u8);
|
|
||||||
@@ -1,52 +1,51 @@
|
|||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
|
|
||||||
List_define(Argument);
|
Array_declare(str);
|
||||||
List_define(Operation);
|
|
||||||
List_define(DataDefinition);
|
|
||||||
List_define(Section);
|
|
||||||
|
|
||||||
static str _ArgumentType_str[] = {
|
static Array(str) _ArgumentType_str_array = ARRAY(str, {
|
||||||
STR("Unset"),
|
STR("Unset"),
|
||||||
STR("Register"),
|
STR("Register"),
|
||||||
STR("ConstValue"),
|
STR("ConstValue"),
|
||||||
STR("VarDataName"),
|
STR("VarDataName"),
|
||||||
STR("ConstDataPointer"),
|
STR("ConstDataPointer"),
|
||||||
STR("ConstDataSize"),
|
STR("ConstDataSize"),
|
||||||
};
|
});
|
||||||
|
|
||||||
str ArgumentType_toString(ArgumentType t){
|
str ArgumentType_toString(ArgumentType t){
|
||||||
if(t >= ARRAY_SIZE(_ArgumentType_str))
|
if(t >= _ArgumentType_str_array.len)
|
||||||
return STR("!!ArgumentType INDEX_ERROR!!");
|
return STR("!!ArgumentType INDEX_ERROR!!");
|
||||||
return _ArgumentType_str[t];
|
return _ArgumentType_str_array.data[t];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Section_init(Section* sec, str name){
|
void Section_construct(Section* sec, str name){
|
||||||
sec->name = name;
|
sec->name = name;
|
||||||
sec->data = List_DataDefinition_alloc(256);
|
sec->data_definitions_list = List_DataDefinition_alloc(256);
|
||||||
sec->code = List_Operation_alloc(1024);
|
sec->operations_list = List_Operation_alloc(1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Section_free(Section* sec){
|
void Section_destroy(Section* sec){
|
||||||
for(u32 i = 0; i < sec->data.len; i++){
|
for(u32 i = 0; i < sec->data_definitions_list.len; i++){
|
||||||
free(sec->data.data[i].data.data);
|
DataDefinition* dd = sec->data_definitions_list.data + i;
|
||||||
|
List_u8_destroy(&dd->data_bytes);
|
||||||
}
|
}
|
||||||
free(sec->data.data);
|
List_DataDefinition_destroy(&sec->data_definitions_list);
|
||||||
|
|
||||||
for(u32 i = 0; i < sec->code.len; i++){
|
for(u32 i = 0; i < sec->operations_list.len; i++){
|
||||||
free(sec->code.data[i].args.data);
|
Operation* op = sec->operations_list.data + i;
|
||||||
|
List_Argument_destroy(&op->args);
|
||||||
}
|
}
|
||||||
free(sec->code.data);
|
List_Operation_destroy(&sec->operations_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AST_init(AST* ast){
|
void AST_construct(AST* ast){
|
||||||
ast->sections = List_Section_alloc(32);
|
ast->sections = List_Section_alloc(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AST_free(AST* ast){
|
void AST_destroy(AST* ast){
|
||||||
for(u32 i = 0; i != ast->sections.len; i++){
|
for(u32 i = 0; i != ast->sections.len; i++){
|
||||||
Section_free(&ast->sections.data[i]);
|
Section_destroy(ast->sections.data + i);
|
||||||
}
|
}
|
||||||
free(ast->sections.data);
|
List_Section_destroy(&ast->sections);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "../instructions/instructions.h"
|
#include "instructions/instructions.h"
|
||||||
#include "../instructions/registers.h"
|
#include "instructions/registers.h"
|
||||||
#include "../collections/List.h"
|
#include "tlibc/collections/List.h"
|
||||||
|
#include "tlibc/collections/List_impl/List_u8.h"
|
||||||
|
|
||||||
typedef enum ArgumentType {
|
typedef enum ArgumentType {
|
||||||
ArgumentType_Unset,
|
ArgumentType_Unset,
|
||||||
@@ -30,7 +31,7 @@ List_declare(Argument);
|
|||||||
|
|
||||||
|
|
||||||
typedef struct Operation {
|
typedef struct Operation {
|
||||||
List_Argument args;
|
List(Argument) args;
|
||||||
Opcode opcode;
|
Opcode opcode;
|
||||||
} Operation;
|
} Operation;
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ List_declare(Operation);
|
|||||||
|
|
||||||
typedef struct DataDefinition {
|
typedef struct DataDefinition {
|
||||||
str name;
|
str name;
|
||||||
List_u8 data;
|
List(u8) data_bytes;
|
||||||
u32 element_size;
|
u32 element_size;
|
||||||
} DataDefinition;
|
} DataDefinition;
|
||||||
|
|
||||||
@@ -48,18 +49,18 @@ List_declare(DataDefinition);
|
|||||||
|
|
||||||
typedef struct Section {
|
typedef struct Section {
|
||||||
str name;
|
str name;
|
||||||
List_DataDefinition data;
|
List(DataDefinition) data_definitions_list;
|
||||||
List_Operation code;
|
List(Operation) operations_list;
|
||||||
} Section;
|
} Section;
|
||||||
|
|
||||||
List_declare(Section);
|
List_declare(Section);
|
||||||
|
|
||||||
void Section_init(Section* Section, str name);
|
void Section_construct(Section* Section, str name);
|
||||||
void Section_free(Section* Section);
|
void Section_destroy(Section* Section);
|
||||||
|
|
||||||
typedef struct AST {
|
typedef struct AST {
|
||||||
List_Section sections;
|
List(Section) sections;
|
||||||
} AST;
|
} AST;
|
||||||
|
|
||||||
void AST_init(AST* ast);
|
void AST_construct(AST* ast);
|
||||||
void AST_free(AST* ast);
|
void AST_destroy(AST* ast);
|
||||||
|
|||||||
@@ -1,42 +1,36 @@
|
|||||||
#include "Binary.h"
|
#include "Binary.h"
|
||||||
|
|
||||||
List_define(ConstDataProps);
|
|
||||||
HashMap_define(ConstDataProps, HashMap_DESTROY_VALUE_FUNC_NULL);
|
|
||||||
List_define(NamedRef);
|
|
||||||
List_define(CompiledSection);
|
|
||||||
HashMap_define(CompiledSectionPtr, HashMap_DESTROY_VALUE_FUNC_NULL);
|
|
||||||
|
|
||||||
|
|
||||||
void CompiledSection_construct(CompiledSection* ptr, str name){
|
void CompiledSection_construct(CompiledSection* ptr, str name){
|
||||||
ptr->name = name;
|
ptr->name = name;
|
||||||
ptr->next = NULL;
|
ptr->next = NULL;
|
||||||
ptr->offset = 0;
|
ptr->offset = 0;
|
||||||
ptr->const_data_props_list = List_ConstDataProps_construct(NULL, 0, 0);
|
ptr->const_data_props_list = List_ConstDataProps_construct(NULL, 0, 0);
|
||||||
ptr->named_refs = List_NamedRef_construct(NULL, 0, 0);
|
ptr->named_refs = List_NamedRef_construct(NULL, 0, 0);
|
||||||
ptr->bytes = List_u8_alloc(64);
|
ptr->bytes = List_u8_alloc(128);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompiledSection_free(CompiledSection* ptr){
|
void CompiledSection_destroy(CompiledSection* ptr){
|
||||||
free(ptr->const_data_props_list.data);
|
List_ConstDataProps_destroy(&ptr->const_data_props_list);
|
||||||
free(ptr->named_refs.data);
|
List_NamedRef_destroy(&ptr->named_refs);
|
||||||
free(ptr->bytes.data);
|
List_u8_destroy(&ptr->bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void BinaryObject_construct(BinaryObject* ptr){
|
void BinaryObject_construct(BinaryObject* ptr){
|
||||||
ptr->section_list = List_CompiledSection_alloc(64);
|
ptr->comp_sec_list = List_CompiledSection_alloc(64);
|
||||||
HashMap_CompiledSectionPtr_alloc(&ptr->section_map);
|
HashMap_construct(&ptr->comp_sec_i_map, u32, NULL);
|
||||||
HashMap_ConstDataProps_alloc(&ptr->const_data_map);
|
HashMap_construct(&ptr->const_data_props_map, ConstDataProps, NULL);
|
||||||
ptr->main_section = NULL;
|
ptr->main_sec = NULL;
|
||||||
ptr->total_size = 0;
|
ptr->total_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryObject_free(BinaryObject* ptr){
|
void BinaryObject_destroy(BinaryObject* ptr){
|
||||||
for(u32 i = 0; i < ptr->section_list.len; i++){
|
for(u32 i = 0; i < ptr->comp_sec_list.len; i++){
|
||||||
CompiledSection_free(&ptr->section_list.data[i]);
|
CompiledSection* sec_ptr = ptr->comp_sec_list.data + i;
|
||||||
|
CompiledSection_destroy(sec_ptr);
|
||||||
}
|
}
|
||||||
free(ptr->section_list.data);
|
List_CompiledSection_destroy(&ptr->comp_sec_list);
|
||||||
|
|
||||||
HashMap_CompiledSectionPtr_free(&ptr->section_map);
|
HashMap_destroy(&ptr->comp_sec_i_map);
|
||||||
HashMap_ConstDataProps_free(&ptr->const_data_map);
|
HashMap_destroy(&ptr->const_data_props_map);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "../instructions/instructions.h"
|
#include "instructions/instructions.h"
|
||||||
#include "../instructions/registers.h"
|
#include "instructions/registers.h"
|
||||||
#include "../collections/List.h"
|
#include "tlibc/collections/List.h"
|
||||||
#include "../collections/HashMap.h"
|
#include "tlibc/collections/List_impl/List_u8.h"
|
||||||
|
#include "tlibc/collections/HashMap.h"
|
||||||
#include "AST.h"
|
#include "AST.h"
|
||||||
|
|
||||||
typedef struct CompiledSection CompiledSection;
|
typedef struct CompiledSection CompiledSection;
|
||||||
@@ -14,10 +15,9 @@ typedef struct ConstDataProps {
|
|||||||
u32 offset; // offset in bytes from section start
|
u32 offset; // offset in bytes from section start
|
||||||
} ConstDataProps;
|
} ConstDataProps;
|
||||||
|
|
||||||
#define ConstDataProps_construct(NAME, SIZE, OFFSET) ((ConstDataProps){ .name = NAME, .size = SIZE, .offset = OFFSET})
|
List_declare(ConstDataProps)
|
||||||
|
|
||||||
List_declare(ConstDataProps);
|
#define ConstDataProps_construct(NAME, SIZE, OFFSET) ((ConstDataProps){ .name = NAME, .size = SIZE, .offset = OFFSET})
|
||||||
HashMap_declare(ConstDataProps);
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum NamedRefType {
|
typedef enum NamedRefType {
|
||||||
@@ -32,35 +32,33 @@ typedef struct NamedRef {
|
|||||||
u32 offset; // offset in bytes from section start
|
u32 offset; // offset in bytes from section start
|
||||||
} NamedRef;
|
} NamedRef;
|
||||||
|
|
||||||
#define NamedRef_construct(NAME, TYPE, OFFSET) ((NamedRef){ .name = NAME, .type = TYPE, .offset = OFFSET})
|
|
||||||
|
|
||||||
List_declare(NamedRef);
|
List_declare(NamedRef);
|
||||||
|
|
||||||
|
#define NamedRef_construct(NAME, TYPE, OFFSET) ((NamedRef){ .name = NAME, .type = TYPE, .offset = OFFSET})
|
||||||
|
|
||||||
|
|
||||||
typedef struct CompiledSection {
|
typedef struct CompiledSection {
|
||||||
str name;
|
str name;
|
||||||
CompiledSection* next;
|
CompiledSection* next;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
List_ConstDataProps const_data_props_list;
|
List(ConstDataProps) const_data_props_list;
|
||||||
List_NamedRef named_refs;
|
List(NamedRef) named_refs;
|
||||||
List_u8 bytes;
|
List(u8) bytes;
|
||||||
} CompiledSection;
|
} CompiledSection;
|
||||||
|
|
||||||
void CompiledSection_construct(CompiledSection* ptr, str name);
|
List_declare(CompiledSection)
|
||||||
void CompiledSection_free(CompiledSection* ptr);
|
|
||||||
|
|
||||||
List_declare(CompiledSection);
|
void CompiledSection_construct(CompiledSection* ptr, str name);
|
||||||
typedef CompiledSection* CompiledSectionPtr;
|
void CompiledSection_destroy(CompiledSection* ptr);
|
||||||
HashMap_declare(CompiledSectionPtr);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct BinaryObject {
|
typedef struct BinaryObject {
|
||||||
List_CompiledSection section_list;
|
List(CompiledSection) comp_sec_list;
|
||||||
HashMap_CompiledSectionPtr section_map;
|
HashMap(u32) comp_sec_i_map;
|
||||||
NULLABLE(CompiledSection*) main_section;
|
NULLABLE(CompiledSection*) main_sec;
|
||||||
HashMap_ConstDataProps const_data_map;
|
HashMap(ConstDataProps) const_data_props_map;
|
||||||
u32 total_size;
|
u32 total_size;
|
||||||
} BinaryObject;
|
} BinaryObject;
|
||||||
|
|
||||||
void BinaryObject_construct(BinaryObject* ptr);
|
void BinaryObject_construct(BinaryObject* ptr);
|
||||||
void BinaryObject_free(BinaryObject* ptr);
|
void BinaryObject_destroy(BinaryObject* ptr);
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
#include "Compiler_internal.h"
|
#include "Compiler_internal.h"
|
||||||
|
|
||||||
HashMap_define(SectionPtr, HashMap_DESTROY_VALUE_FUNC_NULL);
|
void Compiler_construct(Compiler* cmp){
|
||||||
|
|
||||||
void Compiler_init(Compiler* cmp){
|
|
||||||
memset(cmp, 0, sizeof(Compiler));
|
memset(cmp, 0, sizeof(Compiler));
|
||||||
cmp->state = CompilerState_Initial;
|
cmp->state = CompilerState_Initial;
|
||||||
cmp->tokens = List_Token_alloc(4096);
|
cmp->tokens = List_Token_alloc(4096);
|
||||||
cmp->line_lengths = List_u32_alloc(1024);
|
cmp->line_lengths = List_u32_alloc(1024);
|
||||||
AST_init(&cmp->ast);
|
AST_construct(&cmp->ast);
|
||||||
BinaryObject_construct(&cmp->binary);
|
BinaryObject_construct(&cmp->binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler_free(Compiler* cmp){
|
void Compiler_destroy(Compiler* cmp){
|
||||||
free(cmp->code.data);
|
str_destroy(cmp->code);
|
||||||
free(cmp->tokens.data);
|
List_Token_destroy(&cmp->tokens);
|
||||||
free(cmp->line_lengths.data);
|
List_u32_destroy(&cmp->line_lengths);
|
||||||
AST_free(&cmp->ast);
|
AST_destroy(&cmp->ast);
|
||||||
BinaryObject_free(&cmp->binary);
|
BinaryObject_destroy(&cmp->binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
|
CodePos Compiler_getLineAndColumn(Compiler* cmp, u32 pos){
|
||||||
@@ -44,7 +42,7 @@ void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...){
|
|||||||
char* real_format = strcat_malloc(position_str, context, "] ", format);
|
char* real_format = strcat_malloc(position_str, context, "] ", format);
|
||||||
va_list argv;
|
va_list argv;
|
||||||
va_start(argv, format);
|
va_start(argv, format);
|
||||||
char* NULLABLE(buf) = vsprintf_malloc(512, real_format, argv);
|
char* NULLABLE(buf) = vsprintf_malloc(real_format, argv);
|
||||||
va_end(argv);
|
va_end(argv);
|
||||||
free(real_format);
|
free(real_format);
|
||||||
if(buf == NULL){
|
if(buf == NULL){
|
||||||
@@ -64,20 +62,24 @@ str Compiler_constructTokenStr(Compiler* cmp, Token t){
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define List_u8_pushStruct(L_PTR, S_PTR) List_u8_pushMany((L_PTR), (void*)(S_PTR), sizeof(*(S_PTR)))
|
||||||
|
|
||||||
static bool compileSection(Compiler* cmp, Section* sec){
|
static bool compileSection(Compiler* cmp, Section* sec){
|
||||||
CompiledSection* cs = List_CompiledSection_expand(&cmp->binary.section_list, 1);
|
u32 cs_index = cmp->binary.comp_sec_list.len;
|
||||||
|
CompiledSection* cs = List_CompiledSection_expand(&cmp->binary.comp_sec_list, 1);
|
||||||
CompiledSection_construct(cs, sec->name);
|
CompiledSection_construct(cs, sec->name);
|
||||||
if(!HashMap_CompiledSectionPtr_tryPush(&cmp->binary.section_map, cs->name, cs)){
|
if(!HashMap_tryPush(&cmp->binary.comp_sec_i_map, cs->name, &cs_index)){
|
||||||
returnError("duplicate section '%s'", str_copy(sec->name).data);
|
returnError("duplicate section '%s'", str_copy(sec->name).data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile code
|
// compile code
|
||||||
u8 zeroes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
u8 zeroes_8[8];
|
||||||
for(u32 i = 0; i < sec->code.len; i++){
|
memset(zeroes_8, 0, sizeof(zeroes_8));
|
||||||
Operation* op = &sec->code.data[i];
|
for(u32 i = 0; i < sec->operations_list.len; i++){
|
||||||
List_u8_pushMany(&cs->bytes, (void*)&op->opcode, sizeof(op->opcode));
|
Operation* op = sec->operations_list.data + i;
|
||||||
|
List_u8_pushStruct(&cs->bytes, &op->opcode);
|
||||||
for(u32 j = 0; j < op->args.len; j++){
|
for(u32 j = 0; j < op->args.len; j++){
|
||||||
Argument* arg = &op->args.data[j];
|
Argument* arg = op->args.data + j;
|
||||||
switch(arg->type){
|
switch(arg->type){
|
||||||
case ArgumentType_VarDataName:
|
case ArgumentType_VarDataName:
|
||||||
returnError("argument type 'VarDataName' is not supported yet");
|
returnError("argument type 'VarDataName' is not supported yet");
|
||||||
@@ -90,31 +92,38 @@ static bool compileSection(Compiler* cmp, Section* sec){
|
|||||||
List_u8_push(&cs->bytes, arg->value.register_code);
|
List_u8_push(&cs->bytes, arg->value.register_code);
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstValue:
|
case ArgumentType_ConstValue:
|
||||||
List_u8_pushMany(&cs->bytes, (void*)&arg->value.i, 8);
|
List_u8_pushStruct(&cs->bytes, &arg->value.i);
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstDataPointer:
|
case ArgumentType_ConstDataPointer:
|
||||||
List_NamedRef_push(&cs->named_refs, NamedRef_construct(
|
List_NamedRef_push(&cs->named_refs,
|
||||||
|
NamedRef_construct(
|
||||||
arg->value.data_name,
|
arg->value.data_name,
|
||||||
NamedRefType_Ptr,
|
NamedRefType_Ptr,
|
||||||
cs->bytes.len));
|
cs->bytes.len
|
||||||
List_u8_pushMany(&cs->bytes, zeroes, 8);
|
)
|
||||||
|
);
|
||||||
|
List_u8_pushStruct(&cs->bytes, zeroes_8);
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstDataSize:
|
case ArgumentType_ConstDataSize:
|
||||||
List_NamedRef_push(&cs->named_refs, NamedRef_construct(
|
List_NamedRef_push(&cs->named_refs,
|
||||||
|
NamedRef_construct(
|
||||||
arg->value.data_name,
|
arg->value.data_name,
|
||||||
NamedRefType_Size,
|
NamedRefType_Size,
|
||||||
cs->bytes.len));
|
cs->bytes.len
|
||||||
List_u8_pushMany(&cs->bytes, zeroes, 8);
|
)
|
||||||
|
);
|
||||||
|
List_u8_pushStruct(&cs->bytes, zeroes_8);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile data
|
// compile data
|
||||||
for(u32 i = 0; i < sec->data.len; i++){
|
for(u32 i = 0; i < sec->data_definitions_list.len; i++){
|
||||||
DataDefinition* dd = &sec->data.data[i];
|
DataDefinition* dd = sec->data_definitions_list.data + i;
|
||||||
List_ConstDataProps_push(&cs->const_data_props_list, ConstDataProps_construct(dd->name, dd->data.len, cs->bytes.len));
|
ConstDataProps cd_props = ConstDataProps_construct(dd->name, dd->data_bytes.len, cs->bytes.len);
|
||||||
List_u8_pushMany(&cs->bytes, dd->data.data, dd->data.len);
|
List_ConstDataProps_push(&cs->const_data_props_list, cd_props);
|
||||||
|
List_u8_pushMany(&cs->bytes, dd->data_bytes.data, dd->data_bytes.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: push padding
|
// TODO: push padding
|
||||||
@@ -127,7 +136,7 @@ static bool compileBinary(Compiler* cmp){
|
|||||||
cmp->state = CompilerState_Compiling;
|
cmp->state = CompilerState_Compiling;
|
||||||
|
|
||||||
for(u32 i = 0; i < cmp->ast.sections.len; i++){
|
for(u32 i = 0; i < cmp->ast.sections.len; i++){
|
||||||
SectionPtr sec = &cmp->ast.sections.data[i];
|
Section* sec = cmp->ast.sections.data + i;
|
||||||
if(!compileSection(cmp, sec)){
|
if(!compileSection(cmp, sec)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -135,17 +144,18 @@ static bool compileBinary(Compiler* cmp){
|
|||||||
|
|
||||||
// find main section
|
// find main section
|
||||||
str main_sec_name = STR("main");
|
str main_sec_name = STR("main");
|
||||||
CompiledSection** main_sec_ptrptr = HashMap_CompiledSectionPtr_tryGetPtr(&cmp->binary.section_map, main_sec_name);
|
u32* main_sec_i_ptr = HashMap_tryGetPtr(&cmp->binary.comp_sec_i_map, main_sec_name);
|
||||||
if(main_sec_ptrptr == NULL){
|
if(main_sec_i_ptr == NULL){
|
||||||
returnError("no 'main' section was defined");
|
returnError("no 'main' section was defined");
|
||||||
}
|
}
|
||||||
cmp->binary.main_section = *main_sec_ptrptr;
|
u32 main_sec_i = *main_sec_i_ptr;
|
||||||
|
cmp->binary.main_sec = cmp->binary.comp_sec_list.data + main_sec_i;
|
||||||
|
|
||||||
// create linked list of CompiledSection where main is the first
|
// create linked list of CompiledSection where main is the first
|
||||||
CompiledSection* prev_sec = *main_sec_ptrptr;
|
CompiledSection* prev_sec = cmp->binary.main_sec;
|
||||||
u32 total_size = 0;
|
u32 total_size = 0;
|
||||||
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
|
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
|
||||||
CompiledSection* sec = &cmp->binary.section_list.data[i];
|
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
|
||||||
total_size += sec->bytes.len;
|
total_size += sec->bytes.len;
|
||||||
bool is_main_sec = str_equals(sec->name, main_sec_name);
|
bool is_main_sec = str_equals(sec->name, main_sec_name);
|
||||||
if(!is_main_sec){
|
if(!is_main_sec){
|
||||||
@@ -153,13 +163,13 @@ static bool compileBinary(Compiler* cmp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConstDataProps cd = ConstDataProps_construct(sec->name, sec->bytes.len, sec->offset);
|
ConstDataProps cd = ConstDataProps_construct(sec->name, sec->bytes.len, sec->offset);
|
||||||
if(!HashMap_ConstDataProps_tryPush(&cmp->binary.const_data_map, cd.name, cd)){
|
if(!HashMap_tryPush(&cmp->binary.const_data_props_map, cd.name, &cd)){
|
||||||
returnError("duplicate named data '%s'", str_copy(cd.name).data);
|
returnError("duplicate named data '%s'", str_copy(cd.name).data);
|
||||||
}
|
}
|
||||||
for(u32 j = 0; j < sec->const_data_props_list.len; j++){
|
for(u32 j = 0; j < sec->const_data_props_list.len; j++){
|
||||||
cd = sec->const_data_props_list.data[j];
|
cd = sec->const_data_props_list.data[j];
|
||||||
cd.offset += sec->offset;
|
cd.offset += sec->offset;
|
||||||
if(!HashMap_ConstDataProps_tryPush(&cmp->binary.const_data_map, cd.name, cd)){
|
if(!HashMap_tryPush(&cmp->binary.const_data_props_map, cd.name, &cd)){
|
||||||
returnError("duplicate named data '%s'", str_copy(cd.name).data);
|
returnError("duplicate named data '%s'", str_copy(cd.name).data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,18 +181,18 @@ static bool compileBinary(Compiler* cmp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert calculated offsets into sections
|
// insert calculated offsets into sections
|
||||||
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
|
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
|
||||||
CompiledSection* sec = &cmp->binary.section_list.data[i];
|
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
|
||||||
for(u32 j = 0; j < sec->named_refs.len; j++){
|
for(u32 j = 0; j < sec->named_refs.len; j++){
|
||||||
NamedRef* ref = &sec->named_refs.data[j];
|
NamedRef* ref = sec->named_refs.data + j;
|
||||||
|
|
||||||
ConstDataProps* target_data = HashMap_ConstDataProps_tryGetPtr(
|
ConstDataProps* target_data = HashMap_tryGetPtr(
|
||||||
&cmp->binary.const_data_map, ref->name);
|
&cmp->binary.const_data_props_map, ref->name);
|
||||||
if(target_data == NULL){
|
if(target_data == NULL){
|
||||||
returnError("can't find named data '%s'", str_copy(ref->name).data);
|
returnError("can't find named data '%s'", str_copy(ref->name).data);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64* ref_value_ptr = (void*)(sec->bytes.data + ref->offset);
|
u64* ref_value_ptr = (void*)((u8*)sec->bytes.data + ref->offset);
|
||||||
switch(ref->type){
|
switch(ref->type){
|
||||||
default:
|
default:
|
||||||
returnError("invalid NamedRefType %i", ref->type);
|
returnError("invalid NamedRefType %i", ref->type);
|
||||||
@@ -203,7 +213,7 @@ static bool compileBinary(Compiler* cmp){
|
|||||||
static bool writeBinaryFile(Compiler* cmp, FILE* f){
|
static bool writeBinaryFile(Compiler* cmp, FILE* f){
|
||||||
returnErrorIf_auto(cmp->state != CompilerState_Compiling);
|
returnErrorIf_auto(cmp->state != CompilerState_Compiling);
|
||||||
|
|
||||||
CompiledSection* sec = cmp->binary.main_section;
|
CompiledSection* sec = cmp->binary.main_sec;
|
||||||
while(sec){
|
while(sec){
|
||||||
fwrite(sec->bytes.data, 1, sec->bytes.len, f);
|
fwrite(sec->bytes.data, 1, sec->bytes.len, f);
|
||||||
fflush(f);
|
fflush(f);
|
||||||
@@ -225,19 +235,19 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
StringBuilder_append_char(&sb, ret);
|
StringBuilder_append_char(&sb, ret);
|
||||||
}
|
}
|
||||||
if(ferror(f)){
|
if(ferror(f)){
|
||||||
StringBuilder_free(&sb);
|
StringBuilder_destroy(&sb);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
returnError("can't read file '%s'", source_file_name);
|
returnError("can't read file '%s'", source_file_name);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
if(sb.buffer.len == 0){
|
if(sb.buffer.len == 0){
|
||||||
StringBuilder_free(&sb);
|
StringBuilder_destroy(&sb);
|
||||||
returnError("soucre file is empty");
|
returnError("soucre file is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp->code = str_copy(StringBuilder_getStr(&sb));
|
cmp->code = str_copy(StringBuilder_getStr(&sb));
|
||||||
StringBuilder_free(&sb);
|
StringBuilder_destroy(&sb);
|
||||||
|
|
||||||
f = fopen(out_file_name, "wb");
|
f = fopen(out_file_name, "wb");
|
||||||
if(f == NULL){
|
if(f == NULL){
|
||||||
@@ -290,21 +300,20 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
if (debug_log){
|
if (debug_log){
|
||||||
printf("-------------------------------------[AST]-------------------------------------\n");
|
printf("-------------------------------------[AST]-------------------------------------\n");
|
||||||
for(u32 i = 0; i < cmp->ast.sections.len; i++){
|
for(u32 i = 0; i < cmp->ast.sections.len; i++){
|
||||||
Section* sec = &cmp->ast.sections.data[i];
|
Section* sec = cmp->ast.sections.data + i;
|
||||||
str tmpstr = str_copy(sec->name);
|
printf("section '"FMT_str"'\n", sec->name.len, sec->name.data);
|
||||||
printf("section '%s'\n", tmpstr.data);
|
|
||||||
free(tmpstr.data);
|
|
||||||
|
|
||||||
for(u32 j = 0; j < sec->data.len; j++){
|
for(u32 j = 0; j < sec->data_definitions_list.len; j++){
|
||||||
DataDefinition* dd = &sec->data.data[j];
|
DataDefinition* dd = sec->data_definitions_list.data + j;
|
||||||
tmpstr = str_copy(dd->name);
|
printf(" const%u "FMT_str" (len %u)\n",
|
||||||
printf(" const%u %s (len %u)\n", dd->element_size * 8, tmpstr.data, dd->data.len/dd->element_size);
|
dd->element_size * 8,
|
||||||
free(tmpstr.data);
|
dd->name.len, dd->name.data,
|
||||||
|
dd->data_bytes.len/dd->element_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(u32 j = 0; j < sec->code.len; j++){
|
for(u32 j = 0; j < sec->operations_list.len; j++){
|
||||||
Operation* op = &sec->code.data[j];
|
Operation* op = sec->operations_list.data + j;
|
||||||
const Instruction* instr = Instruction_getByOpcode(op->opcode);
|
const Instruction* instr = Instruction_getByOpcode(op->opcode);
|
||||||
if(instr == NULL){
|
if(instr == NULL){
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@@ -313,35 +322,29 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
|
|
||||||
printf(" %s", instr->name.data);
|
printf(" %s", instr->name.data);
|
||||||
for(u32 k = 0; k < op->args.len; k++){
|
for(u32 k = 0; k < op->args.len; k++){
|
||||||
Argument* arg = &op->args.data[k];
|
Argument* arg = op->args.data + k;
|
||||||
printf(" %s(", ArgumentType_toString(arg->type).data);
|
printf(" %s(", ArgumentType_toString(arg->type).data);
|
||||||
|
|
||||||
switch(arg->type){
|
switch(arg->type){
|
||||||
default:
|
default:
|
||||||
fclose(f);
|
fclose(f);
|
||||||
returnError("invalid argument type %i", arg->type);
|
returnError("invalid argument type %i", arg->type);
|
||||||
case ArgumentType_Register:
|
case ArgumentType_Register:;
|
||||||
str register_name = RegisterCode_toString(arg->value.register_code);
|
str register_name = RegisterCode_toString(arg->value.register_code);
|
||||||
printf("%s 0x%x", register_name.data, arg->value.register_code);
|
printf("%s 0x%x", register_name.data, arg->value.register_code);
|
||||||
free(register_name.data);
|
str_destroy(register_name);
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstValue:
|
case ArgumentType_ConstValue:
|
||||||
printf(IFWIN("%lli", "%li"), arg->value.i);
|
printf(IFWIN("%lli", "%li"), arg->value.i);
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstDataPointer:
|
case ArgumentType_ConstDataPointer:
|
||||||
tmpstr = str_copy(arg->value.data_name);
|
printf("@"FMT_str, arg->value.data_name.len, arg->value.data_name.data);
|
||||||
printf("@%s", tmpstr.data);
|
|
||||||
free(tmpstr.data);
|
|
||||||
break;
|
break;
|
||||||
case ArgumentType_ConstDataSize:
|
case ArgumentType_ConstDataSize:
|
||||||
tmpstr = str_copy(arg->value.data_name);
|
printf("#"FMT_str, arg->value.data_name.len, arg->value.data_name.data);
|
||||||
printf("#%s", tmpstr.data);
|
|
||||||
free(tmpstr.data);
|
|
||||||
break;
|
break;
|
||||||
case ArgumentType_VarDataName:
|
case ArgumentType_VarDataName:
|
||||||
tmpstr = str_copy(arg->value.data_name);
|
printf(FMT_str, arg->value.data_name.len, arg->value.data_name.data);
|
||||||
printf("%s", tmpstr.data);
|
|
||||||
free(tmpstr.data);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,11 +366,10 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
|
|||||||
success = compileBinary(cmp);
|
success = compileBinary(cmp);
|
||||||
|
|
||||||
if(debug_log){
|
if(debug_log){
|
||||||
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
|
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
|
||||||
CompiledSection* sec = &cmp->binary.section_list.data[i];
|
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
|
||||||
str tmpstr = str_copy(sec->name);
|
printf("compiled section '"FMT_str"' to %u bytes with offset 0x%x\n",
|
||||||
printf("compiled section '%s' to %u bytes with offset 0x%x\n", tmpstr.data, sec->bytes.len, sec->offset);
|
sec->name.len, sec->name.data, sec->bytes.len, sec->offset);
|
||||||
free(tmpstr.data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "../collections/List.h"
|
#include "tlibc/collections/List.h"
|
||||||
#include "../collections/HashMap.h"
|
#include "tlibc/collections/List_impl/List_u32.h"
|
||||||
|
#include "tlibc/collections/HashMap.h"
|
||||||
#include "Token.h"
|
#include "Token.h"
|
||||||
#include "Binary.h"
|
#include "Binary.h"
|
||||||
|
|
||||||
@@ -15,8 +16,6 @@ typedef enum CompilerState {
|
|||||||
CompilerState_Success
|
CompilerState_Success
|
||||||
} CompilerState;
|
} CompilerState;
|
||||||
|
|
||||||
typedef Section* SectionPtr;
|
|
||||||
HashMap_declare(SectionPtr);
|
|
||||||
|
|
||||||
typedef struct Compiler {
|
typedef struct Compiler {
|
||||||
/* general fields */
|
/* general fields */
|
||||||
@@ -26,8 +25,8 @@ typedef struct Compiler {
|
|||||||
CompilerState state;
|
CompilerState state;
|
||||||
NULLABLE(char* error_message);
|
NULLABLE(char* error_message);
|
||||||
/* lexer fields */
|
/* lexer fields */
|
||||||
List_Token tokens;
|
List(Token) tokens;
|
||||||
List_u32 line_lengths;
|
List(u32) line_lengths;
|
||||||
/* parser fields */
|
/* parser fields */
|
||||||
AST ast;
|
AST ast;
|
||||||
u32 tok_i;
|
u32 tok_i;
|
||||||
@@ -35,8 +34,8 @@ typedef struct Compiler {
|
|||||||
BinaryObject binary;
|
BinaryObject binary;
|
||||||
} Compiler;
|
} Compiler;
|
||||||
|
|
||||||
void Compiler_init(Compiler* cmp);
|
void Compiler_construct(Compiler* cmp);
|
||||||
void Compiler_free(Compiler* cmp);
|
void Compiler_destroy(Compiler* cmp);
|
||||||
|
|
||||||
/// @brief compile assembly language code to machine code
|
/// @brief compile assembly language code to machine code
|
||||||
/// @return true if no errors, false if any error occured (check cmp->error_message)
|
/// @return true if no errors, false if any error occured (check cmp->error_message)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
#include "../string/StringBuilder.h"
|
#include "tlibc/string/StringBuilder.h"
|
||||||
|
|
||||||
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...) __attribute__((__format__(__printf__, 3, 4)));
|
void _Compiler_setError(Compiler* cmp, cstr context, cstr format, ...) __attribute__((__format__(__printf__, 3, 4)));
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ static void readLabel(Compiler* cmp){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isAlphabeticalLower(c) && !isAlphabeticalUpper(c) && !isDigit(c) &&
|
if(!char_isLatinLower(c) && !char_isLatinUpper(c) && !char_isDigit(c) &&
|
||||||
c != '_' && c != '.'){
|
c != '_' && c != '.'){
|
||||||
setError(Error_unexpectedCharacter(c));
|
setError(Error_unexpectedCharacter(c));
|
||||||
return;
|
return;
|
||||||
@@ -169,7 +169,7 @@ static void readArguments(Compiler* cmp){
|
|||||||
tok.type = TokenType_NamedDataPointer;
|
tok.type = TokenType_NamedDataPointer;
|
||||||
else if(c == '#')
|
else if(c == '#')
|
||||||
tok.type = TokenType_NamedDataSize;
|
tok.type = TokenType_NamedDataSize;
|
||||||
else if(isDigit(c))
|
else if(char_isDigit(c))
|
||||||
tok.type = TokenType_Number;
|
tok.type = TokenType_Number;
|
||||||
else tok.type = TokenType_Name;
|
else tok.type = TokenType_Name;
|
||||||
}
|
}
|
||||||
@@ -211,7 +211,7 @@ static void readInstruction(Compiler* cmp){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isAlphabeticalLower(c) && !isAlphabeticalUpper(c) && !isDigit(c)){
|
if(!char_isLatinLower(c) && !char_isLatinUpper(c) && !char_isDigit(c)){
|
||||||
setError(Error_unexpectedCharacter(c));
|
setError(Error_unexpectedCharacter(c));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -248,7 +248,7 @@ bool Compiler_lex(Compiler* cmp){
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// try read instruction
|
// try read instruction
|
||||||
if(isAlphabeticalLower(c) || isAlphabeticalUpper(c))
|
if(char_isLatinLower(c) || char_isLatinUpper(c))
|
||||||
readInstruction(cmp);
|
readInstruction(cmp);
|
||||||
else returnError(Error_unexpectedCharacter(c));
|
else returnError(Error_unexpectedCharacter(c));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -6,34 +6,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define setError_unexpectedToken(T) {\
|
#define setError_unexpectedToken(T) {\
|
||||||
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
|
str tok_str_tmp = Compiler_constructTokenStr(cmp, T);\
|
||||||
cmp->pos = T.begin;\
|
cmp->pos = T.begin;\
|
||||||
Compiler_setError(cmp, "unexpected token '%s'", tok_str.data);\
|
Compiler_setError(cmp, "unexpected token '"FMT_str"'", tok_str_tmp.len, tok_str_tmp.data);\
|
||||||
free(tok_str.data);\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define setError_unexpectedTokenChar(T, I) {\
|
#define setError_unexpectedTokenChar(T, I) {\
|
||||||
cmp->pos = T.begin + I;\
|
cmp->pos = T.begin + I;\
|
||||||
Compiler_setError(cmp, "unexpected token '%c'", cmp->code.data[cmp->pos]);\
|
Compiler_setError(cmp, "unexpected character '%c'", cmp->code.data[cmp->pos]);\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define setError_unexpectedInstruction(T) {\
|
#define setError_unexpectedInstruction(T) {\
|
||||||
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
|
str tok_str_tmp = Compiler_constructTokenStr(cmp, T);\
|
||||||
cmp->pos = T.begin;\
|
cmp->pos = T.begin;\
|
||||||
Compiler_setError(cmp, "unexpected instruction '%s'", tok_str.data);\
|
Compiler_setError(cmp, "unexpected instruction '"FMT_str"'", tok_str_tmp.len, tok_str_tmp.data);\
|
||||||
free(tok_str.data);\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define Error_TokenUnset "token of undefined type"
|
#define Error_TokenUnset "token of undefined type"
|
||||||
#define Error_BitSize "invalid size in bits"
|
#define Error_BitSize "invalid size in bits"
|
||||||
|
|
||||||
static void List_u8_pushBytes(List_u8* l, void* value, u32 startIndex, u32 count){
|
|
||||||
u8* v = value;
|
|
||||||
for(u32 byte_i = startIndex; byte_i < startIndex + count; byte_i++){
|
|
||||||
List_u8_push(l, v[byte_i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isVarSizeBits(u32 B) { return (B == 8 || B == 16 || B == 32 || B == 64); }
|
static inline bool isVarSizeBits(u32 B) { return (B == 8 || B == 16 || B == 32 || B == 64); }
|
||||||
|
|
||||||
static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
|
static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
|
||||||
@@ -76,7 +67,7 @@ static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
|
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
|
||||||
StringBuilder_free(&sb);
|
StringBuilder_destroy(&sb);
|
||||||
return str_null;
|
return str_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,13 +81,13 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
|
|||||||
i32 _element_size_bits;
|
i32 _element_size_bits;
|
||||||
str _instr_name_zero_terminated = str_copy(instr_name);
|
str _instr_name_zero_terminated = str_copy(instr_name);
|
||||||
if(sscanf(_instr_name_zero_terminated.data, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
|
if(sscanf(_instr_name_zero_terminated.data, "const%i", &_element_size_bits) != 1 || !isVarSizeBits(_element_size_bits)){
|
||||||
free(_instr_name_zero_terminated.data);
|
str_destroy(_instr_name_zero_terminated);
|
||||||
setError(Error_BitSize);
|
setError(Error_BitSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(_instr_name_zero_terminated.data);
|
str_destroy(_instr_name_zero_terminated);
|
||||||
ddf->element_size = _element_size_bits / 8;
|
ddf->element_size = _element_size_bits / 8;
|
||||||
ddf->data = List_u8_alloc(32);
|
ddf->data_bytes = List_u8_alloc(32);
|
||||||
|
|
||||||
Token tok = cmp->tokens.data[++cmp->tok_i];
|
Token tok = cmp->tokens.data[++cmp->tok_i];
|
||||||
if(tok.type != TokenType_Name){
|
if(tok.type != TokenType_Name){
|
||||||
@@ -130,13 +121,17 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
|
|||||||
processed_str = str_copy(tok_str);
|
processed_str = str_copy(tok_str);
|
||||||
if(str_seekChar(tok_str, '.', 0) != -1){
|
if(str_seekChar(tok_str, '.', 0) != -1){
|
||||||
f64 f = atof(processed_str.data);
|
f64 f = atof(processed_str.data);
|
||||||
List_u8_pushBytes(&ddf->data, &f, 8 - ddf->element_size, ddf->element_size);
|
// for numbers smaller than 64 bits
|
||||||
|
u8* value_part = (u8*)&f + 8 - ddf->element_size;
|
||||||
|
List_u8_pushMany(&ddf->data_bytes, value_part, ddf->element_size);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
i64 i = atoll(processed_str.data);
|
i64 i = atoll(processed_str.data);
|
||||||
List_u8_pushBytes(&ddf->data, &i, 8 - ddf->element_size, ddf->element_size);
|
// for numbers smaller than 64 bits
|
||||||
|
u8* value_part = (u8*)&i + 8 - ddf->element_size;
|
||||||
|
List_u8_pushMany(&ddf->data_bytes, value_part, ddf->element_size);
|
||||||
}
|
}
|
||||||
free(processed_str.data);
|
str_destroy(processed_str);
|
||||||
break;
|
break;
|
||||||
case TokenType_Char:
|
case TokenType_Char:
|
||||||
tok.begin += 1;
|
tok.begin += 1;
|
||||||
@@ -148,16 +143,16 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
|
|||||||
setError("can't fit char of size %i in %u bit variable", processed_str.len, _element_size_bits);
|
setError("can't fit char of size %i in %u bit variable", processed_str.len, _element_size_bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
|
List_u8_pushMany(&ddf->data_bytes, (u8*)processed_str.data, processed_str.len);
|
||||||
free(processed_str.data);
|
str_destroy(processed_str);
|
||||||
break;
|
break;
|
||||||
case TokenType_String:
|
case TokenType_String:
|
||||||
tok.begin += 1;
|
tok.begin += 1;
|
||||||
tok.length -= 2;
|
tok.length -= 2;
|
||||||
tok_str = Compiler_constructTokenStr(cmp, tok);
|
tok_str = Compiler_constructTokenStr(cmp, tok);
|
||||||
processed_str = resolveEscapeSequences(cmp, tok_str);
|
processed_str = resolveEscapeSequences(cmp, tok_str);
|
||||||
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
|
List_u8_pushMany(&ddf->data_bytes, (u8*)processed_str.data, processed_str.len);
|
||||||
free(processed_str.data);
|
str_destroy(processed_str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +168,7 @@ static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
|
|||||||
}
|
}
|
||||||
|
|
||||||
operPtr->opcode = instr->opcode;
|
operPtr->opcode = instr->opcode;
|
||||||
operPtr->args = List_Argument_alloc(8);
|
operPtr->args = List_Argument_alloc(4);
|
||||||
Argument arg = (Argument){ .type = ArgumentType_Unset, .value.i = 0 };
|
Argument arg = (Argument){ .type = ArgumentType_Unset, .value.i = 0 };
|
||||||
str tok_str = str_null;
|
str tok_str = str_null;
|
||||||
str processed_str = str_null;
|
str processed_str = str_null;
|
||||||
@@ -204,7 +199,7 @@ static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
|
|||||||
else {
|
else {
|
||||||
arg.value.i = atoll(processed_str.data);
|
arg.value.i = atoll(processed_str.data);
|
||||||
}
|
}
|
||||||
free(processed_str.data);
|
str_destroy(processed_str);
|
||||||
List_Argument_push(&operPtr->args, arg);
|
List_Argument_push(&operPtr->args, arg);
|
||||||
break;
|
break;
|
||||||
case TokenType_Name:
|
case TokenType_Name:
|
||||||
@@ -257,7 +252,7 @@ bool Compiler_parse(Compiler* cmp){
|
|||||||
case TokenType_Label:
|
case TokenType_Label:
|
||||||
// create new section
|
// create new section
|
||||||
sec = List_Section_expand(&cmp->ast.sections, 1);
|
sec = List_Section_expand(&cmp->ast.sections, 1);
|
||||||
Section_init(sec, Compiler_constructTokenStr(cmp, tok));
|
Section_construct(sec, Compiler_constructTokenStr(cmp, tok));
|
||||||
break;
|
break;
|
||||||
case TokenType_Instruction:
|
case TokenType_Instruction:
|
||||||
if(sec == NULL)
|
if(sec == NULL)
|
||||||
@@ -265,12 +260,12 @@ bool Compiler_parse(Compiler* cmp){
|
|||||||
str instr_name = Compiler_constructTokenStr(cmp, tok);
|
str instr_name = Compiler_constructTokenStr(cmp, tok);
|
||||||
// data definition starts with const
|
// data definition starts with const
|
||||||
if(str_startsWith(instr_name, STR("const"))){
|
if(str_startsWith(instr_name, STR("const"))){
|
||||||
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data, 1);
|
DataDefinition* dataDefPtr = List_DataDefinition_expand(&sec->data_definitions_list, 1);
|
||||||
memset(dataDefPtr, 0, sizeof(DataDefinition));
|
memset(dataDefPtr, 0, sizeof(DataDefinition));
|
||||||
parseDataDefinition(cmp, instr_name, dataDefPtr);
|
parseDataDefinition(cmp, instr_name, dataDefPtr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Operation* operPtr = List_Operation_expand(&sec->code, 1);
|
Operation* operPtr = List_Operation_expand(&sec->operations_list, 1);
|
||||||
memset(operPtr, 0, sizeof(Operation));
|
memset(operPtr, 0, sizeof(Operation));
|
||||||
parseOperation(cmp, instr_name, operPtr);
|
parseOperation(cmp, instr_name, operPtr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#include "Token.h"
|
#include "Token.h"
|
||||||
|
|
||||||
List_define(Token);
|
Array_declare(str);
|
||||||
|
|
||||||
static str _TokenType_str[] = {
|
static Array(str) _TokenType_str_array = ARRAY(str, {
|
||||||
STR("Unset"),
|
STR("Unset"),
|
||||||
STR("SingleLineComment"),
|
STR("SingleLineComment"),
|
||||||
STR("MultiLineComment"),
|
STR("MultiLineComment"),
|
||||||
@@ -15,10 +15,10 @@ static str _TokenType_str[] = {
|
|||||||
STR("NamedDataPointer"),
|
STR("NamedDataPointer"),
|
||||||
STR("NamedDataSize"),
|
STR("NamedDataSize"),
|
||||||
STR("OperationEnd"),
|
STR("OperationEnd"),
|
||||||
};
|
});
|
||||||
|
|
||||||
str TokenType_toString(TokenType t){
|
str TokenType_toString(TokenType t){
|
||||||
if(t >= ARRAY_SIZE(_TokenType_str))
|
if(t >= _TokenType_str_array.len)
|
||||||
return STR("!!TokenType INDEX_ERROR!!");
|
return STR("!!TokenType INDEX_ERROR!!");
|
||||||
return _TokenType_str[t];
|
return _TokenType_str_array.data[t];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
#include "../collections/List.h"
|
#include "tlibc/collections/List.h"
|
||||||
|
|
||||||
typedef enum TokenType {
|
typedef enum TokenType {
|
||||||
TokenType_Unset, // initial value
|
TokenType_Unset, // initial value
|
||||||
@@ -26,6 +26,6 @@ typedef struct Token {
|
|||||||
TokenType type : 8; // type of token (8 bits)
|
TokenType type : 8; // type of token (8 bits)
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
List_declare(Token);
|
List_declare(Token)
|
||||||
|
|
||||||
#define Token_construct(TYPE, BEGIN, LEN) ((Token){ .type = TYPE, .begin = BEGIN, .length = LEN })
|
#define Token_construct(TYPE, BEGIN, LEN) ((Token){ .type = TYPE, .begin = BEGIN, .length = LEN })
|
||||||
|
|||||||
52
src/cstr.c
52
src/cstr.c
@@ -1,52 +0,0 @@
|
|||||||
#include "std.h"
|
|
||||||
|
|
||||||
char* _strcat_malloc(size_t n, cstr str0, ...){
|
|
||||||
va_list argv;
|
|
||||||
va_start(argv, str0);
|
|
||||||
char* heap_ptr = _vstrcat_malloc(n, str0, argv);
|
|
||||||
va_end(argv);
|
|
||||||
return heap_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* _vstrcat_malloc(size_t n, cstr str0, va_list argv){
|
|
||||||
size_t str0_len = strlen(str0);
|
|
||||||
size_t total_len = str0_len;
|
|
||||||
cstr* const parts = malloc(sizeof(cstr) * n);
|
|
||||||
size_t* const part_lengths = malloc(sizeof(size_t) * n);
|
|
||||||
for(size_t i = 0; i < n; i++){
|
|
||||||
cstr part = va_arg(argv, cstr);
|
|
||||||
size_t length = strlen(part);
|
|
||||||
parts[i] = part;
|
|
||||||
part_lengths[i] = length;
|
|
||||||
total_len += length;
|
|
||||||
}
|
|
||||||
char* const buf = malloc(total_len + 1);
|
|
||||||
memcpy(buf, str0, str0_len);
|
|
||||||
char* walking_ptr = buf + str0_len;
|
|
||||||
for(size_t i = 0; i < n; i++){
|
|
||||||
memcpy(walking_ptr, parts[i], part_lengths[i]);
|
|
||||||
walking_ptr += part_lengths[i];
|
|
||||||
}
|
|
||||||
buf[total_len] = '\0';
|
|
||||||
free(parts);
|
|
||||||
free(part_lengths);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NULLABLE(sprintf_malloc)(size_t buffer_size, cstr format, ...){
|
|
||||||
va_list argv;
|
|
||||||
va_start(argv, format);
|
|
||||||
char* NULLABLE(heap_ptr) = vsprintf_malloc(buffer_size, format, argv);
|
|
||||||
va_end(argv);
|
|
||||||
return heap_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NULLABLE(vsprintf_malloc)(size_t buffer_size, cstr format, va_list argv){
|
|
||||||
char* buf = malloc(buffer_size);
|
|
||||||
int r = vsprintf(buf, format, argv);
|
|
||||||
if(r < 0){
|
|
||||||
free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
/// NOP
|
/// NOP
|
||||||
i32 NOP_impl(VM* vm){
|
i32 NOP_impl(VM* vm){
|
||||||
|
(void)vm;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../instructions.h"
|
#include "instructions/instructions.h"
|
||||||
#include "../registers.h"
|
#include "instructions/registers.h"
|
||||||
|
|
||||||
#define readVar(VAR) {\
|
#define readVar(VAR) {\
|
||||||
if(!VM_dataRead(vm, &VAR, vm->current_pos, sizeof(VAR))) \
|
if(!VM_dataRead(vm, &VAR, vm->current_pos, sizeof(VAR))) \
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include "instructions.h"
|
#include "instructions.h"
|
||||||
#include "../collections/HashMap.h"
|
#include "tlibc/collections/HashMap.h"
|
||||||
|
|
||||||
i32 NOP_impl(VM* vm);
|
i32 NOP_impl(VM* vm);
|
||||||
i32 EXIT_impl(VM* vm);
|
i32 EXIT_impl(VM* vm);
|
||||||
@@ -30,9 +30,9 @@ i32 JMP_impl(VM* vm);
|
|||||||
i32 JNZ_impl(VM* vm);
|
i32 JNZ_impl(VM* vm);
|
||||||
i32 JZ_impl(VM* vm);
|
i32 JZ_impl(VM* vm);
|
||||||
|
|
||||||
|
|
||||||
Array_declare(Instruction);
|
Array_declare(Instruction);
|
||||||
static const Array_Instruction instructions_array = ARRAY(Instruction, {
|
|
||||||
|
static const Array(Instruction) instructions_array = ARRAY(Instruction, {
|
||||||
Instruction_construct(NOP),
|
Instruction_construct(NOP),
|
||||||
Instruction_construct(EXIT),
|
Instruction_construct(EXIT),
|
||||||
Instruction_construct(SYS),
|
Instruction_construct(SYS),
|
||||||
@@ -64,35 +64,39 @@ static const Array_Instruction instructions_array = ARRAY(Instruction, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const Instruction* Instruction_getByOpcode(Opcode opcode){
|
const Instruction* Instruction_getByOpcode(Opcode opcode){
|
||||||
if(opcode >= instructions_array.len)
|
if((u32)opcode >= instructions_array.len)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return instructions_array.data + opcode;
|
return (Instruction*)instructions_array.data + opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
HashMap_declare(Instruction);
|
|
||||||
HashMap_define(Instruction, HashMap_DESTROY_VALUE_FUNC_NULL);
|
|
||||||
|
|
||||||
static HashMap_Instruction* instructions_map = NULL;
|
static HashMap(Opcode)* opcode_map = NULL;
|
||||||
|
|
||||||
|
static void _opcode_map_construct(){
|
||||||
|
opcode_map = malloc(sizeof(*opcode_map));
|
||||||
|
HashMap_construct(opcode_map, Opcode, NULL);
|
||||||
|
for(u32 i = 0; i < instructions_array.len; i++){
|
||||||
|
Instruction* instr_ptr = (Instruction*)instructions_array.data + i;
|
||||||
|
HashMap_tryPush(opcode_map, instr_ptr->name, &instr_ptr->opcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Instruction* Instruction_getByName(str name){
|
const Instruction* Instruction_getByName(str name){
|
||||||
if(instructions_map == NULL){
|
if(opcode_map == NULL)
|
||||||
instructions_map = malloc(sizeof(HashMap_Instruction));
|
_opcode_map_construct();
|
||||||
HashMap_Instruction_alloc(instructions_map);
|
|
||||||
for(u32 i = 0; i < instructions_array.len; i++){
|
|
||||||
HashMap_Instruction_tryPush(instructions_map, instructions_array.data[i].name, instructions_array.data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str name_upper = str_toUpper(name);
|
str name_upper = str_toUpper(name);
|
||||||
Instruction* iptr = HashMap_Instruction_tryGetPtr(instructions_map, name_upper);
|
Opcode* op_ptr = HashMap_tryGetPtr(opcode_map, name_upper);
|
||||||
free(name_upper.data);
|
str_destroy(name_upper);
|
||||||
return iptr;
|
if(op_ptr == NULL)
|
||||||
|
return NULL;
|
||||||
|
return Instruction_getByOpcode(*op_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instruction_freeSearchStructs(){
|
void Instruction_destroySearchStructs(){
|
||||||
if(instructions_map != NULL){
|
if(opcode_map != NULL){
|
||||||
HashMap_Instruction_free(instructions_map);
|
HashMap_destroy(opcode_map);
|
||||||
free(instructions_map);
|
free(opcode_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../VM/VM.h"
|
#include "VM/VM.h"
|
||||||
|
|
||||||
///@param program_pos position in vm->program next afrer opcode
|
///@param program_pos position in vm->program next afrer opcode
|
||||||
///@returns number of bytes read
|
///@returns number of bytes read
|
||||||
@@ -53,4 +53,4 @@ typedef struct Instruction {
|
|||||||
/// @return ptr to struct or NULL
|
/// @return ptr to struct or NULL
|
||||||
const Instruction* NULLABLE(Instruction_getByOpcode)(Opcode opcode);
|
const Instruction* NULLABLE(Instruction_getByOpcode)(Opcode opcode);
|
||||||
const Instruction* NULLABLE(Instruction_getByName)(str name);
|
const Instruction* NULLABLE(Instruction_getByName)(str name);
|
||||||
void Instruction_freeSearchStructs();
|
void Instruction_destroySearchStructs();
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ RegisterCode RegisterCode_parse(str r){
|
|||||||
else check_code(dl)
|
else check_code(dl)
|
||||||
else check_code(dh)
|
else check_code(dh)
|
||||||
|
|
||||||
free(lower.data);
|
str_destroy(lower);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "tlibc/std.h"
|
||||||
#include "../string/str.h"
|
#include "tlibc/string/str.h"
|
||||||
|
|
||||||
typedef enum RegisterCode {
|
typedef enum RegisterCode {
|
||||||
RegisterCode_Unset = 0,
|
RegisterCode_Unset = 0,
|
||||||
|
|||||||
50
src/main.c
50
src/main.c
@@ -1,11 +1,11 @@
|
|||||||
#include "VM/VM.h"
|
#include "VM/VM.h"
|
||||||
#include "instructions/instructions.h"
|
#include "instructions/instructions.h"
|
||||||
#include "collections/List.h"
|
|
||||||
#include "compiler/Compiler.h"
|
#include "compiler/Compiler.h"
|
||||||
#include "VM/Display/Display.h"
|
#include "VM/Display/Display.h"
|
||||||
#include <SDL3/SDL.h>
|
#include "tcpu_version.h"
|
||||||
|
#include "tlibc/time.h"
|
||||||
|
|
||||||
#define arg_is(STR) (strcmp(argv[argi], STR) == 0)
|
#define arg_is(LITERAL) str_equals(arg_str, STR(LITERAL))
|
||||||
|
|
||||||
i32 compileSources(cstr source_file, cstr out_file, bool debug_log);
|
i32 compileSources(cstr source_file, cstr out_file, bool debug_log);
|
||||||
i32 bootFromImage(cstr image_file);
|
i32 bootFromImage(cstr image_file);
|
||||||
@@ -24,15 +24,18 @@ i32 main(const i32 argc, cstr* argv){
|
|||||||
cstr NULLABLE(source_file) = NULL;
|
cstr NULLABLE(source_file) = NULL;
|
||||||
|
|
||||||
bool debug_log = false;
|
bool debug_log = false;
|
||||||
|
bool video_enabled = false;
|
||||||
|
|
||||||
for(i32 argi = 1; argi < argc; argi++){
|
for(i32 argi = 1; argi < argc; argi++){
|
||||||
|
str arg_str = str_from_cstr(argv[argi]);
|
||||||
if(arg_is("-h") || arg_is("--help")){
|
if(arg_is("-h") || arg_is("--help")){
|
||||||
printf(
|
printf(
|
||||||
"-h, --help Show this message.\n"
|
"-h, --help Show this message.\n"
|
||||||
"-op, --opcodes Show list of all instructions.\n"
|
|
||||||
"-i, --image [FILE] Boot VM using image file.\n"
|
|
||||||
"-c, --compile [SOURCE_FILE] [OUT_FILE] Compile assembly source files to machine code.\n"
|
|
||||||
"-d, --debug Enable debug log.\n"
|
"-d, --debug Enable debug log.\n"
|
||||||
|
"-op, --opcodes Show list of all instructions.\n"
|
||||||
|
"-c, --compile [SOURCE_FILE] [OUT_FILE] Compile assembly source files to machine code.\n"
|
||||||
|
"-i, --image [FILE] Boot VM using image file.\n"
|
||||||
|
"--video Enable VM display.\n"
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -80,6 +83,10 @@ i32 main(const i32 argc, cstr* argv){
|
|||||||
else if(arg_is("-d") || arg_is("--debug")){
|
else if(arg_is("-d") || arg_is("--debug")){
|
||||||
debug_log = true;
|
debug_log = true;
|
||||||
}
|
}
|
||||||
|
else if(arg_is("--video")){
|
||||||
|
video_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
printfe("ERROR: unknown argument '%s'\n", argv[argi]);
|
printfe("ERROR: unknown argument '%s'\n", argv[argi]);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -89,13 +96,25 @@ i32 main(const i32 argc, cstr* argv){
|
|||||||
i32 exit_code = 0;
|
i32 exit_code = 0;
|
||||||
if(compile){
|
if(compile){
|
||||||
exit_code = compileSources(source_file, out_file, debug_log);
|
exit_code = compileSources(source_file, out_file, debug_log);
|
||||||
|
if(exit_code != 0)
|
||||||
|
goto main_exit;
|
||||||
}
|
}
|
||||||
if(exit_code == 0 && boot){
|
|
||||||
|
if(boot){
|
||||||
|
printfe("TCPU version: " TCPU_VERSION_CSTR "\n");
|
||||||
|
if(video_enabled){
|
||||||
|
printfe("video enabled\n");
|
||||||
|
if(!Display_init(1600, 900, DisplayFlags_Default)){
|
||||||
|
printfe("DISPLAY ERROR: %s\n", Display_getError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
exit_code = bootFromImage(image_file);
|
exit_code = bootFromImage(image_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// frees global variables to supress valgrind memory leak errors
|
// frees global variables to supress valgrind memory leak errors
|
||||||
Instruction_freeSearchStructs();
|
main_exit:
|
||||||
|
Instruction_destroySearchStructs();
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,11 +138,14 @@ i32 bootFromImage(cstr image_file){
|
|||||||
}
|
}
|
||||||
|
|
||||||
VM vm;
|
VM vm;
|
||||||
VM_init(&vm);
|
VM_construct(&vm);
|
||||||
|
|
||||||
i32 exit_code = 1;
|
i32 exit_code = 1;
|
||||||
if(VM_setMemory(&vm, vm_memory, bytes_read)){
|
if(VM_setMemory(&vm, vm_memory, bytes_read)){
|
||||||
|
printf("===============================================================================\n");
|
||||||
exit_code = VM_boot(&vm);
|
exit_code = VM_boot(&vm);
|
||||||
|
printf("===============================================================================\n");
|
||||||
|
printfe("VM stopped with code %i\n", exit_code);
|
||||||
}
|
}
|
||||||
if(vm.state == VMState_InternalError){
|
if(vm.state == VMState_InternalError){
|
||||||
if(vm.error_message){
|
if(vm.error_message){
|
||||||
@@ -133,17 +155,13 @@ i32 bootFromImage(cstr image_file){
|
|||||||
else printfe("VM ERROR: unknown (error_message is null)\n");
|
else printfe("VM ERROR: unknown (error_message is null)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(exit_code != 0){
|
|
||||||
printfe("program exited with code %i\n", exit_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(vm_memory);
|
free(vm_memory);
|
||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
|
i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
|
||||||
Compiler cmp;
|
Compiler cmp;
|
||||||
Compiler_init(&cmp);
|
Compiler_construct(&cmp);
|
||||||
bool success = Compiler_compile(&cmp, source_file, out_file, debug_log);
|
bool success = Compiler_compile(&cmp, source_file, out_file, debug_log);
|
||||||
if(!success){
|
if(!success){
|
||||||
if(cmp.error_message){
|
if(cmp.error_message){
|
||||||
@@ -151,10 +169,10 @@ i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
|
|||||||
free(cmp.error_message);
|
free(cmp.error_message);
|
||||||
}
|
}
|
||||||
else printfe("COMPILER ERROR: unknown (error_message is null)\n");
|
else printfe("COMPILER ERROR: unknown (error_message is null)\n");
|
||||||
Compiler_free(&cmp);
|
Compiler_destroy(&cmp);
|
||||||
return 111;
|
return 111;
|
||||||
}
|
}
|
||||||
|
|
||||||
Compiler_free(&cmp);
|
Compiler_destroy(&cmp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
63
src/std.h
63
src/std.h
@@ -1,63 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
typedef int8_t i8;
|
|
||||||
typedef uint8_t u8;
|
|
||||||
typedef int16_t i16;
|
|
||||||
typedef uint16_t u16;
|
|
||||||
typedef int32_t i32;
|
|
||||||
typedef uint32_t u32;
|
|
||||||
typedef int64_t i64;
|
|
||||||
typedef uint64_t u64;
|
|
||||||
typedef float f32;
|
|
||||||
typedef double f64;
|
|
||||||
|
|
||||||
typedef const char* cstr;
|
|
||||||
|
|
||||||
#if defined(_WIN64) || defined(_WIN32)
|
|
||||||
#define IFWIN(YES, NO) YES
|
|
||||||
#else
|
|
||||||
#define IFWIN(YES, NO) NO
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
|
|
||||||
#define ALIGN_TO(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1))
|
|
||||||
|
|
||||||
#define __count_args( \
|
|
||||||
a0, a1, a2, a3, a4, a5, a6, a7 , a8, a9, a10,a11,a12,a13,a14,a15, \
|
|
||||||
a16,a17,a18,a19,a20,a21,a22,a23, a24,a25,a26,a27,a28,a29,a30,a31, \
|
|
||||||
a32,a33,a34,a35,a36,a37,a38,a39, a40,a41,a42,a43,a44,a45,a46,a47, \
|
|
||||||
a48,a49,a50,a51,a52,a53,a54,a55, a56,a57,a58,a59,a60,a61,a62,a63, \
|
|
||||||
a64,...) a64
|
|
||||||
// Macro for counting variadic arguments (max 64)
|
|
||||||
// (see usage in kprint.h)
|
|
||||||
#define count_args(ARGS...) __count_args(ARGS, \
|
|
||||||
64,63,62,61,60,59,58,57, 56,55,54,53,52,51,50,49, \
|
|
||||||
48,47,46,45,44,43,42,41, 40,39,38,37,36,35,34,33, \
|
|
||||||
32,31,30,29,28,27,26,25, 24,23,22,21,20,19,18,17, \
|
|
||||||
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
|
||||||
|
|
||||||
#define printfe(FORMAT, ...) fprintf(stderr, FORMAT ,##__VA_ARGS__)
|
|
||||||
|
|
||||||
/// @warning pointer can be null
|
|
||||||
#define NULLABLE(NAME) NAME
|
|
||||||
|
|
||||||
#define strcat_malloc(STR0, ...) _strcat_malloc(count_args(__VA_ARGS__), STR0, __VA_ARGS__)
|
|
||||||
char* _strcat_malloc(size_t n, cstr str0, ...);
|
|
||||||
char* _vstrcat_malloc(size_t n, cstr str0, va_list argv);
|
|
||||||
|
|
||||||
char* NULLABLE(sprintf_malloc)(size_t buffer_size, cstr format, ...) __attribute__((__format__(__printf__, 2, 3)));
|
|
||||||
char* NULLABLE(vsprintf_malloc)(size_t buffer_size, cstr format, va_list argv);
|
|
||||||
|
|
||||||
static inline bool isAlphabeticalLower(char c) { return 'a' <= c && c <= 'z'; }
|
|
||||||
static inline bool isAlphabeticalUpper(char c) { return 'A' <= c && c <= 'Z'; }
|
|
||||||
static inline bool isDigit(char c) { return '0' <= c && c <= '9'; }
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#include "StringBuilder.h"
|
|
||||||
|
|
||||||
void StringBuilder_free(StringBuilder* b){
|
|
||||||
free(b->buffer.data);
|
|
||||||
b->buffer = List_u8_construct(NULL, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
str StringBuilder_getStr(StringBuilder* b){
|
|
||||||
List_u8_push(&b->buffer, '\0');
|
|
||||||
str result = str_construct((char*)b->buffer.data, b->buffer.len - 1, true);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count){
|
|
||||||
if(count < b->buffer.len){
|
|
||||||
b->buffer.len -= count;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
b->buffer.len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void StringBuilder_append_char(StringBuilder* b, char c){
|
|
||||||
List_u8_push(&b->buffer, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void StringBuilder_append_string(StringBuilder* b, str s){
|
|
||||||
List_u8_pushMany(&b->buffer, (u8*)s.data, s.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringBuilder_append_cstr(StringBuilder* b, char* s){
|
|
||||||
StringBuilder_append_string(b, str_construct(s, strlen(s), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringBuilder_append_i64(StringBuilder* b, i64 n){
|
|
||||||
char buf[32];
|
|
||||||
sprintf(buf, IFWIN("%lli", "%li"), n);
|
|
||||||
StringBuilder_append_cstr(b, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringBuilder_append_u64(StringBuilder* b, u64 n){
|
|
||||||
char buf[32];
|
|
||||||
sprintf(buf, IFWIN("%llu", "%lu"), n);
|
|
||||||
StringBuilder_append_cstr(b, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringBuilder_append_f64(StringBuilder* b, f64 n){
|
|
||||||
char buf[32];
|
|
||||||
sprintf(buf, "%lf", n);
|
|
||||||
StringBuilder_append_cstr(b, buf);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../collections/List.h"
|
|
||||||
#include "str.h"
|
|
||||||
|
|
||||||
typedef struct StringBuilder {
|
|
||||||
List_u8 buffer;
|
|
||||||
} StringBuilder;
|
|
||||||
|
|
||||||
static inline StringBuilder StringBuilder_alloc(u32 initial_size) {
|
|
||||||
return (StringBuilder){ .buffer = List_u8_alloc(initial_size) };
|
|
||||||
}
|
|
||||||
void StringBuilder_free(StringBuilder* b);
|
|
||||||
|
|
||||||
/// @param count set to -1 to clear StringBuilder
|
|
||||||
void StringBuilder_removeFromEnd(StringBuilder* b, u32 count);
|
|
||||||
void StringBuilder_append_char(StringBuilder* b, char c);
|
|
||||||
void StringBuilder_append_cstr(StringBuilder* b, char* s);
|
|
||||||
void StringBuilder_append_string(StringBuilder* b, str s);
|
|
||||||
void StringBuilder_append_i64(StringBuilder* b, i64 a);
|
|
||||||
void StringBuilder_append_u64(StringBuilder* b, u64 a);
|
|
||||||
void StringBuilder_append_f64(StringBuilder* b, f64 a);
|
|
||||||
|
|
||||||
// adds '\0' to the buffer and returns pointer to buffer content
|
|
||||||
str StringBuilder_getStr(StringBuilder* b);
|
|
||||||
125
src/string/str.c
125
src/string/str.c
@@ -1,125 +0,0 @@
|
|||||||
#include "str.h"
|
|
||||||
|
|
||||||
str str_copy(str src){
|
|
||||||
if(src.data == NULL || src.len == 0)
|
|
||||||
return src;
|
|
||||||
|
|
||||||
str nstr = str_construct((char*)malloc(src.len + 1), src.len, true);
|
|
||||||
memcpy(nstr.data, src.data, src.len);
|
|
||||||
nstr.data[nstr.len] = '\0';
|
|
||||||
return nstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool str_equals(str s0, str s1){
|
|
||||||
if(s0.len != s1.len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for(u32 i = 0; i < s0.len; i++)
|
|
||||||
if(s0.data[i] != s1.data[i])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
str str_reverse(str s){
|
|
||||||
if(s.data == NULL || s.len == 0)
|
|
||||||
return s;
|
|
||||||
|
|
||||||
str r = str_construct(malloc(s.len), s.len, s.isZeroTerminated);
|
|
||||||
for(u32 i = 0; i < s.len; i++ )
|
|
||||||
r.data[i] = s.data[s.len - i - 1];
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 str_seek(str src, str fragment, u32 startIndex){
|
|
||||||
if(src.len == 0 || fragment.len == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for(u32 i = startIndex; i < src.len - fragment.len + 1; i++){
|
|
||||||
for(u32 j = 0;; j++){
|
|
||||||
if(j == fragment.len)
|
|
||||||
return i;
|
|
||||||
if(src.data[i + j] != fragment.data[j])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 str_seekReverse(str src, str fragment, u32 startIndex){
|
|
||||||
if(src.len == 0 || fragment.len == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(startIndex > src.len - 1)
|
|
||||||
startIndex = src.len - 1;
|
|
||||||
for(u32 i = startIndex; i >= fragment.len - 1; i--){
|
|
||||||
for(u32 j = 0;; j++){
|
|
||||||
if(j == fragment.len)
|
|
||||||
return i - j + 1;
|
|
||||||
if(src.data[i - j] != fragment.data[fragment.len - 1 - j])
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 str_seekChar(str src, char c, u32 startIndex){
|
|
||||||
for(u32 i = startIndex; i < src.len; i++){
|
|
||||||
if(src.data[i] == c)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 str_seekCharReverse(str src, char c, u32 startIndex){
|
|
||||||
if(startIndex > src.len - 1)
|
|
||||||
startIndex = src.len - 1;
|
|
||||||
for(u32 i = startIndex; i != (u32)-1; i--){
|
|
||||||
if(src.data[i] == c)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool str_startsWith(str src, str fragment){
|
|
||||||
if(src.len < fragment.len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
src.len = fragment.len;
|
|
||||||
return str_equals(src, fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool str_endsWith(str src, str fragment){
|
|
||||||
if(src.len < fragment.len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
src.data = (char*)(src.data + src.len - fragment.len);
|
|
||||||
src.len = fragment.len;
|
|
||||||
return str_equals(src, fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 str_hash32(str s){
|
|
||||||
u8* ubuf = (u8*)s.data;
|
|
||||||
u32 hash=0;
|
|
||||||
for (u32 i = 0; i < s.len; i++)
|
|
||||||
hash = (hash<<6) + (hash<<16) - hash + ubuf[i];
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
str str_toUpper(str src){
|
|
||||||
str r = str_copy(src);
|
|
||||||
for (u32 i = 0; i < r.len; i++){
|
|
||||||
if(isAlphabeticalLower(r.data[i]))
|
|
||||||
r.data[i] = r.data[i] - 'a' + 'A';
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
str str_toLower(str src){
|
|
||||||
str r = str_copy(src);
|
|
||||||
for (u32 i = 0; i < r.len; i++){
|
|
||||||
if(isAlphabeticalUpper(r.data[i]))
|
|
||||||
r.data[i] = r.data[i] - 'A' + 'a';
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../std.h"
|
|
||||||
|
|
||||||
typedef struct str {
|
|
||||||
char* data;
|
|
||||||
u32 len;
|
|
||||||
bool isZeroTerminated;
|
|
||||||
} str;
|
|
||||||
|
|
||||||
/// creates str from a string literal
|
|
||||||
#define STR(LITERAL) str_construct(LITERAL, ARRAY_SIZE(LITERAL) - 1, true)
|
|
||||||
|
|
||||||
#define str_construct(DATA, LEN, ZERO_TERMINATED) ((str){ .data = DATA, .len = LEN, .isZeroTerminated = ZERO_TERMINATED })
|
|
||||||
|
|
||||||
static const str str_null = str_construct(NULL, 0, 0);
|
|
||||||
|
|
||||||
/// copies src content to new string and adds \0 at the end
|
|
||||||
str str_copy(str src);
|
|
||||||
|
|
||||||
/// compares two strings, NullPtr-friendly
|
|
||||||
bool str_equals(str str0, str str1);
|
|
||||||
|
|
||||||
/// allocates new string which is reversed variant of <s>
|
|
||||||
str str_reverse(str s);
|
|
||||||
|
|
||||||
i32 str_seek(str src, str fragment, u32 startIndex);
|
|
||||||
i32 str_seekReverse(str src, str fragment, u32 startIndex);
|
|
||||||
|
|
||||||
i32 str_seekChar(str src, char c, u32 startIndex);
|
|
||||||
i32 str_seekCharReverse(str src, char c, u32 startIndex);
|
|
||||||
|
|
||||||
bool str_startsWith(str src, str fragment);
|
|
||||||
bool str_endsWith(str src, str fragment);
|
|
||||||
|
|
||||||
/// @brief calculates string hash using sdbm32 algorythm (something like lightweight crc32)
|
|
||||||
/// @return non-cryptografic hash of the string
|
|
||||||
u32 str_hash32(str s);
|
|
||||||
|
|
||||||
str str_toUpper(str src);
|
|
||||||
str str_toLower(str src);
|
|
||||||
3
src/tcpu_version.h
Normal file
3
src/tcpu_version.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TCPU_VERSION_CSTR "1.0.0"
|
||||||
Reference in New Issue
Block a user