#include "sloth.h" #include #include #include #include #include SlothError sloth_init(Sloth *ctx) { SlothError err; err = sloth_dict_append(ctx, SLOTH_DICT_C("+", sloth_add)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C(".", sloth_write)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C("@", sloth_store)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C("!", sloth_retrieve)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C("<", sloth_compare)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C("neg", sloth_neg)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C(":", sloth_compile_begin)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_I(";", sloth_compile_end)); if (err != NULL) { sloth_deinit(ctx); return err; } err = sloth_dict_append(ctx, SLOTH_DICT_C(".t", sloth_inspect_stack)); if (err != NULL) { sloth_deinit(ctx); return err; } return NULL; } void sloth_deinit(Sloth *ctx) { if (ctx->stack != NULL) { free(ctx->stack); ctx->stack = NULL; } while (ctx->dict != NULL) { SlothDict *const next = ctx->dict->next; if (ctx->dict->instrs != NULL) { SlothInstr *const next_instr = ctx->dict->instrs->next; free(ctx->dict->instrs); ctx->dict->instrs = next_instr; } free(ctx->dict); ctx->dict = next; } if (ctx->comp.instrs != NULL) { SlothInstr *const next_instr = ctx->comp.instrs->next; free(ctx->comp.instrs); ctx->comp.instrs = next_instr; } } SlothError sloth_dict_append(Sloth *ctx, SlothDict dict) { SlothDict **dest; if (ctx->dict == NULL) dest = &ctx->dict; else { SlothDict *last = ctx->dict; while (last->next != NULL) last = last->next; dest = &last->next; } *dest = malloc(sizeof(SlothDict)); if (*dest == NULL) return "sloth_dict_append: malloc failed"; memcpy(*dest, &dict, sizeof(SlothDict)); return NULL; } SlothError sloth_str_to_instr(Sloth *ctx, const char *s, SlothInstr *instr) { const SlothHash hash = XXH32(s, strlen(s), 0); instr->next = NULL; for (SlothDict *dict = ctx->dict; dict != NULL; dict = dict->next) if (dict->hash == hash) { instr->litteral = 0; instr->hash = hash; return NULL; } for (size_t i = 0; s[i] != '\0'; i++) if (!isdigit(s[i])) return "sloth_str_to_instr: unrecognized token"; instr->litteral = 1; instr->byte = atoi(s); return NULL; } SlothError sloth_exec_instr(Sloth *ctx, const SlothInstr *instr) { SlothError err = NULL; while (instr != NULL) { if (instr->litteral) err = sloth_push(ctx, instr->byte); else for (SlothDict *dict = ctx->dict; dict != NULL; dict = dict->next) { if (dict->hash == instr->hash) { if (dict->c_func) err = dict->func(ctx); else err = sloth_exec_instr(ctx, dict->instrs); break; } } if (err != NULL) return err; instr = instr->next; } return NULL; } SlothError sloth_exec(Sloth *ctx, const char *s) { SlothError err; SlothInstr instr = {0}; err = sloth_str_to_instr(ctx, s, &instr); if (err != NULL) return err; err = sloth_exec_instr(ctx, &instr); if (err != NULL) return err; return NULL; } SlothError sloth_compile(Sloth *ctx, const char *s) { SlothError err; if (ctx->comp.hash == 0) { ctx->comp.hash = XXH32(s, strlen(s), 0); return NULL; } SlothInstr instr = {0}; err = sloth_str_to_instr(ctx, s, &instr); if (err != NULL) return err; SlothInstr **dest; if (ctx->comp.instrs == NULL) dest = &ctx->comp.instrs; else { SlothInstr *last = ctx->comp.instrs; while (last->next != NULL) last = last->next; dest = &last->next; } *dest = malloc(sizeof(SlothInstr)); if (*dest == NULL) return "sloth_compile: malloc failed"; memcpy(*dest, &instr, sizeof(SlothInstr)); return NULL; } static int sloth_is_immediate(Sloth *ctx, const char *s) { const SlothHash hash = XXH32(s, strlen(s), 0); for (SlothDict *dict = ctx->dict; dict != NULL; dict = dict->next) if (dict->hash == hash) return dict->immediate; return 0; } SlothError sloth_exec_line(Sloth *ctx, char *s) { SlothError err = NULL; static const char *sep = "\t\n\v\f\r "; for (char *tok = strtok(s, sep); tok != NULL; tok = strtok(NULL, sep)) { if (ctx->compile && sloth_is_immediate(ctx, tok)) err = sloth_compile(ctx, tok); else err = sloth_exec(ctx, tok); if (err != NULL) return err; } return NULL; } SlothError sloth_pop(Sloth *ctx, SlothByte *v) { if (ctx->stack_size == 0) return "sloth_pull: stack is empty"; *v = ctx->stack[ctx->stack_size - 1]; ctx->stack_size -= 1; return NULL; } SlothError sloth_push(Sloth *ctx, SlothByte v) { if (ctx->stack == NULL) { ctx->stack = malloc(sizeof(SlothByte) * 16); if (ctx->stack == NULL) return "sloth_push: calloc failed"; ctx->stack_capacity = 16; } else if (ctx->stack_size == ctx->stack_capacity) { SlothByte *const new_stack = realloc(ctx->stack, ctx->stack_capacity * 2); if (new_stack == NULL) return "sloth_push: realloc failed"; ctx->stack_capacity *= 2; } ctx->stack[ctx->stack_size] = v; ctx->stack_size += 1; return NULL; } SlothError sloth_add(Sloth *ctx) { SlothError err; SlothByte a, b; err = sloth_pop(ctx, &a); if (err != NULL) return err; err = sloth_pop(ctx, &b); if (err != NULL) return err; a += b; err = sloth_push(ctx, a); if (err != NULL) return err; return NULL; } SlothError sloth_write(Sloth *ctx) { SlothError err; SlothByte a; err = sloth_pop(ctx, &a); if (err != NULL) return err; printf("%c", (unsigned char)a); return NULL; } SlothError sloth_store(Sloth *ctx) { SlothError err; SlothByte a, b; err = sloth_pop(ctx, &a); if (err != NULL) return err; err = sloth_pop(ctx, &b); if (err != NULL) return err; ctx->mem[a] = b; return NULL; } SlothError sloth_retrieve(Sloth *ctx) { SlothError err; SlothByte a; err = sloth_pop(ctx, &a); if (err != NULL) return err; err = sloth_push(ctx, ctx->mem[a]); if (err != NULL) return err; return NULL; } SlothError sloth_compare(Sloth *ctx) { SlothError err; SlothByte a, b; err = sloth_pop(ctx, &a); if (err != NULL) return err; err = sloth_pop(ctx, &b); if (err != NULL) return err; err = sloth_push(ctx, b < a); if (err != NULL) return err; return NULL; } SlothError sloth_neg(Sloth *ctx) { SlothError err; SlothByte a; err = sloth_pop(ctx, &a); if (err != NULL) return err; err = sloth_push(ctx, -a); if (err != NULL) return err; return NULL; } SlothError sloth_compile_begin(Sloth *ctx) { if (ctx->compile) return "sloth_compile_begin: already in compile mode"; ctx->comp.hash = 0; ctx->comp.c_func = 0; ctx->comp.func = NULL; ctx->comp.instrs = NULL; ctx->comp.next = NULL; ctx->compile = 1; return NULL; } SlothError sloth_compile_end(Sloth *ctx) { if (!ctx->compile) return "sloth_compile_end: not in compile mode"; if (ctx->comp.hash == 0) return "sloth_compile_end: compiled instruction missing hash"; const SlothError err = sloth_dict_append(ctx, ctx->comp); if (err != NULL) return NULL; ctx->comp.hash = 0; ctx->comp.instrs = NULL; ctx->compile = 0; return NULL; } SlothError sloth_inspect_stack(Sloth *ctx) { printf("<%lu> ", ctx->stack_size); for (size_t i = 0; i < ctx->stack_size; i++) printf("%d ", ctx->stack[i]); return NULL; }