Compare commits

...

5 Commits

Author SHA1 Message Date
Timerix
cf724a8d13 updated tlibc 2025-11-26 20:56:58 +05:00
5397965319 added video enable option 2025-08-29 14:37:58 +05:00
7876210be6 updated tlibc 2025-08-10 19:06:22 +03:00
17baabbd95 properly named constructors and destructors 2025-07-24 18:26:51 +03:00
72f8e196a7 moved collections and string code to tlibc submodule 2025-07-24 17:49:50 +03:00
44 changed files with 450 additions and 1001 deletions

3
.gitmodules vendored Normal file
View 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
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "all",
"defines": [],
"includePath": [
"dependencies/tlibc/include",
"src",
"${default}"
],
"cStandard": "c11"
}
],
"version": 4
}

10
.vscode/launch.json vendored
View File

@@ -2,16 +2,20 @@
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Debug",
"name": "gdb_debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/bin/tcpu",
"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",
"preLaunchTask": "build_exec_dbg",
"stopAtEntry": false,
"externalConsole": false,
"internalConsoleOptions": "neverOpen",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
@@ -26,4 +30,4 @@
]
}
]
}
}

View File

@@ -2,8 +2,12 @@
Machine code interpreter written in pure C. Can execute programs up to 1 MEGABYTE (1048576 bytes) in size!!!
## Building
1. Install [cbuild](https://timerix.ddns.net:3322/Timerix/cbuild.git)
2. Install [SDL3](https://github.com/libsdl-org/SDL) and [SDL3_image](https://github.com/libsdl-org/SDL_image) from package manager or source.
1. Clone repo
```
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
cbuild build_exec_dbg
```

1
dependencies/tlibc vendored Submodule

Submodule dependencies/tlibc added at 6a7f0a8715

19
dependencies/tlibc.config vendored Normal file
View 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

View File

@@ -3,5 +3,5 @@ Example of graphical application
*/
.main:
//TODO: write code here
//TODO: add a way to access Event struct's fields
exit

View File

@@ -1,22 +1,30 @@
#!/usr/bin/env bash
CBUILD_VERSION=2.1.4
CONFIG_VERSION=1
CBUILD_VERSION=2.3.2
PROJECT="tcpu"
CMP_C="gcc"
CMP_CPP="g++"
STD_C="c11"
STD_C="c99"
STD_CPP="c++11"
WARN_C="-Wall -Wextra -Wno-unused-parameter"
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
WARN_C="-Wall -Wextra
-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_CPP="$(find src -name '*.cpp')"
# Directory with 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.
ENABLED_DEPENDENCIES=''
ENABLED_DEPENDENCIES='tlibc'
# OBJDIR structure:
# ├── objects/ - Compiled object files. Cleans on each call of build task
@@ -25,7 +33,9 @@ ENABLED_DEPENDENCIES=''
# └── profile/ - gcc *.gcda profiling info files
OBJDIR="obj"
OUTDIR="bin"
STATIC_LIB_FILE="lib$PROJECT.a"
STATIC_LIB_FILE="$PROJECT.a"
INCLUDE="-Isrc -I$DEPENDENCIES_DIR/tlibc/include"
# OS-specific options
case "$OS" in
@@ -33,13 +43,11 @@ case "$OS" in
EXEC_FILE="$PROJECT.exe"
SHARED_LIB_FILE="$PROJECT.dll"
LINKER_LIBS="-lSDL3_image -lSDL3"
INCLUDE=""
;;
LINUX)
EXEC_FILE="$PROJECT"
SHARED_LIB_FILE="$PROJECT.so"
LINKER_LIBS="-lSDL3_image -lSDL3"
INCLUDE=""
;;
*)
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"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT="@cbuild/default_tasks/strip_exec.sh"
;;
# creates executable with debug info and no optimizations
build_exec_dbg)
C_ARGS="-O0 -g3"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
POST_TASK_SCRIPT=""
;;
# creates shared library
build_shared_lib)
C_ARGS="-O2 -fpic -flto -shared"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates shared library with debug symbols and no optimizations
build_shared_lib_dbg)
C_ARGS="-O0 -g3 -fpic -shared"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS -Wl,-soname,$SHARED_LIB_FILE"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_shared_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates static library
build_static_lib)
C_ARGS="-O2 -fpic -fdata-sections -ffunction-sections"
CPP_ARGS="$C_ARGS"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
POST_TASK_SCRIPT=""
;;
# creates static library with debug symbols and no optimizations
build_static_lib_dbg)
C_ARGS="-O0 -g3"
CPP_ARGS="$C_ARGS"
PRE_TASK_SCRIPT=
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT=""
TASK_SCRIPT="@cbuild/default_tasks/build_static_lib.sh"
POST_TASK_SCRIPT=""
;;
# executes $EXEC_FILE
exec)
TASK_SCRIPT=cbuild/default_tasks/exec.sh
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
;;
# executes $EXEC_FILE with valgrind memory checker
valgrind)
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
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"
;;
# generates profiling info
profile)
@@ -127,22 +135,25 @@ case "$TASK" in
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
TASK_SCRIPT=cbuild/default_tasks/profile.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/profile.sh"
POST_TASK_SCRIPT=""
;;
# compiles program with -pg and runs it with gprof
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
# requires graphviz (https://www.graphviz.org/download/source/)
gprof)
OUTDIR="$OUTDIR/gprof"
# -pg adds code to executable, that generates file containing function call info (gmon.out)
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -pg"
# arguments that emit some call counter code and disable optimizations to see function names
# 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"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
TASK_SCRIPT=cbuild/default_tasks/gprof.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/gprof.sh"
POST_TASK_SCRIPT=""
;;
# compiles program and runs it with callgrind (part of valgrind)
# 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"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
TASK_SCRIPT=cbuild/default_tasks/callgrind.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/callgrind.sh"
POST_TASK_SCRIPT=""
;;
# compiles executable with sanitizers and executes it to find errors and warnings
sanitize)
@@ -164,19 +175,19 @@ case "$TASK" in
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
CPP_ARGS="$C_ARGS"
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
PRE_TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
TASK_SCRIPT=cbuild/default_tasks/exec.sh
POST_TASK_SCRIPT=
PRE_TASK_SCRIPT="@cbuild/default_tasks/build_exec.sh"
TASK_SCRIPT="@cbuild/default_tasks/exec.sh"
POST_TASK_SCRIPT=""
;;
# rebuilds specified dependencies
# EXAMPLE: `cbuild rebuild_dependencies=libexample1,fonts`
# 'all' can be specified to rebuild all dependencies
rebuild_dependencies)
TASK_SCRIPT=cbuild/default_tasks/rebuild_dependencies.sh
TASK_SCRIPT="@cbuild/default_tasks/rebuild_dependencies.sh"
;;
# deletes generated files
clean)
TASK_SCRIPT=cbuild/default_tasks/clean.sh
TASK_SCRIPT="@cbuild/default_tasks/clean.sh"
;;
# nothing to do
"" | no_task)

