| 
				
				
				
				 | 
			
			 | 
			
			@ -0,0 +1,549 @@ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <stdio.h> | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <stdlib.h> | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <string.h> | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include <ctype.h> | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#include "ink.h" | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_RESERVED (-1) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_FUNCTION_KW (-2) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_DO_KW (-3) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_END_KW (-4) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_LABEL (-5) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define INK_RETURN (-6) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define _KEYWORD_INK_FUNCTION "fn" | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define _KEYWORD_INK_DO "do" | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#define _KEYWORD_INK_END "end" | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			struct label { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int active; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int dest; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				char* name; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			}; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->native_words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->native_words_capacity = 8; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} else if(ctx->native_words_top == ctx->native_words_capacity) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					int new_count = (ctx->native_words_capacity + ctx->native_words_capacity/2); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					void* renewed = ctx->realloc(ctx->native_words, sizeof(struct native_fn) * new_count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->native_words = renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->native_words_capacity = new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int len = strlen(name); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				char* copy = ctx->malloc(len+1); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(copy == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				memcpy(copy, name, len); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				copy[len] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->native_words[ctx->native_words_top].value = value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->native_words[ctx->native_words_top].name = copy; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->native_words_top++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static int ink_add_indigenous(struct context* ctx, const char* name, struct elem* m, size_t count) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->words == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->words = ctx->malloc(sizeof(struct fn) * 8); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->words_capacity = 8; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} else if(ctx->words_top == ctx->words_capacity) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					int new_count = (ctx->words_capacity + ctx->words_capacity/2); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					void* renewed = ctx->realloc(ctx->words, sizeof(struct native_fn) * new_count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->words = renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->words_capacity = new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						memcpy(ctx->words[i].things, m, sizeof(struct elem) * count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->words[i].size = count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						return i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int len = strlen(name); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				char* copy = ctx->malloc(len+1); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(copy == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				memcpy(copy, name, len); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				copy[len] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->words[ctx->words_top].things = 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; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return ctx->words_top++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static int ink_add_lex_string(struct context* ctx, const char* name) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->lex_reserved_words == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->lex_reserved_words = ctx->malloc(sizeof(char*) * 8); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->lex_reserved_words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->lex_reserved_words_capacity = 8; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} else if(ctx->lex_reserved_words_top == ctx->lex_reserved_words_capacity) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					int new_count = (ctx->lex_reserved_words_capacity + ctx->lex_reserved_words_capacity/2); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					void* renewed = ctx->realloc(ctx->lex_reserved_words, sizeof(struct native_fn) * new_count); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->lex_reserved_words = renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->lex_reserved_words_capacity = new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				for(i = 0; i < ctx->lex_reserved_words_top; i++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(strcmp(ctx->lex_reserved_words[i], name) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						return i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int len = strlen(name); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				i = ctx->lex_reserved_words_top; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words[i] = malloc(len+1); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				memcpy(ctx->lex_reserved_words[i], name, len); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words[i][len] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words_top++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void 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(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->stack = renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->capacity = new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->stack[ctx->top] = value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->top++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void 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(renewed == NULL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->function_stack = renewed; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ctx->function_stack_capacity = new_count; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->function_stack[ctx->function_stack_top] = value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->function_stack_top++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			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--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void ink_pop(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->stack == NULL) return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->top == 0) return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->top--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			struct context* ink_make_context(void*(*malloc)(size_t), void*(*realloc)(void*, size_t), void(*free)(void*)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct context* ctx = (struct context*)malloc(sizeof(struct context)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->malloc = malloc; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->realloc = realloc; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->free = free; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				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->native_words = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->native_words_capacity = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->native_words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->words = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->words_capacity = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words_capacity = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->lex_reserved_words_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return ctx; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						case INK_FUNCTION: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							printf("%s:%d\n", _->words[thing.value].name, _->function_stack[i].index); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						default: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void add_int(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]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ctx->stack[ctx->top-1].value = a.value + b.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void print_int(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a =  ctx->stack[ctx->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				printf("%d", a.value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void print_as_utf8(struct context* ctx) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(ctx->top < 1 || ctx->stack[ctx->top-1].type != INK_INTEGER) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem a =  ctx->stack[ctx->top-1]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(a.value <= 0x7F) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					putc(a.value, stdout); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} else if(a.value <= 0x7FF) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					putc(((a.value & 0xFC0) >> 6) | 192, stdout); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					putc((a.value  & 0x3F) | 128, stdout); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} 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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} 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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ctx->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_pop(ctx); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			struct context* ink_make_default_context() { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct context* ctx = ink_make_context(malloc, realloc, free); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return ctx; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void ink_consume_one(int* end, struct context* pContext, char** buffer, char* r) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(*end == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					return; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				r[*end] = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int done = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (strcmp(r, _KEYWORD_INK_FUNCTION) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.value = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.type = INK_FUNCTION_KW; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (!done && strcmp(r, _KEYWORD_INK_DO) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.value = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.type = INK_DO_KW; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (!done && strcmp(r, _KEYWORD_INK_END) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.value = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.type = INK_END_KW; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (!done) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					for (i = 0; i < pContext->words_top; ++i) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if (strcmp(r, pContext->words[i].name) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							value.value = i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							value.type = INK_FUNCTION; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (!done) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					for (i = 0; i < pContext->native_words_top; ++i) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if (strcmp(r, pContext->native_words[i].name) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							value.value = i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							value.type = INK_NATIVE_FUNCTION; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if (!done) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					for(i = (r[0] == '-'); i < *end; i++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if(!isdigit(r[i])){ | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							goto not_an_int; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.value = atoi(r); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.type = INK_INTEGER; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					done = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				not_an_int: if (!done) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					i = ink_add_lex_string(pContext, r); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					value.value = i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(r[strlen(r) - 1] == ':') { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						value.type = INK_LABEL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						value.type = INK_RESERVED; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					ink_push(pContext, value); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				*end = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static void ink_lex(struct context *pContext, char* buffer) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				char r[128]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int end = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				while(*buffer != 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(isspace(*buffer)) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ink_consume_one(&end, pContext, &buffer, r); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						r[end] = *buffer; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						++end; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					++buffer; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_consume_one(&end, pContext, &buffer, r); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			static int lblcmp(const char* label, const char* other, size_t label_sz) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				while (label_sz != 1) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(*other == 0) return 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					if(*label != *other) return 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					++label; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					++other; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					label_sz--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			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]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				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); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				for(i = 0; i < pContext->top; ++i) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					struct elem current = pContext->stack[i]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					switch (mode) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						case MODE_EXECUTABLE: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							switch(current.type) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								case INK_FUNCTION_KW: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									mode = MODE_FUNCTION; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									goto next_token; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								case INK_DO_KW: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								case INK_END_KW: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								default: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									executable_buffer[*executable_buffer_top] = current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									*executable_buffer_top += 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						case MODE_FUNCTION: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							if(current.type == INK_DO_KW) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								if(function_name == -1) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									// TODO: error (function name was not supplied) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									mode = MODE_DO; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									memset(labels, 0, sizeof(struct label)*128); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									goto next_token; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							if(function_name != -1) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								// TODO: error (function name supplied already) | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							if(current.type != INK_RESERVED) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							function_name = current.value; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						case MODE_DO: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							if(current.type == INK_END_KW) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								int j; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								for(j = 0; j < function_buffer_top; j++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									struct elem pt =  function_buffer[j]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									if(pt.type == INK_LABEL) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										int k; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										for(k = 0; k < 128; k++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											if(labels[k].active) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												if(strcmp(labels[k].name, pContext->lex_reserved_words[pt.value]) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													labels[k].dest = j; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													// TODO: error | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												labels[k].active = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												labels[k].name = pContext->lex_reserved_words[pt.value]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												labels[k].dest = j; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												memcpy(function_buffer+j, function_buffer+j+1, sizeof(struct elem)*(function_buffer_top-j-1)); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												function_buffer_top--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												j--; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								for(j = 0; j < function_buffer_top; j++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									struct elem pt =  function_buffer[j]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									if(pt.type == INK_RESERVED) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										const char* str = pContext->lex_reserved_words[pt.value]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										int k; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										for(k = 0; k < 128; k++) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											if(labels[k].active) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												const char* lbl = labels[k].name; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												int label_sz = strlen(lbl); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												if(lblcmp(labels[k].name, pContext->lex_reserved_words[pt.value], label_sz) == 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													function_buffer[j].type = INK_INTEGER; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													function_buffer[j].value = labels[k].dest - j; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
													break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
												} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
											} else break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
										} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
									} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								ink_add_indigenous(pContext, pContext->lex_reserved_words[function_name], function_buffer, function_buffer_top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								function_buffer_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								mode = MODE_EXECUTABLE; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								goto next_token; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							function_buffer[function_buffer_top] = current; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							function_buffer_top += 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					next_token: i=i; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				if(mode == MODE_FUNCTION || mode == MODE_DO) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					// error, missing an end | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#undef MODE_EXECUTABLE | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#undef MODE_FUNCTION | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			#undef MODE_DO | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			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]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				switch(top->executing.type) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					case INK_NATIVE_FUNCTION: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if(top->index != 0) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							ink_pop_fn(pContext); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							top->index++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							if(pContext->native_words_top <= top->executing.value) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								pContext->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
								return -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							pContext->native_words[top->executing.value].value(pContext); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					case INK_FUNCTION: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if(pContext->words_top <= top->executing.value) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							pContext->panic = 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							return -1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						if(top->index >= pContext->words[top->executing.value].size) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							ink_pop_fn(pContext); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} else { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							struct stack_frame frame; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							frame.executing = pContext->words[top->executing.value].things[top->index]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							frame.index = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							ink_push_fn(pContext, frame); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
							top->index++; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					default: | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ink_push(pContext, top->executing); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						ink_pop_fn(pContext); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
						break; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				return 1; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			
 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			void ink_run(struct context *pContext, char* buffer) { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				pContext->free(pContext->stack); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				pContext->stack = NULL; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				pContext->top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				pContext->capacity = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_lex(pContext, buffer); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int i = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct elem executable_buffer[256]; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int executable_buffer_top = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_parse(pContext, executable_buffer, &executable_buffer_top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				struct stack_frame frame; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				frame.executing.value = ink_add_indigenous(pContext, "__-MAIN-__", executable_buffer, executable_buffer_top); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				frame.executing.type = INK_FUNCTION; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				frame.index = 0; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				ink_push_fn(pContext, frame); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				 | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				int out; | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				do { | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
					out = ink_step(pContext); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
				} while(out > 0); | 
			
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
			} |