diff --git a/.gitignore b/.gitignore index 4d0826a..bb39ecf 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -cmake-build-* \ No newline at end of file +cmake-build-* +.idea/* \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/ink.iml b/.idea/ink.iml deleted file mode 100644 index f08604b..0000000 --- a/.idea/ink.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 79b3c94..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 0df1c94..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 65bbea2..eaf6b50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,16 @@ project(ink C) set(CMAKE_C_STANDARD 90) add_library(ink lib.c ink.h) + +# Uncomment to disable the redundant arithmetic +# add_definitions(-DNOEXTRAARITHMETIC) + +# Uncomment to disable array types +# add_definitions(-DNOARRAYLIB) + +# Ensures the interpreter doesn't use the standard C library functions +# add_definitions(-DNOSTDLIB) + add_executable(ink_exe main.c) target_link_libraries(ink_exe PUBLIC ink) diff --git a/README.md b/README.md index bcf101b..7d0c706 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # `ink` -`ink` is a minimalistic interpreted programming language, tentatively implemented exclusively in C98. It features -coroutines and can currently only manipulate integers. Part of the code may not be compliant with C98 and I will try to +`ink` is a minimalistic interpreted programming language, tentatively implemented exclusively in C89. It features +coroutines and can currently only manipulate integers. Part of the code may not be compliant with C89 and I will try to fix that in time. It is fully self-contained and doesn't rely on a working standard library beyond the following: @@ -13,8 +13,8 @@ It is fully self-contained and doesn't rely on a working standard library beyond To make the library not use the standard library, build it with `NOSTDLIB` defined as a preprocessor directive. -All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. In the -future, I will add a garbage collector to handle cleaning dynamically allocated resources. +All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. I added a +garbage collector to handle cleaning dynamically allocated resources. It is possible to segregate unsafe allocations (allocations that should be hidden from the interpreter) by setting the `inner_` versions of the library functions to different allocation functions. diff --git a/ink.h b/ink.h index 22afddc..e77d8ee 100644 --- a/ink.h +++ b/ink.h @@ -94,6 +94,9 @@ struct ink_collection_list { int count; }; +/** + * Contains the data and metadata of an embedded element including the pointer to the element + */ struct element_slab { void* data; int uses; @@ -247,7 +250,7 @@ int ink_step_everyone(struct context *pContext); * @param pContext The context to execute the code in * @param buffer The buffer that contains the source as a NULL terminated string */ -void ink_compile(struct context *pContext, char *buffer); +void ink_compile(struct context *pContext, const char *buffer); /** * Includes the standard library in the specified context diff --git a/lib.c b/lib.c index 42100ea..538d4c7 100644 --- a/lib.c +++ b/lib.c @@ -514,7 +514,7 @@ int ink_make_routine(struct context* ctx) { int new_count; void* renewed; new_count = (ctx->routines_capacity + ctx->routines_capacity/2); - renewed = ctx->inner_realloc(ctx->routines, sizeof(struct stack_frame) * new_count); + renewed = ctx->inner_realloc(ctx->routines, sizeof(struct ink_routine) * new_count); if(renewed == NULL) { return -99; } else { @@ -770,7 +770,7 @@ int ink_step(struct context *pContext) { return 1; } -void ink_compile(struct context *pContext, char* buffer) { +void ink_compile(struct context *pContext, const char* buffer) { int routine, saved, executable_buffer_top; /* Main function has a size limit of 256 (need to know that for REPL */ struct elem executable_buffer[256]; @@ -1012,6 +1012,8 @@ void ink_gc(struct context* ctx) { } } + /* TODO: Mark objects contained within function code */ + /* Mark the rest of the data */ do { marked = 0; @@ -1171,6 +1173,46 @@ static void div_int(struct context* ctx) { currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value; } +static void is_equal(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + struct elem ret; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + ink_pop(ctx); + ink_pop(ctx); + ret.type = INK_INTEGER; + ret.value = a.value == b.value && a.type == b.type; + +} + +static void is_different(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + struct elem ret; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + ink_pop(ctx); + ink_pop(ctx); + ret.type = INK_INTEGER; + ret.value = !(a.value == b.value && a.type == b.type); + +} + +#ifndef NOEXTRAARITHMETIC + static void rem_int(struct context* ctx) { struct ink_routine* currentRoutine; struct elem a; @@ -1190,6 +1232,84 @@ static void rem_int(struct context* ctx) { currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value; } +static void gt_int(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { + currentRoutine->panic = -1; + return; + } + ink_pop(ctx); + currentRoutine->stack[currentRoutine->top-1].value = b.value > a.value; +} + +static void gte_int(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { + currentRoutine->panic = -1; + return; + } + ink_pop(ctx); + currentRoutine->stack[currentRoutine->top-1].value = b.value >= a.value; +} + +static void lte_int(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { + currentRoutine->panic = -1; + return; + } + ink_pop(ctx); + currentRoutine->stack[currentRoutine->top-1].value = b.value <= a.value; +} + +#endif // NOEXTRAARITHMETIC + +static void lt_int(struct context* ctx) { + struct ink_routine* currentRoutine; + struct elem a; + struct elem b; + currentRoutine = ctx->routines + ctx->routine_current; + if(currentRoutine->top < 2) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top-1]; + b = currentRoutine->stack[currentRoutine->top-2]; + if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { + currentRoutine->panic = -1; + return; + } + ink_pop(ctx); + currentRoutine->stack[currentRoutine->top-1].value = b.value < a.value; +} + static void dupe_elem(struct context* ctx) { struct ink_routine* currentRoutine; struct elem a; @@ -1348,12 +1468,6 @@ static void print_as_utf8(struct context* ctx) { ink_pop(ctx); } -struct ink_array { - int top; - int capacity; - struct elem* elements; -}; - static int get_type_by_name(struct context* ctx, const char* name) { int i; for(i = 0; i < ctx->types_top; ++i) { @@ -1364,20 +1478,50 @@ static int get_type_by_name(struct context* ctx, const char* name) { return -1; } +static void run_gc(struct context* ctx) { + ink_gc(ctx); +} + +static void clear_stack(struct context* ctx) { + struct ink_routine* currentRoutine; + currentRoutine = ctx->routines + ctx->routine_current; + while (currentRoutine->top >= 1) { + ink_pop(ctx); + } + return; +} + +static void collect_noop(struct context* _1, void* _2) {} + +static struct ink_collection_list gc_noop(struct context* _1, void* _2) { + struct ink_collection_list c; + c.elements = NULL; + c.count = 0; + return c; +} + +#ifndef NOARRAYLIB + +struct ink_array { + int top; + int capacity; + struct elem* elements; +}; + static void collect_array(struct context* ctx, void* array) { - struct ink_array* ary; + struct ink_array* ary; ary = array; - if(ary->elements != NULL) ctx->free(ary->elements); + if(ary->elements != NULL) ctx->free(ary->elements); } static struct ink_collection_list gc_array(struct context* ctx, void* array) { - struct ink_array* ary; - struct ink_collection_list c; + struct ink_array* ary; + struct ink_collection_list c; ary = array; - c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); - c.count = ary->top; - memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); - return c; + c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top); + c.count = ary->top; + memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top); + return c; } static void new_array(struct context* ctx) { @@ -1527,6 +1671,33 @@ static void index_array(struct context* ctx) { ink_push(ctx, ary->elements[idx.value]); } +static void get_size_array(struct context* ctx) { + int tid; + struct ink_routine *currentRoutine; + struct elem a; + struct ink_array *ary; + struct elem sz; + + tid = get_type_by_name(ctx, "array"); + currentRoutine = ctx->routines + ctx->routine_current; + if (currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top - 1].type != tid) { + currentRoutine->panic = -1; + return; + } + a = currentRoutine->stack[currentRoutine->top - 1]; + ary = ink_get_value(ctx, a); + if (ary == NULL) { + currentRoutine->panic = -1; + return; + } + ink_pop(ctx); + + sz.type = INK_INTEGER; + sz.value = ary->top; + + ink_push(ctx, sz); +} + static void print_array_of_codepoints(struct context* ctx) { int tid, i; struct ink_routine *currentRoutine; @@ -1556,19 +1727,6 @@ static void print_array_of_codepoints(struct context* ctx) { } } -static void run_gc(struct context* ctx) { - ink_gc(ctx); -} - -static void clear_stack(struct context* ctx) { - struct ink_routine* currentRoutine; - currentRoutine = ctx->routines + ctx->routine_current; - while (currentRoutine->top >= 1) { - ink_pop(ctx); - } - return; -} - static void arrayify_stack(struct context* ctx) { struct ink_routine* currentRoutine; struct elem array_ref; @@ -1594,27 +1752,11 @@ static void arrayify_stack(struct context* ctx) { return; } - -static void collect_noop(struct context*, void*) {} - -static struct ink_collection_list gc_noop(struct context*, void*) { - struct ink_collection_list c; - c.elements = NULL; - c.count = 0; - return c; -} +#endif // NOARRAYLIB int ink_std_library(struct context* ctx) { int v; v = 0; - ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array); - ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop); - v += ink_add_native(ctx, "[", push_array_stack_delim); - v += ink_add_native(ctx, "]", push_delimited_array); - v += ink_add_native(ctx, "array.new", new_array); - v += ink_add_native(ctx, "array.push", push_array); - v += ink_add_native(ctx, "array.index", index_array); - v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints); v += ink_add_native(ctx, "sys.trace", print_stacktrace); v += ink_add_native(ctx, "sys.gc", run_gc); v += ink_add_native(ctx, "print_int", print_int); @@ -1623,14 +1765,35 @@ int ink_std_library(struct context* ctx) { v += ink_add_native(ctx, "-", sub_int); v += ink_add_native(ctx, "*", mult_int); v += ink_add_native(ctx, "/", div_int); - v += ink_add_native(ctx, "%", rem_int); + v += ink_add_native(ctx, "==", is_equal); + v += ink_add_native(ctx, "!=", is_different); + v += ink_add_native(ctx, "<", lt_int); v += ink_add_native(ctx, "swap", swap_elem); v += ink_add_native(ctx, "dup", dupe_elem); v += ink_add_native(ctx, "drop", drop_elem); v += ink_add_native(ctx, "stack.clear", clear_stack); - v += ink_add_native(ctx, "stack.to_array", arrayify_stack); v += ink_add_native(ctx, "pluck", pluck_elem); v += ink_add_native(ctx, "return_if", return_if); v += ink_add_native(ctx, "jump_if", jump_if); +#ifndef NOEXTRAARITHMETIC + v += ink_add_native(ctx, ">", gt_int); + v += ink_add_native(ctx, ">=", gte_int); + v += ink_add_native(ctx, "=<", lte_int); + v += ink_add_native(ctx, "%", rem_int); +#endif // NOEXTRAARITHMETIC +#ifndef NOARRAYLIB + ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array); + ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop); + v += ink_add_native(ctx, "[", push_array_stack_delim); + v += ink_add_native(ctx, "]", push_delimited_array); + v += ink_add_native(ctx, "array.new", new_array); + v += ink_add_native(ctx, "array.push", push_array); + v += ink_add_native(ctx, "array.index", index_array); + v += ink_add_native(ctx, "array.size", get_size_array); + v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints); + v += ink_add_native(ctx, "stack.to_array", arrayify_stack); +#endif // NOARRAYLIB + return v; -} \ No newline at end of file +} +