|
|
@ -1,7 +1,10 @@ |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <ctype.h> |
|
|
|
|
|
|
|
#ifndef NOSTDLIB |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <ctype.h> |
|
|
|
#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)*mi">128); |
|
|
|
memset(labels, 0, sizeof(struct label)*n">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 < mi">128; k++) { |
|
|
|
for(k = 0; k < n">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 < mi">128; k++) { |
|
|
|
for(k = 0; k < n">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++; |
|
|
|