#include #include #include "fh_runtime.h" #include "fh_config.h" #include "fh_error.h" #include "fh_print.h" #include "fh_builtins.h" #include "fh_stack.h" #include "fh_mem.h" #define TOBOOL(a) (a == 0 ? 0 : 0xFFFFFFFF) static enum fh_error w_plus(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(ds_push(fh, a + b)); return FH_OK; } static enum fh_error w_minus(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(ds_push(fh, a - b)); return FH_OK; } static enum fh_error w_star(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(ds_push(fh, a * b)); return FH_OK; } static enum fh_error w_zero_less(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a < 0))); return FH_OK; } static enum fh_error w_zero_greater(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a > 0))); return FH_OK; } static enum fh_error w_zero_equals(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a == 0))); return FH_OK; } static enum fh_error w_zero_not_equals(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a != 0))); return FH_OK; } static enum fh_error w_less(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a < b))); return FH_OK; } static enum fh_error w_greater(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a > b))); return FH_OK; } static enum fh_error w_equals(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a == b))); return FH_OK; } static enum fh_error w_not_equals(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); TRY(ds_push(fh, TOBOOL(a != b))); return FH_OK; } static enum fh_error wp_add(struct fh_thread_s *fh, const struct fh_word_s *w) { enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, a + w->param)); return FH_OK; } static enum fh_error wp_mul(struct fh_thread_s *fh, const struct fh_word_s *w) { enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, a * w->param)); return FH_OK; } static enum fh_error wp_div(struct fh_thread_s *fh, const struct fh_word_s *w) { enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_push(fh, a * w->param)); return FH_OK; } static enum fh_error w_star_slash(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0, c = 0; TRY(ds_pop(fh, &c)); TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); if (c == 0) { return FH_ERR_DIV_BY_ZERO; } uint64_t v = ((uint64_t) a * (uint64_t) b) / (uint64_t) c; TRY(ds_push(fh, (uint32_t) v)); return FH_OK; } static enum fh_error w_slash(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); if (b == 0) { return FH_ERR_DIV_BY_ZERO; } TRY(ds_push(fh, a / b)); return FH_OK; } static enum fh_error w_slash_mod(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0, b = 0; TRY(ds_pop(fh, &b)); TRY(ds_pop(fh, &a)); if (b == 0) { return FH_ERR_DIV_BY_ZERO; } uint32_t rem = a % b; uint32_t div = a / b; TRY(ds_push(fh, rem)); TRY(ds_push(fh, div)); return FH_OK; } static enum fh_error w_colon(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; if (fh->state != FH_STATE_INTERPRET) { return FH_ERR_INVALID_STATE; } fh_setstate(fh, FH_STATE_COMPILE, FH_SUBSTATE_COLONNAME); if (fh->dict_top >= DICT_SIZE) { return FH_ERR_DICT_FULL; } fh->dict[fh->dict_top].start = fh->compile_top; fh->dict[fh->dict_top].handler = w_user_word; return FH_OK; } static enum fh_error w_semicolon(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; struct fh_instruction_s instr; if (fh->state != FH_STATE_COMPILE) { return FH_ERR_INVALID_STATE; } instr.kind = FH_INSTR_WORD; instr.data = CPLWORD_ENDWORD; TRY(fh_compile_put(fh, &instr, INSTR_SIZE)); /* Return to interpret state */ fh_setstate(fh, FH_STATE_INTERPRET, 0); fh->dict_top++; return FH_OK; } static enum fh_error w_dup(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_peek(fh, &a)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_two_dup(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; uint32_t b = 0; TRY(ds_peek_n(fh, &a, 0)); TRY(ds_peek_n(fh, &b, 1)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_drop(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); return FH_OK; } static enum fh_error w_two_drop(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a)); return FH_OK; } static enum fh_error w_swap(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; TRY(ds_roll(fh, 1)); return FH_OK; } static enum fh_error w_two_swap(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; if (fh->data_stack_top < 4) { LOG("DS two-swap UNDERFLOW"); return FH_ERR_DS_UNDERFLOW; } uint32_t n = fh->data_stack_top - 4; uint32_t a = fh->data_stack[n]; uint32_t b = fh->data_stack[n + 1]; fh->data_stack[n] = fh->data_stack[n + 2]; fh->data_stack[n + 1] = fh->data_stack[n + 3]; fh->data_stack[n + 2] = a; fh->data_stack[n + 3] = b; return FH_OK; } static enum fh_error w_rot(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; TRY(ds_roll(fh, 2)); return FH_OK; } static enum fh_error w_over(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_peek_n(fh, &a, 1)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_two_over(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; uint32_t b = 0; TRY(ds_peek_n(fh, &a, 2)); TRY(ds_peek_n(fh, &b, 3)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_tuck(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; uint32_t b = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(ds_push(fh, a)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_pick(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t nth = 0; uint32_t a = 0; TRY(ds_pop(fh, &nth)); TRY(ds_peek_n(fh, &a, nth)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_roll(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t n = 0; TRY(ds_pop(fh, &n)); TRY(ds_roll(fh, n)); return FH_OK; } static enum fh_error w_to_r(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; TRY(ds_pop(fh, &a)); TRY(rs_push(fh, a)); return FH_OK; } static enum fh_error w_two_to_r(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; uint32_t b; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(rs_push(fh, b)); TRY(rs_push(fh, a)); return FH_OK; } static enum fh_error w_two_r_from(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; uint32_t b; TRY(rs_pop(fh, &a)); TRY(rs_pop(fh, &b)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_two_r_fetch(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; uint32_t b; TRY(rs_peek_n(fh, &a, 0)); TRY(rs_peek_n(fh, &b, 1)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_r_from(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; TRY(rs_pop(fh, &a)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_r_fetch(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a; TRY(rs_peek(fh, &a)); TRY(ds_push(fh, a)); return FH_OK; } static enum fh_error w_dot(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t a = 0; TRY(ds_pop(fh, &a)); FHPRINT("%d ", (int32_t) a); return FH_OK; } static enum fh_error w_type(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t count = 0, addr = 0; TRY(ds_pop(fh, &count)); TRY(ds_pop(fh, &addr)); FHPRINT("%.*s", count, &fh->heap[addr]); return FH_OK; } static enum fh_error w_cr(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; (void) fh; FHPRINT("\n"); return FH_OK; } static enum fh_error w_space(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; (void) fh; FHPRINT(" "); return FH_OK; } static enum fh_error w_dump(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; (void) fh; FHPRINT("DS "); for (int i = 0; i < fh->data_stack_top; i++) { FHPRINT("%d ", fh->data_stack[i]); } FHPRINT("\nRS "); for (int i = 0; i < fh->return_stack_top; i++) { FHPRINT("%d ", fh->return_stack[i]); } FHPRINT("\n"); return FH_OK; } static enum fh_error w_abort(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh->data_stack_top = 0; fh->return_stack_top = 0; fh->state = FH_STATE_QUIT; return FH_OK; } static enum fh_error w_quit(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh->return_stack_top = 0; fh->state = FH_STATE_QUIT; return FH_OK; } static enum fh_error w_s_quote(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh_setsubstate(fh, FH_SUBSTATE_SQUOTE); return FH_OK; } static enum fh_error w_dot_quote(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh_setsubstate(fh, FH_SUBSTATE_DOTQUOTE); return FH_OK; } static enum fh_error w_backslash(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh_setsubstate(fh, FH_SUBSTATE_LINECOMMENT); return FH_OK; } static enum fh_error w_paren(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh_setsubstate(fh, FH_SUBSTATE_PARENCOMMENT); return FH_OK; } static enum fh_error w_bye(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; fh_setstate(fh, FH_STATE_SHUTDOWN, 0); return FH_OK; } static enum fh_error wp_setbase(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; fh->base = w->param; return FH_OK; } static enum fh_error w_base(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; TRY(ds_push(fh, MAGICADDR_BASE)); return FH_OK; } static enum fh_error w_fetch(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t addr = 0; TRY(ds_pop(fh, &addr)); uint32_t val = 0; TRY(fh_fetch(fh, addr, &val)); TRY(ds_push(fh, val)); return FH_OK; } static enum fh_error w_store(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t addr = 0; TRY(ds_pop(fh, &addr)); uint32_t val = 0; TRY(ds_pop(fh, &val)); TRY(fh_store(fh, addr, val)); return FH_OK; } static enum fh_error w_two_store(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t addr = 0; TRY(ds_pop(fh, &addr)); uint32_t a = 0, b = 0; TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &b)); TRY(fh_store(fh, addr, a)); TRY(fh_store(fh, addr + CELL, b)); return FH_OK; } static enum fh_error w_two_fetch(struct fh_thread_s *fh, const struct fh_word_s *w) { (void) w; enum fh_error rv; uint32_t addr = 0; TRY(ds_pop(fh, &addr)); uint32_t a = 0, b = 0; TRY(fh_fetch(fh, addr, &a)); TRY(fh_fetch(fh, addr + CELL, &b)); TRY(ds_push(fh, b)); TRY(ds_push(fh, a)); return FH_OK; } /** Add pointers to built-in word handlers to a runtime struct */ enum fh_error register_builtin_words(struct fh_thread_s *fh) { struct name_and_handler { const char *name; word_exec_t handler; bool immediate; uint32_t param; }; const struct name_and_handler builtins[] = { {"s\"", w_s_quote, 1, 0}, {".\"", w_dot_quote, 1, 0}, /* Compiler control words */ {"bye", w_bye, 0, 0}, /* Pointers */ {"@", w_fetch, 0, 0}, {"!", w_store, 0, 0}, {"2!", w_two_store, 0, 0}, {"2@", w_two_fetch, 0, 0}, /* Arithmetics */ {"dec", wp_setbase, 0, 10}, {"hex", wp_setbase, 0, 16}, {"base", w_base, 0, 0}, {"+", w_plus, 0, 0}, {"-", w_minus, 0, 0}, {"*", w_star, 0, 0}, {"*/", w_star_slash, 0, 0}, {"/", w_slash, 0, 0}, {"/mod", w_slash_mod, 0, 0}, {"0<", w_zero_less, 0, 0}, {"0=", w_zero_equals, 0, 0}, {"0<>", w_zero_not_equals, 0, 0}, {"0>", w_zero_greater, 0, 0}, {"<", w_less, 0, 0}, {"=", w_equals, 0, 0}, {"<>", w_not_equals, 0, 0}, {">", w_greater, 0, 0}, {"1+", wp_add, 0, 1}, {"1-", wp_add, 0, -1}, {"2+", wp_add, 0, 2}, {"2-", wp_add, 0, -2}, {"2*", wp_mul, 0, 2}, {"2/", wp_div, 0, 2}, /* Stack manip */ {"drop", w_drop, 0, 0}, {"dup", w_dup, 0, 0}, {"over", w_over, 0, 0}, {"swap", w_swap, 0, 0}, {"rot", w_rot, 0, 0}, {"tuck", w_tuck, 0, 0}, {"pick", w_pick, 0, 0}, {"roll", w_roll, 0, 0}, /* Double wide stack manip */ {"2drop", w_two_drop, 0, 0}, {"2dup", w_two_dup, 0, 0}, {"2over", w_two_over, 0, 0}, {"2swap", w_two_swap, 0, 0}, // /* Return stack manip */ {">r", w_to_r, 0, 0}, {"r>", w_r_from, 0, 0}, {"r@", w_r_fetch, 0, 0}, // /* Double wide return stack manip */ {"2>r", w_two_to_r, 0, 0}, {"2r>", w_two_r_from, 0, 0}, {"2r@", w_two_r_fetch, 0, 0}, /* Printing */ {".", w_dot, 0, 0}, {"type", w_type, 0, 0}, {"cr", w_cr, 0, 0}, {"space", w_space, 0, 0}, {"dump", w_dump, 0, 0}, /* Control flow */ {"abort", w_abort, 0, 0}, {"quit", w_quit, 0, 0}, /* Syntax */ {":", w_colon, 0, 0}, {";", w_semicolon, 1, 0}, {"\\", w_backslash, 1, 0}, // line comment {"(", w_paren, 1, 0}, // enclosed comment { /* end marker */ } }; // foreach struct fh_word_s w; const struct name_and_handler *p = builtins; enum fh_error rv; while (p->handler) { strcpy(w.name, p->name); w.handler = p->handler; w.builtin = 1; w.immediate = p->immediate; w.param = p->param; rv = fh_add_word(&w, fh); if (rv != FH_OK) { return rv; } p++; } return FH_OK; }