diff --git a/ink.h b/ink.h index 22842cd..649b1c8 100644 --- a/ink.h +++ b/ink.h @@ -33,6 +33,7 @@ struct context { void*(*malloc)(size_t); void*(*realloc)(void*, size_t); void(*free)(void*); + int(*putchar)(int); struct elem* stack; int capacity; @@ -58,7 +59,7 @@ struct context { void ink_add_native(struct context* ctx, const char* name, void(*value)(struct context*)); void ink_push(struct context* ctx, struct elem value); void ink_push_fn(struct context* ctx, struct stack_frame value); -struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*)); +struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)); struct context* ink_make_default_context(); int ink_step(struct context *pContext); void ink_run(struct context *pContext, char* buffer); diff --git a/lib.c b/lib.c index de520d4..360a4ab 100644 --- a/lib.c +++ b/lib.c @@ -1,7 +1,10 @@ -#include -#include -#include -#include + +#ifndef NOSTDLIB + #include + #include + #include + #include +#endif #include "ink.h" #define INK_RESERVED (-1) @@ -14,6 +17,7 @@ #define _KEYWORD_INK_FUNCTION "fn" #define _KEYWORD_INK_DO "do" #define _KEYWORD_INK_END "end" +#define _KEYWORD_INK_RETURN "return" struct label { int active; @@ -21,6 +25,79 @@ struct label { char* name; }; +#ifdef NOSTDLIB + +static size_t strlen(const char* c) { + size_t j = 0; + while(*(c++)) { + j++; + } + return j; +} + +static void* memcpy(void* _dest, const void* _src, size_t sz) { + char* dest = _dest; + const char* src = _src; + while(sz--) { + *(dest++) = *(src++); + } + return dest; +} + +static int strcmp(const char* dest, const char* src) { + while(*dest != 0 && *src != 0) { + if(*(dest++) != *(src++)) { + return 1; + } + } + return 0; +} + +static void* memmove(void* _dest, const void* _src, size_t sz) { + char* dest = _dest; + const char* src = _src; + if (src < dest) { + src += sz; + dest += sz; + while (sz-- > 0) { + *--dest = *--src; + } + } else { + while (sz-- > 0) { + *dest++ = *src++; + } + } + return dest; +} + +static void* memset(void* _dest, int src, size_t sz) { + char* dest = _dest; + while(sz--) { + *(dest++) = src++; + } + return dest; +} + +static int isspace(int d) { + return d == ' ' || d == '\t' || d == '\n'; +} + +static int isdigit(int d) { + return '0' <= d && d <= '9'; +} + +static int atoi(const char* c) { + int ret = 0; + while(*c) { + ret *= 10; + ret += *c - '0'; + ++c; + } + return ret; +} + +#endif + void ink_add_native(struct context* ctx, const char* name, void(*value)(struct context*)) { if(ctx->native_words == NULL) { ctx->native_words = ctx->malloc(sizeof(struct native_fn) * 8); @@ -67,7 +144,7 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem for(i = 0; i < ctx->words_top; ++i) { if(strcmp(name, ctx->words[i].name) == 0) { ctx->free(ctx->words[i].things); - ctx->words[i].things = malloc(sizeof(struct elem) * count); + ctx->words[i].things = ctx->malloc(sizeof(struct elem) * count); memcpy(ctx->words[i].things, m, sizeof(struct elem) * count); ctx->words[i].size = count; return i; @@ -80,7 +157,7 @@ static int ink_add_indigenous(struct context* ctx, const char* name, struct elem } memcpy(copy, name, len); copy[len] = 0; - ctx->words[ctx->words_top].things = malloc(sizeof(struct elem) * count); + ctx->words[ctx->words_top].things = ctx->malloc(sizeof(struct elem) * count); memcpy(ctx->words[ctx->words_top].things, m, sizeof(struct elem) * count); ctx->words[ctx->words_top].size = count; ctx->words[ctx->words_top].name = copy; @@ -110,7 +187,7 @@ static int ink_add_lex_string(struct context* ctx, const char* name) { } int len = strlen(name); i = ctx->lex_reserved_words_top; - ctx->lex_reserved_words[i] = malloc(len+1); + ctx->lex_reserved_words[i] = ctx->malloc(len+1); memcpy(ctx->lex_reserved_words[i], name, len); ctx->lex_reserved_words[i][len] = 0; ctx->lex_reserved_words_top++; @@ -167,11 +244,12 @@ static void ink_pop(struct context* ctx) { ctx->top--; } -struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*)) { +struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)) { struct context* ctx = (struct context*)malloc(sizeof(struct context)); ctx->malloc = malloc; ctx->realloc = realloc; ctx->free = free; + ctx->putchar = putchar; ctx->panic = 0; ctx->stack = NULL; ctx->capacity = 0; @@ -191,17 +269,55 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, return ctx; } +/** + * Allocates a string that contains the integer + * @param _ context (used to allocate) + * @param cpy the value + * @return the allocated string, needs to be freed by ctx->free + */ +static char* ink_itoa(struct context* _, int cpy) { + char* n = _->malloc(16); + n[15] = 0; + char* it = n+15; + do { + it--; + *it = (cpy % 10) + '0'; + cpy = cpy / 10; + } while(cpy); + memmove(n, it, 16 - (it-n)); + return n; +} + static void print_stacktrace(struct context* _) { int i = 0; for(; i < _->function_stack_top; ++i) { struct elem thing = _->function_stack[i].executing; switch(thing.type) { - case INK_NATIVE_FUNCTION: - printf("%s\n", _->native_words[thing.value].name); + case INK_NATIVE_FUNCTION: { + char *n = _->native_words[thing.value].name; + while (*n) { + _->putchar(*n); + ++n; + } + _->putchar(10); break; - case INK_FUNCTION: - printf("%s:%d\n", _->words[thing.value].name, _->function_stack[i].index); + } + case INK_FUNCTION:{ + char *n = _->native_words[thing.value].name; + while (*n) { + _->putchar(*n); + ++n; + } + _->putchar(':'); + n = ink_itoa(_, _->function_stack[i].index); + while (*n) { + _->putchar(*n); + ++n; + } + _->free(n); + _->putchar(10); break; + } default: break; } @@ -223,6 +339,92 @@ static void add_int(struct context* ctx) { ctx->stack[ctx->top-1].value = a.value + b.value; } +static void dupe_elem(struct context* ctx) { + if(ctx->top < 1) { + ctx->panic = 1; + return; + } + struct elem a = ctx->stack[ctx->top-1]; + ink_push(ctx, a); +} + +static void drop_elem(struct context* ctx) { + if(ctx->top < 1) { + ctx->panic = 1; + return; + } + ink_pop(ctx); +} + +static void pluck_elem(struct context* ctx) { + if(ctx->top < 1) { + ctx->panic = 1; + return; + } + struct elem a = ctx->stack[ctx->top-1]; + if(a.type != INK_INTEGER) { + ctx->panic = 1; + return; + } + int position = ctx->top - (a.value + 1); + if(position >= ctx->top || position < 0) { + ctx->panic = 1; + return; + } + ink_pop(ctx); + ink_push(ctx, ctx->stack[position]); +} + +static void swap_elem(struct context* ctx) { + if(ctx->top < 2) { + ctx->panic = 1; + return; + } + struct elem a = ctx->stack[ctx->top-1]; + struct elem b = ctx->stack[ctx->top-2]; + ctx->stack[ctx->top-2] = a; + ctx->stack[ctx->top-1] = b; +} + +static void return_if(struct context* ctx) { + if(ctx->top < 1) { + ctx->panic = 1; + return; + } + struct elem a = ctx->stack[ctx->top-1]; + if(a.type != INK_INTEGER) { + ctx->panic = 1; + return; + } + if(a.value) { + ink_pop_fn(ctx); + ink_pop_fn(ctx); + } + ink_pop(ctx); + return; +} + +static void jump_if(struct context* ctx) { + if(ctx->top < 1) { + ctx->panic = 1; + return; + } + struct elem a = ctx->stack[ctx->top-1]; + if(a.type != INK_INTEGER) { + ctx->panic = 1; + return; + } + ink_pop(ctx); + if(a.value) { + ink_pop_fn(ctx); + a = ctx->stack[ctx->top-1]; + ctx->function_stack[ctx->function_stack_top - 1].index += a.value - 3; + ink_pop(ctx); + //printf("\t*%d\n", ctx->function_stack[ctx->function_stack_top - 1].index); + } + return; +} + static void print_int(struct context* ctx) { if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { ctx->panic = 1; @@ -230,7 +432,13 @@ static void print_int(struct context* ctx) { } struct elem a = ctx->stack[ctx->top-1]; ink_pop(ctx); - printf("%d", a.value); + char* n = ink_itoa(ctx, a.value); + char* str = n; + while (*str) { + ctx->putchar(*str); + ++str; + } + ctx->free(n); } static void print_as_utf8(struct context* ctx) { @@ -240,19 +448,19 @@ static void print_as_utf8(struct context* ctx) { } struct elem a = ctx->stack[ctx->top-1]; if(a.value <= 0x7F) { - putc(a.value, stdout); + ctx->putchar(a.value); } else if(a.value <= 0x7FF) { - putc(((a.value & 0xFC0) >> 6) | 192, stdout); - putc((a.value & 0x3F) | 128, stdout); + ctx->putchar(((a.value & 0xFC0) >> 6) | 192); + ctx->putchar((a.value & 0x3F) | 128); } else if(a.value <= 0xFFFF) { - putc(((a.value & 0x3F000) >> 12) | 224, stdout); - putc(((a.value & 0xFC0) >> 6) | 128, stdout); - putc((a.value & 0x3F) | 128, stdout); + ctx->putchar(((a.value & 0x3F000) >> 12) | 224); + ctx->putchar(((a.value & 0xFC0) >> 6) | 128); + ctx->putchar((a.value & 0x3F) | 128); } else if(a.value <= 0x10FFFF) { - putc(((a.value & 0x3C0000) >> 18) | 240, stdout); - putc(((a.value & 0x3F000) >> 12) | 128, stdout); - putc(((a.value & 0xFC0) >> 6) | 128, stdout); - putc((a.value & 0x3F) | 128, stdout); + ctx->putchar(((a.value & 0x3C0000) >> 18) | 240); + ctx->putchar(((a.value & 0x3F000) >> 12) | 128); + ctx->putchar(((a.value & 0xFC0) >> 6) | 128); + ctx->putchar((a.value & 0x3F) | 128); } else { ctx->panic = 1; return; @@ -260,14 +468,22 @@ static void print_as_utf8(struct context* ctx) { ink_pop(ctx); } +#ifndef NOSTDLIB struct context* ink_make_default_context() { - struct context* ctx = ink_make_context(malloc, realloc, free); + struct context* ctx = ink_make_context(malloc, realloc, free, putchar); ink_add_native(ctx, "trace", print_stacktrace); ink_add_native(ctx, "print_int", print_int); ink_add_native(ctx, "print_utf8", print_as_utf8); ink_add_native(ctx, "+", add_int); + ink_add_native(ctx, "swap", swap_elem); + ink_add_native(ctx, "dup", dupe_elem); + ink_add_native(ctx, "drop", drop_elem); + ink_add_native(ctx, "pluck", pluck_elem); + ink_add_native(ctx, "return_if", return_if); + ink_add_native(ctx, "jump_if", jump_if); return ctx; } +#endif static void ink_consume_one(int* end, struct context* pContext, char** buffer, char* r) { int i; @@ -297,6 +513,13 @@ static void ink_consume_one(int* end, struct context* pContext, char** buffer, c ink_push(pContext, value); done = 1; } + if (!done && strcmp(r, _KEYWORD_INK_RETURN) == 0) { + struct elem value; + value.value = 0; + value.type = INK_RETURN; + ink_push(pContext, value); + done = 1; + } if (!done) { for (i = 0; i < pContext->words_top; ++i) { if (strcmp(r, pContext->words[i].name) == 0) { @@ -375,17 +598,26 @@ static int lblcmp(const char* label, const char* other, size_t label_sz) { return 0; } +/** + * + * @param pContext + * @param executable_buffer + * @param executable_buffer_top + * @internal Loop from hell + */ static void ink_parse(struct context* pContext, struct elem* executable_buffer, int* executable_buffer_top) { int i; - struct label labels[128]; - struct elem function_buffer[256]; +#define LABEL_BUFFER 128 +#define FUNCTION_BUFFER 256 + struct label labels[LABEL_BUFFER]; + struct elem function_buffer[FUNCTION_BUFFER]; int function_buffer_top = 0; int function_name = -1; #define MODE_EXECUTABLE 0 #define MODE_FUNCTION 1 #define MODE_DO 2 int mode = 0; - memset(labels, 0, sizeof(struct label)*128); + memset(labels, 0, sizeof(struct label)*LABEL_BUFFER); for(i = 0; i < pContext->top; ++i) { struct elem current = pContext->stack[i]; switch (mode) { @@ -427,7 +659,7 @@ static void ink_parse(struct context* pContext, struct elem* executable_buffer, struct elem pt = function_buffer[j]; if(pt.type == INK_LABEL) { int k; - for(k = 0; k < 128; k++) { + for(k = 0; k < LABEL_BUFFER; k++) { if(labels[k].active) { if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) { labels[k].dest = j; @@ -451,7 +683,7 @@ static void ink_parse(struct context* pContext, struct elem* executable_buffer, if(pt.type == INK_RESERVED) { const char* str = pContext->lex_reserved_words[pt.value]; int k; - for(k = 0; k < 128; k++) { + for(k = 0; k < LABEL_BUFFER; k++) { if(labels[k].active) { const char* lbl = labels[k].name; int label_sz = strlen(lbl); @@ -481,12 +713,14 @@ static void ink_parse(struct context* pContext, struct elem* executable_buffer, #undef MODE_EXECUTABLE #undef MODE_FUNCTION #undef MODE_DO + +#undef LABEL_BUFFER +#undef FUNCTION_BUFFER } int ink_step(struct context *pContext) { if(pContext->function_stack_top == 0) return 0; if(pContext->panic) { - perror("PANIC!!!\n"); return -1; } struct stack_frame* top = &pContext->function_stack[pContext->function_stack_top-1]; @@ -511,8 +745,13 @@ int ink_step(struct context *pContext) { if(top->index >= pContext->words[top->executing.value].size) { ink_pop_fn(pContext); } else { + struct elem next = pContext->words[top->executing.value].things[top->index]; + if(next.type == INK_RETURN) { + ink_pop_fn(pContext); + return 1; + } struct stack_frame frame; - frame.executing = pContext->words[top->executing.value].things[top->index]; + frame.executing = next; frame.index = 0; ink_push_fn(pContext, frame); top->index++; diff --git a/main.c b/main.c index 766ce7f..0c06264 100644 --- a/main.c +++ b/main.c @@ -13,6 +13,11 @@ int main(int argc, char** argv) { } read_buffer[cnt] = 0; ink_run(ctx, read_buffer); + + if(ctx->panic) { + perror("Panicked !!"); + } + fclose(file); } diff --git a/test/test01.nk b/test/test01.nk index cc27c58..25bd71c 100644 --- a/test/test01.nk +++ b/test/test01.nk @@ -1,3 +1,16 @@ fn potato do - label: trace trace label print_int 10 print_utf8 endfn print_int 10 print_utf8 endfn: + trace return +end + +fn print_n_utf8_impl do + start: + -1 + swap print_utf8 + dup start swap jump_if +end + +fn potato2 do + start: + -1 + dup + 65 print_utf8 10 print_utf8 + start swap jump_if end \ No newline at end of file diff --git a/test/test02.nk b/test/test02.nk index d64e5a3..3fc8712 100644 --- a/test/test02.nk +++ b/test/test02.nk @@ -1 +1,3 @@ -potato potato \ No newline at end of file +fn print_n_utf8 do + print_n_utf8_impl drop +end diff --git a/test/test03.nk b/test/test03.nk new file mode 100644 index 0000000..0648943 --- /dev/null +++ b/test/test03.nk @@ -0,0 +1 @@ +100 108 114 111 119 32 111 108 108 101 72 11 print_n_utf8 \ No newline at end of file