View 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"

View File

@@ -1,71 +1,72 @@
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include "Display.h"
#include "tcpu_version.h"
typedef struct Display {
str name;
i32 width;
i32 height;
SDL_Window* window;
SDL_Renderer* renderer;
} 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;
Display* Display_create(str name, i32 w, i32 h, DisplayFlags flags){
Display* d = malloc(sizeof(Display));
d->name = str_copy(name);
d->width = w;
d->height = h;
d->window = NULL;
d->renderer = NULL;
if (SDL_ShouldInit(&sdl_init_state)) {
bool Display_init(i32 w, i32 h, DisplayFlags flags){
(void)flags;
_d.width = w;
_d.height = h;
_d.window = NULL;
_d.renderer = NULL;
if (SDL_ShouldInit(&_sdl_init_state)) {
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)
return false;
}
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 d;
return true;
}
void Display_destroy(Display* d){
free(d->name.data);
SDL_DestroyRenderer(d->renderer);
SDL_DestroyWindow(d->window);
free(d);
void Display_destroy(){
SDL_DestroyRenderer(_d.renderer);
SDL_DestroyWindow(_d.window);
// if (SDL_ShouldQuit(&sdl_init_state)) {
// if (SDL_ShouldQuit(&_sdl_init_state)) {
// SDL_Quit();
// SDL_SetInitialized(&sdl_init_state, false);
// SDL_SetInitialized(&_sdl_init_state, false);
// }
}
bool Display_setName(Display* d, str name){
d->name = str_copy(name);
return SDL_SetWindowTitle(d->window, name.data);
NULLABLE(cstr) Display_getError(){
return SDL_GetError();
}
bool Display_setSize(Display* d, u32 w, u32 h){
d->width = w;
d->height = h;
return SDL_SetWindowSize(d->window, w, h);
bool Display_setSize(u32 w, u32 h){
_d.width = w;
_d.height = h;
return SDL_SetWindowSize(_d.window, w, h);
}
bool Display_setDrawingColor(Display* d, ColorRGBA color){
return SDL_SetRenderDrawColor(d->renderer, color.r, color.g, color.b, color.a);
bool Display_setFullScreenMode(bool value){
return SDL_SetWindowFullscreen(_d.window, value);
}
bool Display_clear(Display* d){
return SDL_RenderClear(d->renderer);
bool Display_setDrawingColor(ColorRGBA color){
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) {\
@@ -75,16 +76,12 @@ bool Display_clear(Display* d){
DST.h = SRC.h;\
}
bool Display_fillRect(Display* d, Rect rect) {
bool Display_fillRect(Rect rect) {
SDL_FRect sdl_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){
return SDL_RenderPresent(d->renderer);
}
NULLABLE(cstr) Display_getError(){
return SDL_GetError();
bool Display_swapBuffers(){
return SDL_RenderPresent(_d.renderer);
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../../std.h"
#include "../../string/str.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
typedef struct Rect {
i32 x, y;
@@ -18,15 +18,13 @@ typedef enum DisplayFlags {
DisplayFlags_Default = 0
} DisplayFlags;
typedef struct Display Display;
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);
bool Display_init(i32 w, i32 h, DisplayFlags flags);
void Display_destroy();
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();

View File

@@ -1,7 +1,7 @@
#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));
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);
char* real_format = strcat_malloc(position_str, context, "] ", 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);
free(real_format);
if(buf == NULL){

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../instructions/registers.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
#include "instructions/registers.h"
typedef union Register {
u64 rx;
@@ -43,7 +43,7 @@ typedef struct VM {
size_t current_pos;
} VM;
void VM_init(VM* vm);
void VM_construct(VM* vm);
/// @brief Loads a program from the buffer.
/// @param data buffer starting with machine code

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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;\
}

View File

@@ -1,4 +0,0 @@
#include "List.h"
List_define(u32);
List_define(u8);

View File

@@ -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);

View File

@@ -1,52 +1,51 @@
#include "AST.h"
List_define(Argument);
List_define(Operation);
List_define(DataDefinition);
List_define(Section);
Array_declare(str);
static str _ArgumentType_str[] = {
static Array(str) _ArgumentType_str_array = ARRAY(str, {
STR("Unset"),
STR("Register"),
STR("ConstValue"),
STR("VarDataName"),
STR("ConstDataPointer"),
STR("ConstDataSize"),
};
});
str ArgumentType_toString(ArgumentType t){
if(t >= ARRAY_SIZE(_ArgumentType_str))
if(t >= _ArgumentType_str_array.len)
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->data = List_DataDefinition_alloc(256);
sec->code = List_Operation_alloc(1024);
sec->data_definitions_list = List_DataDefinition_alloc(256);
sec->operations_list = List_Operation_alloc(1024);
}
void Section_free(Section* sec){
for(u32 i = 0; i < sec->data.len; i++){
free(sec->data.data[i].data.data);
void Section_destroy(Section* sec){
for(u32 i = 0; i < sec->data_definitions_list.len; i++){
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++){
free(sec->code.data[i].args.data);
for(u32 i = 0; i < sec->operations_list.len; i++){
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);
}
void AST_free(AST* ast){
void AST_destroy(AST* ast){
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);
}

View File

@@ -1,9 +1,10 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../instructions/instructions.h"
#include "../instructions/registers.h"
#include "../collections/List.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
#include "instructions/instructions.h"
#include "instructions/registers.h"
#include "tlibc/collections/List.h"
#include "tlibc/collections/List_impl/List_u8.h"
typedef enum ArgumentType {
ArgumentType_Unset,
@@ -30,7 +31,7 @@ List_declare(Argument);
typedef struct Operation {
List_Argument args;
List(Argument) args;
Opcode opcode;
} Operation;
@@ -39,7 +40,7 @@ List_declare(Operation);
typedef struct DataDefinition {
str name;
List_u8 data;
List(u8) data_bytes;
u32 element_size;
} DataDefinition;
@@ -48,18 +49,18 @@ List_declare(DataDefinition);
typedef struct Section {
str name;
List_DataDefinition data;
List_Operation code;
List(DataDefinition) data_definitions_list;
List(Operation) operations_list;
} Section;
List_declare(Section);
void Section_init(Section* Section, str name);
void Section_free(Section* Section);
void Section_construct(Section* Section, str name);
void Section_destroy(Section* Section);
typedef struct AST {
List_Section sections;
List(Section) sections;
} AST;
void AST_init(AST* ast);
void AST_free(AST* ast);
void AST_construct(AST* ast);
void AST_destroy(AST* ast);

View File

@@ -1,42 +1,36 @@
#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){
ptr->name = name;
ptr->next = NULL;
ptr->offset = 0;
ptr->const_data_props_list = List_ConstDataProps_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){
free(ptr->const_data_props_list.data);
free(ptr->named_refs.data);
free(ptr->bytes.data);
void CompiledSection_destroy(CompiledSection* ptr){
List_ConstDataProps_destroy(&ptr->const_data_props_list);
List_NamedRef_destroy(&ptr->named_refs);
List_u8_destroy(&ptr->bytes);
}
void BinaryObject_construct(BinaryObject* ptr){
ptr->section_list = List_CompiledSection_alloc(64);
HashMap_CompiledSectionPtr_alloc(&ptr->section_map);
HashMap_ConstDataProps_alloc(&ptr->const_data_map);
ptr->main_section = NULL;
ptr->comp_sec_list = List_CompiledSection_alloc(64);
HashMap_construct(&ptr->comp_sec_i_map, u32, NULL);
HashMap_construct(&ptr->const_data_props_map, ConstDataProps, NULL);
ptr->main_sec = NULL;
ptr->total_size = 0;
}
void BinaryObject_free(BinaryObject* ptr){
for(u32 i = 0; i < ptr->section_list.len; i++){
CompiledSection_free(&ptr->section_list.data[i]);
void BinaryObject_destroy(BinaryObject* ptr){
for(u32 i = 0; i < ptr->comp_sec_list.len; 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_ConstDataProps_free(&ptr->const_data_map);
HashMap_destroy(&ptr->comp_sec_i_map);
HashMap_destroy(&ptr->const_data_props_map);
}

View File

@@ -1,10 +1,11 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../instructions/instructions.h"
#include "../instructions/registers.h"
#include "../collections/List.h"
#include "../collections/HashMap.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
#include "instructions/instructions.h"
#include "instructions/registers.h"
#include "tlibc/collections/List.h"
#include "tlibc/collections/List_impl/List_u8.h"
#include "tlibc/collections/HashMap.h"
#include "AST.h"
typedef struct CompiledSection CompiledSection;
@@ -14,10 +15,9 @@ typedef struct ConstDataProps {
u32 offset; // offset in bytes from section start
} ConstDataProps;
#define ConstDataProps_construct(NAME, SIZE, OFFSET) ((ConstDataProps){ .name = NAME, .size = SIZE, .offset = OFFSET})
List_declare(ConstDataProps)
List_declare(ConstDataProps);
HashMap_declare(ConstDataProps);
#define ConstDataProps_construct(NAME, SIZE, OFFSET) ((ConstDataProps){ .name = NAME, .size = SIZE, .offset = OFFSET})
typedef enum NamedRefType {
@@ -32,35 +32,33 @@ typedef struct NamedRef {
u32 offset; // offset in bytes from section start
} NamedRef;
#define NamedRef_construct(NAME, TYPE, OFFSET) ((NamedRef){ .name = NAME, .type = TYPE, .offset = OFFSET})
List_declare(NamedRef);
#define NamedRef_construct(NAME, TYPE, OFFSET) ((NamedRef){ .name = NAME, .type = TYPE, .offset = OFFSET})
typedef struct CompiledSection {
str name;
CompiledSection* next;
u32 offset;
List_ConstDataProps const_data_props_list;
List_NamedRef named_refs;
List_u8 bytes;
List(ConstDataProps) const_data_props_list;
List(NamedRef) named_refs;
List(u8) bytes;
} CompiledSection;
void CompiledSection_construct(CompiledSection* ptr, str name);
void CompiledSection_free(CompiledSection* ptr);
List_declare(CompiledSection)
List_declare(CompiledSection);
typedef CompiledSection* CompiledSectionPtr;
HashMap_declare(CompiledSectionPtr);
void CompiledSection_construct(CompiledSection* ptr, str name);
void CompiledSection_destroy(CompiledSection* ptr);
typedef struct BinaryObject {
List_CompiledSection section_list;
HashMap_CompiledSectionPtr section_map;
NULLABLE(CompiledSection*) main_section;
HashMap_ConstDataProps const_data_map;
List(CompiledSection) comp_sec_list;
HashMap(u32) comp_sec_i_map;
NULLABLE(CompiledSection*) main_sec;
HashMap(ConstDataProps) const_data_props_map;
u32 total_size;
} BinaryObject;
void BinaryObject_construct(BinaryObject* ptr);
void BinaryObject_free(BinaryObject* ptr);
void BinaryObject_destroy(BinaryObject* ptr);

View File

@@ -1,22 +1,20 @@
#include "Compiler_internal.h"
HashMap_define(SectionPtr, HashMap_DESTROY_VALUE_FUNC_NULL);
void Compiler_init(Compiler* cmp){
void Compiler_construct(Compiler* cmp){
memset(cmp, 0, sizeof(Compiler));
cmp->state = CompilerState_Initial;
cmp->tokens = List_Token_alloc(4096);
cmp->line_lengths = List_u32_alloc(1024);
AST_init(&cmp->ast);
AST_construct(&cmp->ast);
BinaryObject_construct(&cmp->binary);
}
void Compiler_free(Compiler* cmp){
free(cmp->code.data);
free(cmp->tokens.data);
free(cmp->line_lengths.data);
AST_free(&cmp->ast);
BinaryObject_free(&cmp->binary);
void Compiler_destroy(Compiler* cmp){
str_destroy(cmp->code);
List_Token_destroy(&cmp->tokens);
List_u32_destroy(&cmp->line_lengths);
AST_destroy(&cmp->ast);
BinaryObject_destroy(&cmp->binary);
}
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);
va_list argv;
va_start(argv, format);
char* NULLABLE(buf) = vsprintf_malloc(512, real_format, argv);
char* NULLABLE(buf) = vsprintf_malloc(real_format, argv);
va_end(argv);
free(real_format);
if(buf == NULL){
@@ -64,20 +62,24 @@ str Compiler_constructTokenStr(Compiler* cmp, Token t){
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){
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);
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);
}
// compile code
u8 zeroes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
for(u32 i = 0; i < sec->code.len; i++){
Operation* op = &sec->code.data[i];
List_u8_pushMany(&cs->bytes, (void*)&op->opcode, sizeof(op->opcode));
u8 zeroes_8[8];
memset(zeroes_8, 0, sizeof(zeroes_8));
for(u32 i = 0; i < sec->operations_list.len; i++){
Operation* op = sec->operations_list.data + i;
List_u8_pushStruct(&cs->bytes, &op->opcode);
for(u32 j = 0; j < op->args.len; j++){
Argument* arg = &op->args.data[j];
Argument* arg = op->args.data + j;
switch(arg->type){
case ArgumentType_VarDataName:
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);
break;
case ArgumentType_ConstValue:
List_u8_pushMany(&cs->bytes, (void*)&arg->value.i, 8);
List_u8_pushStruct(&cs->bytes, &arg->value.i);
break;
case ArgumentType_ConstDataPointer:
List_NamedRef_push(&cs->named_refs, NamedRef_construct(
List_NamedRef_push(&cs->named_refs,
NamedRef_construct(
arg->value.data_name,
NamedRefType_Ptr,
cs->bytes.len));
List_u8_pushMany(&cs->bytes, zeroes, 8);
cs->bytes.len
)
);
List_u8_pushStruct(&cs->bytes, zeroes_8);
break;
case ArgumentType_ConstDataSize:
List_NamedRef_push(&cs->named_refs, NamedRef_construct(
List_NamedRef_push(&cs->named_refs,
NamedRef_construct(
arg->value.data_name,
NamedRefType_Size,
cs->bytes.len));
List_u8_pushMany(&cs->bytes, zeroes, 8);
cs->bytes.len
)
);
List_u8_pushStruct(&cs->bytes, zeroes_8);
break;
}
}
}
// compile data
for(u32 i = 0; i < sec->data.len; i++){
DataDefinition* dd = &sec->data.data[i];
List_ConstDataProps_push(&cs->const_data_props_list, ConstDataProps_construct(dd->name, dd->data.len, cs->bytes.len));
List_u8_pushMany(&cs->bytes, dd->data.data, dd->data.len);
for(u32 i = 0; i < sec->data_definitions_list.len; i++){
DataDefinition* dd = sec->data_definitions_list.data + i;
ConstDataProps cd_props = ConstDataProps_construct(dd->name, dd->data_bytes.len, cs->bytes.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
@@ -127,7 +136,7 @@ static bool compileBinary(Compiler* cmp){
cmp->state = CompilerState_Compiling;
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)){
return false;
}
@@ -135,17 +144,18 @@ static bool compileBinary(Compiler* cmp){
// find main section
str main_sec_name = STR("main");
CompiledSection** main_sec_ptrptr = HashMap_CompiledSectionPtr_tryGetPtr(&cmp->binary.section_map, main_sec_name);
if(main_sec_ptrptr == NULL){
u32* main_sec_i_ptr = HashMap_tryGetPtr(&cmp->binary.comp_sec_i_map, main_sec_name);
if(main_sec_i_ptr == NULL){
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
CompiledSection* prev_sec = *main_sec_ptrptr;
CompiledSection* prev_sec = cmp->binary.main_sec;
u32 total_size = 0;
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
CompiledSection* sec = &cmp->binary.section_list.data[i];
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
total_size += sec->bytes.len;
bool is_main_sec = str_equals(sec->name, main_sec_name);
if(!is_main_sec){
@@ -153,13 +163,13 @@ static bool compileBinary(Compiler* cmp){
}
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);
}
for(u32 j = 0; j < sec->const_data_props_list.len; j++){
cd = sec->const_data_props_list.data[j];
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);
}
}
@@ -171,18 +181,18 @@ static bool compileBinary(Compiler* cmp){
}
// insert calculated offsets into sections
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
CompiledSection* sec = &cmp->binary.section_list.data[i];
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
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(
&cmp->binary.const_data_map, ref->name);
ConstDataProps* target_data = HashMap_tryGetPtr(
&cmp->binary.const_data_props_map, ref->name);
if(target_data == NULL){
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){
default:
returnError("invalid NamedRefType %i", ref->type);
@@ -203,7 +213,7 @@ static bool compileBinary(Compiler* cmp){
static bool writeBinaryFile(Compiler* cmp, FILE* f){
returnErrorIf_auto(cmp->state != CompilerState_Compiling);
CompiledSection* sec = cmp->binary.main_section;
CompiledSection* sec = cmp->binary.main_sec;
while(sec){
fwrite(sec->bytes.data, 1, sec->bytes.len, 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);
}
if(ferror(f)){
StringBuilder_free(&sb);
StringBuilder_destroy(&sb);
fclose(f);
returnError("can't read file '%s'", source_file_name);
}
fclose(f);
if(sb.buffer.len == 0){
StringBuilder_free(&sb);
StringBuilder_destroy(&sb);
returnError("soucre file is empty");
}
cmp->code = str_copy(StringBuilder_getStr(&sb));
StringBuilder_free(&sb);
StringBuilder_destroy(&sb);
f = fopen(out_file_name, "wb");
if(f == NULL){
@@ -290,21 +300,20 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
if (debug_log){
printf("-------------------------------------[AST]-------------------------------------\n");
for(u32 i = 0; i < cmp->ast.sections.len; i++){
Section* sec = &cmp->ast.sections.data[i];
str tmpstr = str_copy(sec->name);
printf("section '%s'\n", tmpstr.data);
free(tmpstr.data);
Section* sec = cmp->ast.sections.data + i;
printf("section '"FMT_str"'\n", sec->name.len, sec->name.data);
for(u32 j = 0; j < sec->data.len; j++){
DataDefinition* dd = &sec->data.data[j];
tmpstr = str_copy(dd->name);
printf(" const%u %s (len %u)\n", dd->element_size * 8, tmpstr.data, dd->data.len/dd->element_size);
free(tmpstr.data);
for(u32 j = 0; j < sec->data_definitions_list.len; j++){
DataDefinition* dd = sec->data_definitions_list.data + j;
printf(" const%u "FMT_str" (len %u)\n",
dd->element_size * 8,
dd->name.len, dd->name.data,
dd->data_bytes.len/dd->element_size);
}
for(u32 j = 0; j < sec->code.len; j++){
Operation* op = &sec->code.data[j];
for(u32 j = 0; j < sec->operations_list.len; j++){
Operation* op = sec->operations_list.data + j;
const Instruction* instr = Instruction_getByOpcode(op->opcode);
if(instr == NULL){
fclose(f);
@@ -313,35 +322,29 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
printf(" %s", instr->name.data);
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);
switch(arg->type){
default:
fclose(f);
returnError("invalid argument type %i", arg->type);
case ArgumentType_Register:
case ArgumentType_Register:;
str register_name = RegisterCode_toString(arg->value.register_code);
printf("%s 0x%x", register_name.data, arg->value.register_code);
free(register_name.data);
str_destroy(register_name);
break;
case ArgumentType_ConstValue:
printf(IFWIN("%lli", "%li"), arg->value.i);
break;
case ArgumentType_ConstDataPointer:
tmpstr = str_copy(arg->value.data_name);
printf("@%s", tmpstr.data);
free(tmpstr.data);
printf("@"FMT_str, arg->value.data_name.len, arg->value.data_name.data);
break;
case ArgumentType_ConstDataSize:
tmpstr = str_copy(arg->value.data_name);
printf("#%s", tmpstr.data);
free(tmpstr.data);
printf("#"FMT_str, arg->value.data_name.len, arg->value.data_name.data);
break;
case ArgumentType_VarDataName:
tmpstr = str_copy(arg->value.data_name);
printf("%s", tmpstr.data);
free(tmpstr.data);
printf(FMT_str, arg->value.data_name.len, arg->value.data_name.data);
break;
}
@@ -363,11 +366,10 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
success = compileBinary(cmp);
if(debug_log){
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
CompiledSection* sec = &cmp->binary.section_list.data[i];
str tmpstr = str_copy(sec->name);
printf("compiled section '%s' to %u bytes with offset 0x%x\n", tmpstr.data, sec->bytes.len, sec->offset);
free(tmpstr.data);
for(u32 i = 0; i < cmp->binary.comp_sec_list.len; i++){
CompiledSection* sec = cmp->binary.comp_sec_list.data + i;
printf("compiled section '"FMT_str"' to %u bytes with offset 0x%x\n",
sec->name.len, sec->name.data, sec->bytes.len, sec->offset);
}
}

View File

@@ -1,8 +1,9 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../collections/List.h"
#include "../collections/HashMap.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
#include "tlibc/collections/List.h"
#include "tlibc/collections/List_impl/List_u32.h"
#include "tlibc/collections/HashMap.h"
#include "Token.h"
#include "Binary.h"
@@ -15,8 +16,6 @@ typedef enum CompilerState {
CompilerState_Success
} CompilerState;
typedef Section* SectionPtr;
HashMap_declare(SectionPtr);
typedef struct Compiler {
/* general fields */
@@ -26,8 +25,8 @@ typedef struct Compiler {
CompilerState state;
NULLABLE(char* error_message);
/* lexer fields */
List_Token tokens;
List_u32 line_lengths;
List(Token) tokens;
List(u32) line_lengths;
/* parser fields */
AST ast;
u32 tok_i;
@@ -35,8 +34,8 @@ typedef struct Compiler {
BinaryObject binary;
} Compiler;
void Compiler_init(Compiler* cmp);
void Compiler_free(Compiler* cmp);
void Compiler_construct(Compiler* cmp);
void Compiler_destroy(Compiler* cmp);
/// @brief compile assembly language code to machine code
/// @return true if no errors, false if any error occured (check cmp->error_message)

View File

@@ -1,5 +1,5 @@
#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)));

View File

@@ -103,7 +103,7 @@ static void readLabel(Compiler* cmp){
return;
}
if(!isAlphabeticalLower(c) && !isAlphabeticalUpper(c) && !isDigit(c) &&
if(!char_isLatinLower(c) && !char_isLatinUpper(c) && !char_isDigit(c) &&
c != '_' && c != '.'){
setError(Error_unexpectedCharacter(c));
return;
@@ -169,7 +169,7 @@ static void readArguments(Compiler* cmp){
tok.type = TokenType_NamedDataPointer;
else if(c == '#')
tok.type = TokenType_NamedDataSize;
else if(isDigit(c))
else if(char_isDigit(c))
tok.type = TokenType_Number;
else tok.type = TokenType_Name;
}
@@ -211,7 +211,7 @@ static void readInstruction(Compiler* cmp){
return;
}
if(!isAlphabeticalLower(c) && !isAlphabeticalUpper(c) && !isDigit(c)){
if(!char_isLatinLower(c) && !char_isLatinUpper(c) && !char_isDigit(c)){
setError(Error_unexpectedCharacter(c));
return;
}
@@ -248,7 +248,7 @@ bool Compiler_lex(Compiler* cmp){
break;
default:
// try read instruction
if(isAlphabeticalLower(c) || isAlphabeticalUpper(c))
if(char_isLatinLower(c) || char_isLatinUpper(c))
readInstruction(cmp);
else returnError(Error_unexpectedCharacter(c));
break;

View File

@@ -6,34 +6,25 @@
}
#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;\
Compiler_setError(cmp, "unexpected token '%s'", tok_str.data);\
free(tok_str.data);\
Compiler_setError(cmp, "unexpected token '"FMT_str"'", tok_str_tmp.len, tok_str_tmp.data);\
}
#define setError_unexpectedTokenChar(T, 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) {\
str tok_str = str_copy(Compiler_constructTokenStr(cmp, T));\
str tok_str_tmp = Compiler_constructTokenStr(cmp, T);\
cmp->pos = T.begin;\
Compiler_setError(cmp, "unexpected instruction '%s'", tok_str.data);\
free(tok_str.data);\
Compiler_setError(cmp, "unexpected instruction '"FMT_str"'", tok_str_tmp.len, tok_str_tmp.data);\
}
#define Error_TokenUnset "token of undefined type"
#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 NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
@@ -76,7 +67,7 @@ static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
break;
default:
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
StringBuilder_free(&sb);
StringBuilder_destroy(&sb);
return str_null;
}
@@ -90,13 +81,13 @@ static void parseDataDefinition(Compiler* cmp, str instr_name, DataDefinition* d
i32 _element_size_bits;
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)){
free(_instr_name_zero_terminated.data);
str_destroy(_instr_name_zero_terminated);
setError(Error_BitSize);
return;
}
free(_instr_name_zero_terminated.data);
str_destroy(_instr_name_zero_terminated);
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];
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);
if(str_seekChar(tok_str, '.', 0) != -1){
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 {
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;
case TokenType_Char:
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);
return;
}
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
free(processed_str.data);
List_u8_pushMany(&ddf->data_bytes, (u8*)processed_str.data, processed_str.len);
str_destroy(processed_str);
break;
case TokenType_String:
tok.begin += 1;
tok.length -= 2;
tok_str = Compiler_constructTokenStr(cmp, tok);
processed_str = resolveEscapeSequences(cmp, tok_str);
List_u8_pushBytes(&ddf->data, processed_str.data, 0, processed_str.len);
free(processed_str.data);
List_u8_pushMany(&ddf->data_bytes, (u8*)processed_str.data, processed_str.len);
str_destroy(processed_str);
break;
}
}
@@ -173,7 +168,7 @@ static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
}
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 };
str tok_str = str_null;
str processed_str = str_null;
@@ -204,7 +199,7 @@ static void parseOperation(Compiler* cmp, str instr_name, Operation* operPtr){
else {
arg.value.i = atoll(processed_str.data);
}
free(processed_str.data);
str_destroy(processed_str);
List_Argument_push(&operPtr->args, arg);
break;
case TokenType_Name:
@@ -257,7 +252,7 @@ bool Compiler_parse(Compiler* cmp){
case TokenType_Label:
// create new section
sec = List_Section_expand(&cmp->ast.sections, 1);
Section_init(sec, Compiler_constructTokenStr(cmp, tok));
Section_construct(sec, Compiler_constructTokenStr(cmp, tok));
break;
case TokenType_Instruction:
if(sec == NULL)
@@ -265,12 +260,12 @@ bool Compiler_parse(Compiler* cmp){
str instr_name = Compiler_constructTokenStr(cmp, tok);
// data definition starts with 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));
parseDataDefinition(cmp, instr_name, dataDefPtr);
}
else {
Operation* operPtr = List_Operation_expand(&sec->code, 1);
Operation* operPtr = List_Operation_expand(&sec->operations_list, 1);
memset(operPtr, 0, sizeof(Operation));
parseOperation(cmp, instr_name, operPtr);
}

View File

@@ -1,8 +1,8 @@
#include "Token.h"
List_define(Token);
Array_declare(str);
static str _TokenType_str[] = {
static Array(str) _TokenType_str_array = ARRAY(str, {
STR("Unset"),
STR("SingleLineComment"),
STR("MultiLineComment"),
@@ -15,10 +15,10 @@ static str _TokenType_str[] = {
STR("NamedDataPointer"),
STR("NamedDataSize"),
STR("OperationEnd"),
};
});
str TokenType_toString(TokenType t){
if(t >= ARRAY_SIZE(_TokenType_str))
if(t >= _TokenType_str_array.len)
return STR("!!TokenType INDEX_ERROR!!");
return _TokenType_str[t];
return _TokenType_str_array.data[t];
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "../collections/List.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
#include "tlibc/collections/List.h"
typedef enum TokenType {
TokenType_Unset, // initial value
@@ -26,6 +26,6 @@ typedef struct Token {
TokenType type : 8; // type of token (8 bits)
} Token;
List_declare(Token);
List_declare(Token)
#define Token_construct(TYPE, BEGIN, LEN) ((Token){ .type = TYPE, .begin = BEGIN, .length = LEN })

View File

@@ -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;
}

View File

@@ -2,5 +2,6 @@
/// NOP
i32 NOP_impl(VM* vm){
(void)vm;
return 0;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../instructions.h"
#include "../registers.h"
#include "instructions/instructions.h"
#include "instructions/registers.h"
#define readVar(VAR) {\
if(!VM_dataRead(vm, &VAR, vm->current_pos, sizeof(VAR))) \

View File

@@ -1,5 +1,5 @@
#include "instructions.h"
#include "../collections/HashMap.h"
#include "tlibc/collections/HashMap.h"
i32 NOP_impl(VM* vm);
i32 EXIT_impl(VM* vm);
@@ -30,9 +30,9 @@ i32 JMP_impl(VM* vm);
i32 JNZ_impl(VM* vm);
i32 JZ_impl(VM* vm);
Array_declare(Instruction);
static const Array_Instruction instructions_array = ARRAY(Instruction, {
static const Array(Instruction) instructions_array = ARRAY(Instruction, {
Instruction_construct(NOP),
Instruction_construct(EXIT),
Instruction_construct(SYS),
@@ -64,35 +64,39 @@ static const Array_Instruction instructions_array = ARRAY(Instruction, {
});
const Instruction* Instruction_getByOpcode(Opcode opcode){
if(opcode >= instructions_array.len)
if((u32)opcode >= instructions_array.len)
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){
if(instructions_map == NULL){
instructions_map = malloc(sizeof(HashMap_Instruction));
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]);
}
}
if(opcode_map == NULL)
_opcode_map_construct();
str name_upper = str_toUpper(name);
Instruction* iptr = HashMap_Instruction_tryGetPtr(instructions_map, name_upper);
free(name_upper.data);
return iptr;
Opcode* op_ptr = HashMap_tryGetPtr(opcode_map, name_upper);
str_destroy(name_upper);
if(op_ptr == NULL)
return NULL;
return Instruction_getByOpcode(*op_ptr);
}
void Instruction_freeSearchStructs(){
if(instructions_map != NULL){
HashMap_Instruction_free(instructions_map);
free(instructions_map);
void Instruction_destroySearchStructs(){
if(opcode_map != NULL){
HashMap_destroy(opcode_map);
free(opcode_map);
}
}
}

View File

@@ -1,5 +1,5 @@
#pragma once
#include "../VM/VM.h"
#include "VM/VM.h"
///@param program_pos position in vm->program next afrer opcode
///@returns number of bytes read
@@ -53,4 +53,4 @@ typedef struct Instruction {
/// @return ptr to struct or NULL
const Instruction* NULLABLE(Instruction_getByOpcode)(Opcode opcode);
const Instruction* NULLABLE(Instruction_getByName)(str name);
void Instruction_freeSearchStructs();
void Instruction_destroySearchStructs();

View File

@@ -30,7 +30,7 @@ RegisterCode RegisterCode_parse(str r){
else check_code(dl)
else check_code(dh)
free(lower.data);
str_destroy(lower);
return code;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../std.h"
#include "../string/str.h"
#include "tlibc/std.h"
#include "tlibc/string/str.h"
typedef enum RegisterCode {
RegisterCode_Unset = 0,

View File

@@ -1,11 +1,11 @@
#include "VM/VM.h"
#include "instructions/instructions.h"
#include "collections/List.h"
#include "compiler/Compiler.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 bootFromImage(cstr image_file);
@@ -24,15 +24,18 @@ i32 main(const i32 argc, cstr* argv){
cstr NULLABLE(source_file) = NULL;
bool debug_log = false;
bool video_enabled = false;
for(i32 argi = 1; argi < argc; argi++){
str arg_str = str_from_cstr(argv[argi]);
if(arg_is("-h") || arg_is("--help")){
printf(
"-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"
"-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;
}
@@ -80,6 +83,10 @@ i32 main(const i32 argc, cstr* argv){
else if(arg_is("-d") || arg_is("--debug")){
debug_log = true;
}
else if(arg_is("--video")){
video_enabled = true;
}
else {
printfe("ERROR: unknown argument '%s'\n", argv[argi]);
return 1;
@@ -89,13 +96,25 @@ i32 main(const i32 argc, cstr* argv){
i32 exit_code = 0;
if(compile){
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);
}
// frees global variables to supress valgrind memory leak errors
Instruction_freeSearchStructs();
main_exit:
Instruction_destroySearchStructs();
return exit_code;
}
@@ -119,11 +138,14 @@ i32 bootFromImage(cstr image_file){
}
VM vm;
VM_init(&vm);
VM_construct(&vm);
i32 exit_code = 1;
if(VM_setMemory(&vm, vm_memory, bytes_read)){
printf("===============================================================================\n");
exit_code = VM_boot(&vm);
printf("===============================================================================\n");
printfe("VM stopped with code %i\n", exit_code);
}
if(vm.state == VMState_InternalError){
if(vm.error_message){
@@ -133,17 +155,13 @@ i32 bootFromImage(cstr image_file){
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);
return exit_code;
}
i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
Compiler cmp;
Compiler_init(&cmp);
Compiler_construct(&cmp);
bool success = Compiler_compile(&cmp, source_file, out_file, debug_log);
if(!success){
if(cmp.error_message){
@@ -151,10 +169,10 @@ i32 compileSources(cstr source_file, cstr out_file, bool debug_log){
free(cmp.error_message);
}
else printfe("COMPILER ERROR: unknown (error_message is null)\n");
Compiler_free(&cmp);
Compiler_destroy(&cmp);
return 111;
}
Compiler_free(&cmp);
Compiler_destroy(&cmp);
return 0;
}

View File

@@ -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'; }

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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
View File

@@ -0,0 +1,3 @@
#pragma once
#define TCPU_VERSION_CSTR "1.0.0"