#include "fh_error.h" #include "fh_runtime.h" #include "fh_mem.h" #include "fh_stack.h" #include "fh_print.h" #include "fh_builtins.h" static enum fh_error wp_setbase(struct fh_thread_s *fh, const struct fh_word_s *w) { fh_setbase(fh, w->param); return FH_OK; } enum fh_error wp_const(struct fh_thread_s *fh, const struct fh_word_s *w) { enum fh_error rv; TRY(ds_push(fh, w->param)); return FH_OK; } 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, &b)); TRY(ds_pop(fh, &a)); 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_and(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_or(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_xor(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((int32_t) 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((int32_t) a < (int32_t) 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((int32_t) a > (int32_t) b))); return FH_OK; } static enum fh_error w_u_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_u_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; } 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; } 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_star_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, 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 product = ((uint64_t) a * (uint64_t) b); uint64_t v = product / (uint64_t) c; uint64_t m = product % (uint64_t) c; TRY(ds_push(fh, (uint32_t) m)); 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_abs(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)); int32_t sa = (int32_t) a; // TODO is this right? if (sa < 0) { sa = -sa; } TRY(ds_push(fh, sa)); return FH_OK; } static enum fh_error w_invert(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, ~a)); return FH_OK; } static enum fh_error w_negate(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, (uint32_t) (-(uint32_t) a))); 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; } const struct name_and_handler fh_builtins_arith[] = { /* Arithmetics */ {"base", wp_const, 0, MAGICADDR_BASE}, {"decimal", wp_setbase, 0, 10}, {"hex", wp_setbase, 0, 16}, {"false", wp_const, 0, 0}, {"true", wp_const, 0, 0xFFFFFFFF}, {"+", w_plus, 0, 0}, {"-", w_minus, 0, 0}, {"*", w_star, 0, 0}, {"*/", w_star_slash, 0, 0}, {"*/mod", w_star_slash_mod, 0, 0}, {"or", w_or, 0, 0}, {"and", w_and, 0, 0}, {"xor", w_xor, 0, 0}, {"/", w_slash, 0, 0}, {"abs", w_abs, 0, 0}, {"/mod", w_slash_mod, 0, 0}, {"invert", w_invert, 0, 0}, {"negate", w_negate, 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}, {"u<", w_u_less, 0, 0}, {"=", w_equals, 0, 0}, {"<>", w_not_equals, 0, 0}, {">", w_greater, 0, 0}, {"u>", w_u_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}, { /* end marker */ } };