|
@ -4,6 +4,9 @@ |
|
|
#include <stdlib.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <string.h> |
|
|
#include <ctype.h> |
|
|
#include <ctype.h> |
|
|
|
|
|
#ifndef NOINSTR |
|
|
|
|
|
#include <time.h> |
|
|
|
|
|
#endif |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#define INK_RESERVED (-1) |
|
|
#define INK_RESERVED (-1) |
|
@ -195,55 +198,64 @@ static int ink_add_lex_string(struct context* ctx, const char* name) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int ink_push(struct context* ctx, struct elem value) { |
|
|
int ink_push(struct context* ctx, struct elem value) { |
|
|
if(ctx->stack == NULL) { |
|
|
|
|
|
ctx->stack = ctx->malloc(sizeof(struct elem) * 8); |
|
|
|
|
|
ctx->top = 0; |
|
|
|
|
|
ctx->capacity = 8; |
|
|
|
|
|
} else if(ctx->top == ctx->capacity) { |
|
|
|
|
|
int new_count = (ctx->capacity + ctx->capacity/2); |
|
|
|
|
|
void* renewed = ctx->realloc(ctx->stack, sizeof(struct elem) * new_count); |
|
|
|
|
|
|
|
|
if(ctx->routine_current >= ctx->routines_top) return -65; |
|
|
|
|
|
struct ink_routine* current = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(current->stack == NULL) { |
|
|
|
|
|
current->stack = ctx->malloc(sizeof(struct elem) * 8); |
|
|
|
|
|
current->top = 0; |
|
|
|
|
|
current->capacity = 8; |
|
|
|
|
|
} else if(current->top == current->capacity) { |
|
|
|
|
|
int new_count = (current->capacity + current->capacity/2); |
|
|
|
|
|
void* renewed = ctx->realloc(current->stack, sizeof(struct elem) * new_count); |
|
|
if(renewed == NULL) { |
|
|
if(renewed == NULL) { |
|
|
return -18; |
|
|
return -18; |
|
|
} else { |
|
|
} else { |
|
|
ctx->stack = renewed; |
|
|
|
|
|
ctx->capacity = new_count; |
|
|
|
|
|
|
|
|
current->stack = renewed; |
|
|
|
|
|
current->capacity = new_count; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
ctx->stack[ctx->top] = value; |
|
|
|
|
|
ctx->top++; |
|
|
|
|
|
|
|
|
current->stack[current->top] = value; |
|
|
|
|
|
current->top++; |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int ink_push_fn(struct context* ctx, struct stack_frame value) { |
|
|
int ink_push_fn(struct context* ctx, struct stack_frame value) { |
|
|
if(ctx->function_stack == NULL) { |
|
|
|
|
|
ctx->function_stack = ctx->malloc(sizeof(struct stack_frame) * 8); |
|
|
|
|
|
ctx->function_stack_top = 0; |
|
|
|
|
|
ctx->function_stack_capacity = 8; |
|
|
|
|
|
} else if(ctx->function_stack_top == ctx->function_stack_capacity) { |
|
|
|
|
|
int new_count = (ctx->function_stack_capacity + ctx->function_stack_capacity/2); |
|
|
|
|
|
void* renewed = ctx->realloc(ctx->function_stack, sizeof(struct stack_frame) * new_count); |
|
|
|
|
|
|
|
|
if(ctx->routine_current >= ctx->routines_top) return -55; |
|
|
|
|
|
struct ink_routine* current = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(current->panic) return -56; |
|
|
|
|
|
if(current->function_stack == NULL) { |
|
|
|
|
|
current->function_stack = ctx->malloc(sizeof(struct stack_frame) * 8); |
|
|
|
|
|
current->function_stack_top = 0; |
|
|
|
|
|
current->function_stack_capacity = 8; |
|
|
|
|
|
} else if(current->function_stack_top == current->function_stack_capacity) { |
|
|
|
|
|
int new_count = (current->function_stack_capacity + current->function_stack_capacity/2); |
|
|
|
|
|
void* renewed = ctx->realloc(current->function_stack, sizeof(struct stack_frame) * new_count); |
|
|
if(renewed == NULL) { |
|
|
if(renewed == NULL) { |
|
|
return -9; |
|
|
return -9; |
|
|
} else { |
|
|
} else { |
|
|
ctx->function_stack = renewed; |
|
|
|
|
|
ctx->function_stack_capacity = new_count; |
|
|
|
|
|
|
|
|
current->function_stack = renewed; |
|
|
|
|
|
current->function_stack_capacity = new_count; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
ctx->function_stack[ctx->function_stack_top] = value; |
|
|
|
|
|
ctx->function_stack_top++; |
|
|
|
|
|
|
|
|
current->function_stack[current->function_stack_top] = value; |
|
|
|
|
|
current->function_stack_top++; |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void ink_pop_fn(struct context* ctx) { |
|
|
|
|
|
if(ctx->function_stack == NULL) return; |
|
|
|
|
|
if(ctx->function_stack_top == 0) return; |
|
|
|
|
|
ctx->function_stack_top--; |
|
|
|
|
|
|
|
|
void ink_pop_fn(struct context* ctx) { |
|
|
|
|
|
if(ctx->routine_current >= ctx->routines_top) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].panic) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].function_stack == NULL) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].function_stack_top == 0) return; |
|
|
|
|
|
ctx->routines[ctx->routine_current].function_stack_top--; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void ink_pop(struct context* ctx) { |
|
|
|
|
|
if(ctx->stack == NULL) return; |
|
|
|
|
|
if(ctx->top == 0) return; |
|
|
|
|
|
ctx->top--; |
|
|
|
|
|
|
|
|
void ink_pop(struct context* ctx) { |
|
|
|
|
|
if(ctx->routine_current >= ctx->routines_top) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].panic) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].stack == NULL) return; |
|
|
|
|
|
if(ctx->routines[ctx->routine_current].top == 0) return; |
|
|
|
|
|
ctx->routines[ctx->routine_current].top--; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)) { |
|
|
struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*), int(*putchar)(int)) { |
|
@ -253,12 +265,9 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, |
|
|
ctx->free = free; |
|
|
ctx->free = free; |
|
|
ctx->putchar = putchar; |
|
|
ctx->putchar = putchar; |
|
|
ctx->panic = 0; |
|
|
ctx->panic = 0; |
|
|
ctx->stack = NULL; |
|
|
|
|
|
ctx->capacity = 0; |
|
|
|
|
|
ctx->top = 0; |
|
|
|
|
|
ctx->function_stack = NULL; |
|
|
|
|
|
ctx->function_stack_capacity = 0; |
|
|
|
|
|
ctx->function_stack_top = 0; |
|
|
|
|
|
|
|
|
ctx->routines = NULL; |
|
|
|
|
|
ctx->routines_capacity = 0; |
|
|
|
|
|
ctx->routines_top = 0; |
|
|
ctx->native_words = NULL; |
|
|
ctx->native_words = NULL; |
|
|
ctx->native_words_capacity = 0; |
|
|
ctx->native_words_capacity = 0; |
|
|
ctx->native_words_top = 0; |
|
|
ctx->native_words_top = 0; |
|
@ -268,6 +277,7 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, |
|
|
ctx->lex_reserved_words = NULL; |
|
|
ctx->lex_reserved_words = NULL; |
|
|
ctx->lex_reserved_words_capacity = 0; |
|
|
ctx->lex_reserved_words_capacity = 0; |
|
|
ctx->lex_reserved_words_top = 0; |
|
|
ctx->lex_reserved_words_top = 0; |
|
|
|
|
|
ctx->steps = 0; |
|
|
return ctx; |
|
|
return ctx; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -276,6 +286,7 @@ struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, |
|
|
* @param _ context (used to allocate) |
|
|
* @param _ context (used to allocate) |
|
|
* @param cpy the value |
|
|
* @param cpy the value |
|
|
* @return the allocated string, needs to be freed by ctx->free |
|
|
* @return the allocated string, needs to be freed by ctx->free |
|
|
|
|
|
* @internal this function is slightly cursed |
|
|
*/ |
|
|
*/ |
|
|
static char* ink_itoa(struct context* _, int cpy) { |
|
|
static char* ink_itoa(struct context* _, int cpy) { |
|
|
char* n = _->malloc(16); |
|
|
char* n = _->malloc(16); |
|
@ -439,6 +450,74 @@ static int lblcmp(const char* label, const char* other, size_t label_sz) { |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ink_make_routine(struct context* ctx) { |
|
|
|
|
|
if(ctx->routines == NULL) { |
|
|
|
|
|
ctx->routines = ctx->malloc(sizeof(struct ink_routine) * 8); |
|
|
|
|
|
ctx->routines_top = 0; |
|
|
|
|
|
ctx->routines_capacity = 8; |
|
|
|
|
|
struct ink_routine* it = ctx->routines; |
|
|
|
|
|
struct ink_routine* end = ctx->routines + 8; |
|
|
|
|
|
for(;it != end;++it) { |
|
|
|
|
|
it->stack = NULL; |
|
|
|
|
|
it->function_stack = NULL; |
|
|
|
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
|
|
} |
|
|
|
|
|
} else if(ctx->routines_top == ctx->routines_capacity) { |
|
|
|
|
|
int new_count = (ctx->routines_capacity + ctx->routines_capacity/2); |
|
|
|
|
|
void* renewed = ctx->realloc(ctx->routines, sizeof(struct stack_frame) * new_count); |
|
|
|
|
|
if(renewed == NULL) { |
|
|
|
|
|
return -99; |
|
|
|
|
|
} else { |
|
|
|
|
|
ctx->routines = renewed; |
|
|
|
|
|
struct ink_routine* it = ctx->routines + ctx->routines_capacity; |
|
|
|
|
|
struct ink_routine* end = ctx->routines + new_count; |
|
|
|
|
|
for(;it != end;++it) { |
|
|
|
|
|
it->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
|
|
} |
|
|
|
|
|
ctx->routines_capacity = new_count; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct ink_routine* it = ctx->routines; |
|
|
|
|
|
struct ink_routine* end = ctx->routines + ctx->routines_capacity; |
|
|
|
|
|
|
|
|
|
|
|
for(;it != end;++it) { |
|
|
|
|
|
if(it->panic == INK_ROUTINE_CAN_REUSE) { |
|
|
|
|
|
it->panic = 0; |
|
|
|
|
|
it->stack = NULL; |
|
|
|
|
|
it->top = 0; |
|
|
|
|
|
it->capacity = 0; |
|
|
|
|
|
it->function_stack = NULL; |
|
|
|
|
|
it->function_stack_top = 0; |
|
|
|
|
|
it->function_stack_capacity = 0; |
|
|
|
|
|
int idx = it - ctx->routines; |
|
|
|
|
|
if(idx >= ctx->routines_top) { |
|
|
|
|
|
ctx->routines_top = idx + 1; |
|
|
|
|
|
} |
|
|
|
|
|
return idx; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ink_kill_routine(struct context* ctx, int routine){ |
|
|
|
|
|
if(routine < 0 || routine >= ctx->routines_top) { |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
struct ink_routine* curr = ctx->routines + routine; |
|
|
|
|
|
if(curr->panic == INK_ROUTINE_CAN_REUSE) { |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
if(curr->stack != NULL) { |
|
|
|
|
|
ctx->free(curr->stack); |
|
|
|
|
|
curr->stack = NULL; |
|
|
|
|
|
} |
|
|
|
|
|
if(curr->function_stack != NULL) { |
|
|
|
|
|
ctx->free(curr->function_stack); |
|
|
|
|
|
curr->function_stack = NULL; |
|
|
|
|
|
} |
|
|
|
|
|
curr->panic = INK_ROUTINE_CAN_REUSE; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* |
|
|
* |
|
|
* @param pContext |
|
|
* @param pContext |
|
@ -447,6 +526,7 @@ static int lblcmp(const char* label, const char* other, size_t label_sz) { |
|
|
* @internal Loop from hell |
|
|
* @internal Loop from hell |
|
|
*/ |
|
|
*/ |
|
|
static int ink_parse(struct context* pContext, struct elem* executable_buffer, int* executable_buffer_top) { |
|
|
static int ink_parse(struct context* pContext, struct elem* executable_buffer, int* executable_buffer_top) { |
|
|
|
|
|
struct ink_routine* currentRoutine = pContext->routines + pContext->routine_current; |
|
|
int i; |
|
|
int i; |
|
|
#define LABEL_BUFFER 128 |
|
|
#define LABEL_BUFFER 128 |
|
|
#define FUNCTION_BUFFER 256 |
|
|
#define FUNCTION_BUFFER 256 |
|
@ -459,9 +539,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
#define MODE_DO 2 |
|
|
#define MODE_DO 2 |
|
|
int mode = 0; |
|
|
int mode = 0; |
|
|
memset(labels, 0, sizeof(struct label)*LABEL_BUFFER); |
|
|
memset(labels, 0, sizeof(struct label)*LABEL_BUFFER); |
|
|
for(i = 0; i < pContext->top; ++i) { |
|
|
|
|
|
|
|
|
for(i = 0; i < currentRoutine->top; ++i) { |
|
|
struct elem current; |
|
|
struct elem current; |
|
|
current = pContext->stack[i]; |
|
|
|
|
|
|
|
|
current = currentRoutine->stack[i]; |
|
|
switch (mode) { |
|
|
switch (mode) { |
|
|
case MODE_EXECUTABLE: |
|
|
case MODE_EXECUTABLE: |
|
|
switch(current.type) { |
|
|
switch(current.type) { |
|
@ -570,7 +650,9 @@ static int ink_parse(struct context* pContext, struct elem* executable_buffer, i |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int ink_step(struct context *pContext) { |
|
|
int ink_step(struct context *pContext) { |
|
|
if(pContext->function_stack_top == 0) return 0; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = pContext->routines + pContext->routine_current; |
|
|
|
|
|
pContext->steps++; |
|
|
|
|
|
if(currentRoutine->function_stack_top == 0) return 0; |
|
|
if(pContext->panic) { |
|
|
if(pContext->panic) { |
|
|
return -1; |
|
|
return -1; |
|
|
} |
|
|
} |
|
@ -578,7 +660,7 @@ int ink_step(struct context *pContext) { |
|
|
struct stack_frame* top; |
|
|
struct stack_frame* top; |
|
|
struct elem next; |
|
|
struct elem next; |
|
|
int t; |
|
|
int t; |
|
|
top = &pContext->function_stack[pContext->function_stack_top-1]; |
|
|
|
|
|
|
|
|
top = ¤tRoutine->function_stack[currentRoutine->function_stack_top-1]; |
|
|
t = top->executing.type; |
|
|
t = top->executing.type; |
|
|
switch(t) { |
|
|
switch(t) { |
|
|
case INK_NATIVE_FUNCTION: |
|
|
case INK_NATIVE_FUNCTION: |
|
@ -628,11 +710,14 @@ int ink_step(struct context *pContext) { |
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void ink_run(struct context *pContext, char* buffer) { |
|
|
|
|
|
pContext->free(pContext->stack); |
|
|
|
|
|
pContext->stack = NULL; |
|
|
|
|
|
pContext->top = 0; |
|
|
|
|
|
pContext->capacity = 0; |
|
|
|
|
|
|
|
|
void ink_compile(struct context *pContext, char* buffer) { |
|
|
|
|
|
int routine = ink_make_routine(pContext); |
|
|
|
|
|
int saved = pContext->routine_current; |
|
|
|
|
|
pContext->routine_current = routine; |
|
|
|
|
|
struct ink_routine* currentRoutine = pContext->routines + routine; |
|
|
|
|
|
currentRoutine->stack = NULL; |
|
|
|
|
|
currentRoutine->top = 0; |
|
|
|
|
|
currentRoutine->capacity = 0; |
|
|
int err; |
|
|
int err; |
|
|
err = ink_lex(pContext, buffer); |
|
|
err = ink_lex(pContext, buffer); |
|
|
if(err < 0) { |
|
|
if(err < 0) { |
|
@ -648,7 +733,13 @@ void ink_run(struct context *pContext, char* buffer) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct stack_frame frame; |
|
|
struct stack_frame frame; |
|
|
frame.executing.value = ink_add_indigenous(pContext, "__-MAIN-__", executable_buffer, executable_buffer_top); |
|
|
|
|
|
|
|
|
char main_fn[32] = "__-MAIN-__"; |
|
|
|
|
|
char* integer = ink_itoa(pContext, routine); |
|
|
|
|
|
size_t integer_size = strlen(integer); |
|
|
|
|
|
memcpy(main_fn+10, integer, integer_size); |
|
|
|
|
|
pContext->free(integer); |
|
|
|
|
|
main_fn[10+integer_size] = 0; |
|
|
|
|
|
frame.executing.value = ink_add_indigenous(pContext, main_fn, executable_buffer, executable_buffer_top); |
|
|
if(frame.executing.value < 0) { |
|
|
if(frame.executing.value < 0) { |
|
|
pContext->panic = 1; |
|
|
pContext->panic = 1; |
|
|
return; |
|
|
return; |
|
@ -661,19 +752,49 @@ void ink_run(struct context *pContext, char* buffer) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pContext->routine_current = saved; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ink_can_run(struct context* pContext) { |
|
|
|
|
|
int it = 0; |
|
|
|
|
|
for(;it < pContext->routines_top; ++it) { |
|
|
|
|
|
if(pContext->routines[it].panic == 0) { |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ink_step_everyone(struct context* pContext) { |
|
|
int out; |
|
|
int out; |
|
|
do { |
|
|
|
|
|
|
|
|
pContext->routine_current = -1; |
|
|
|
|
|
for(;;) { |
|
|
|
|
|
do{ |
|
|
|
|
|
++(pContext->routine_current); |
|
|
|
|
|
} while(pContext->routine_current < pContext->routines_top && pContext->routines[pContext->routine_current].panic != 0); |
|
|
|
|
|
if(pContext->routine_current >= pContext->routines_top) break; |
|
|
|
|
|
if(pContext->routines[pContext->routine_current].panic == INK_ROUTINE_SUCCESS) { |
|
|
|
|
|
ink_kill_routine(pContext, pContext->routine_current); |
|
|
|
|
|
} |
|
|
out = ink_step(pContext); |
|
|
out = ink_step(pContext); |
|
|
} while(out > 0); |
|
|
|
|
|
|
|
|
if(out == 0) { |
|
|
|
|
|
pContext->routines[pContext->routine_current].panic = INK_ROUTINE_SUCCESS; |
|
|
|
|
|
} else if(out < 0) { |
|
|
|
|
|
pContext->routines[pContext->routine_current].panic = out; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/**********************************************************************************************************************/ |
|
|
/**********************************************************************************************************************/ |
|
|
|
|
|
|
|
|
static void print_stacktrace(struct context* _) { |
|
|
static void print_stacktrace(struct context* _) { |
|
|
int i = 0; |
|
|
int i = 0; |
|
|
for(; i < _->function_stack_top; ++i) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = _->routines + _->routine_current; |
|
|
|
|
|
for(; i < currentRoutine->function_stack_top; ++i) { |
|
|
struct elem thing; |
|
|
struct elem thing; |
|
|
thing = _->function_stack[i].executing; |
|
|
|
|
|
|
|
|
thing = currentRoutine->function_stack[i].executing; |
|
|
switch(thing.type) { |
|
|
switch(thing.type) { |
|
|
case INK_NATIVE_FUNCTION: { |
|
|
case INK_NATIVE_FUNCTION: { |
|
|
char *n = _->native_words[thing.value].name; |
|
|
char *n = _->native_words[thing.value].name; |
|
@ -691,7 +812,7 @@ static void print_stacktrace(struct context* _) { |
|
|
++n; |
|
|
++n; |
|
|
} |
|
|
} |
|
|
_->putchar(':'); |
|
|
_->putchar(':'); |
|
|
n = ink_itoa(_, _->function_stack[i].index); |
|
|
|
|
|
|
|
|
n = ink_itoa(_, currentRoutine->function_stack[i].index); |
|
|
while (*n) { |
|
|
while (*n) { |
|
|
_->putchar(*n); |
|
|
_->putchar(*n); |
|
|
++n; |
|
|
++n; |
|
@ -707,104 +828,111 @@ static void print_stacktrace(struct context* _) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void add_int(struct context* ctx) { |
|
|
static void add_int(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
ctx->stack[ctx->top-1].value = a.value + b.value; |
|
|
|
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = a.value + b.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void sub_int(struct context* ctx) { |
|
|
static void sub_int(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
ctx->stack[ctx->top-1].value = b.value - a.value; |
|
|
|
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value - a.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void mult_int(struct context* ctx) { |
|
|
static void mult_int(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
ctx->stack[ctx->top-1].value = b.value * a.value; |
|
|
|
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value * a.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void div_int(struct context* ctx) { |
|
|
static void div_int(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
ctx->stack[ctx->top-1].value = b.value / a.value; |
|
|
|
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void rem_int(struct context* ctx) { |
|
|
static void rem_int(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { |
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
ctx->stack[ctx->top-1].value = b.value % a.value; |
|
|
|
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void dupe_elem(struct context* ctx) { |
|
|
static void dupe_elem(struct context* ctx) { |
|
|
if(ctx->top < 1) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
int err; |
|
|
int err; |
|
|
err = ink_push(ctx, a); |
|
|
err = ink_push(ctx, a); |
|
|
if(err < 0) ctx->panic; |
|
|
if(err < 0) ctx->panic; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void drop_elem(struct context* ctx) { |
|
|
static void drop_elem(struct context* ctx) { |
|
|
if(ctx->top < 1) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
@ -812,47 +940,50 @@ static void drop_elem(struct context* ctx) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void pluck_elem(struct context* ctx) { |
|
|
static void pluck_elem(struct context* ctx) { |
|
|
if(ctx->top < 1) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
if(a.type != INK_INTEGER) { |
|
|
if(a.type != INK_INTEGER) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
int position = ctx->top - (a.value + 1); |
|
|
|
|
|
if(position >= ctx->top || position < 0) { |
|
|
|
|
|
|
|
|
int position = currentRoutine->top - (a.value + 1); |
|
|
|
|
|
if(position >= currentRoutine->top || position < 0) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
int err; |
|
|
int err; |
|
|
err = ink_push(ctx, ctx->stack[position]); |
|
|
|
|
|
|
|
|
err = ink_push(ctx, currentRoutine->stack[position]); |
|
|
if(err < 0) ctx->panic; |
|
|
if(err < 0) ctx->panic; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void swap_elem(struct context* ctx) { |
|
|
static void swap_elem(struct context* ctx) { |
|
|
if(ctx->top < 2) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 2) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
struct elem b; |
|
|
struct elem b; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
b = ctx->stack[ctx->top-2]; |
|
|
|
|
|
ctx->stack[ctx->top-2] = a; |
|
|
|
|
|
ctx->stack[ctx->top-1] = b; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
b = currentRoutine->stack[currentRoutine->top-2]; |
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-2] = a; |
|
|
|
|
|
currentRoutine->stack[currentRoutine->top-1] = b; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void return_if(struct context* ctx) { |
|
|
static void return_if(struct context* ctx) { |
|
|
if(ctx->top < 1) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
if(a.type != INK_INTEGER) { |
|
|
if(a.type != INK_INTEGER) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
@ -866,12 +997,13 @@ static void return_if(struct context* ctx) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void jump_if(struct context* ctx) { |
|
|
static void jump_if(struct context* ctx) { |
|
|
if(ctx->top < 1) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
if(a.type != INK_INTEGER) { |
|
|
if(a.type != INK_INTEGER) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
@ -879,21 +1011,21 @@ static void jump_if(struct context* ctx) { |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
if(a.value) { |
|
|
if(a.value) { |
|
|
ink_pop_fn(ctx); |
|
|
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); |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
|
|
|
currentRoutine->function_stack[currentRoutine->function_stack_top - 1].index += a.value - 3; |
|
|
} |
|
|
} |
|
|
|
|
|
ink_pop(ctx); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void print_int(struct context* ctx) { |
|
|
static void print_int(struct context* ctx) { |
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
|
|
ctx->panic = 1; |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) { |
|
|
|
|
|
currentRoutine->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
ink_pop(ctx); |
|
|
ink_pop(ctx); |
|
|
char* n = ink_itoa(ctx, a.value); |
|
|
char* n = ink_itoa(ctx, a.value); |
|
|
char* str = n; |
|
|
char* str = n; |
|
@ -905,12 +1037,13 @@ static void print_int(struct context* ctx) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void print_as_utf8(struct context* ctx) { |
|
|
static void print_as_utf8(struct context* ctx) { |
|
|
if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { |
|
|
|
|
|
|
|
|
struct ink_routine* currentRoutine = ctx->routines + ctx->routine_current; |
|
|
|
|
|
if(currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top-1].type != INK_INTEGER) { |
|
|
ctx->panic = 1; |
|
|
ctx->panic = 1; |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
struct elem a; |
|
|
struct elem a; |
|
|
a = ctx->stack[ctx->top-1]; |
|
|
|
|
|
|
|
|
a = currentRoutine->stack[currentRoutine->top-1]; |
|
|
if(a.value <= 0x7F) { |
|
|
if(a.value <= 0x7F) { |
|
|
ctx->putchar(a.value); |
|
|
ctx->putchar(a.value); |
|
|
} else if(a.value <= 0x7FF) { |
|
|
} else if(a.value <= 0x7FF) { |
|
@ -934,6 +1067,7 @@ static void print_as_utf8(struct context* ctx) { |
|
|
|
|
|
|
|
|
int ink_std_library(struct context* ctx) { |
|
|
int ink_std_library(struct context* ctx) { |
|
|
int v; |
|
|
int v; |
|
|
|
|
|
v = 0; |
|
|
v += ink_add_native(ctx, "trace", print_stacktrace); |
|
|
v += ink_add_native(ctx, "trace", print_stacktrace); |
|
|
v += ink_add_native(ctx, "print_int", print_int); |
|
|
v += ink_add_native(ctx, "print_int", print_int); |
|
|
v += ink_add_native(ctx, "print_utf8", print_as_utf8); |
|
|
v += ink_add_native(ctx, "print_utf8", print_as_utf8); |
|
|