parent
f74d157a7c
commit
ef2e6943bd
@ -0,0 +1,6 @@ |
|||||||
|
|
||||||
|
: test 10 0 DO I . I 5 = IF LEAVE THEN LOOP ; |
||||||
|
|
||||||
|
see test |
||||||
|
|
||||||
|
test |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,346 @@ |
|||||||
|
#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(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; |
||||||
|
} |
||||||
|
|
||||||
|
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}, |
||||||
|
{"=", 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}, |
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,236 @@ |
|||||||
|
#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 w_recurse(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_WORD, fh->dict_last)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static enum fh_error w_if(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
TRY(cs_push(fh, fh->here)); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMPZERO, MAGICADDR_UNRESOLVED)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_else(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t ifaddr = 0; |
||||||
|
TRY(cs_pop(fh, &ifaddr)); |
||||||
|
struct fh_instruction_s *if_instr = fh_instr_at(fh, ifaddr); |
||||||
|
if (if_instr->data != MAGICADDR_UNRESOLVED) { |
||||||
|
LOGE("IF-ELSE control stack corruption"); |
||||||
|
return FH_ERR_INTERNAL; |
||||||
|
} |
||||||
|
|
||||||
|
if_instr->data = fh->here + INSTR_SIZE; |
||||||
|
|
||||||
|
TRY(cs_push(fh, fh->here)); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMP, MAGICADDR_UNRESOLVED)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_then(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t ifaddr = 0; |
||||||
|
TRY(cs_pop(fh, &ifaddr)); |
||||||
|
struct fh_instruction_s *if_instr = fh_instr_at(fh, ifaddr); |
||||||
|
if (if_instr->data != MAGICADDR_UNRESOLVED) { |
||||||
|
LOGE("IF-ELSE control stack corruption"); |
||||||
|
return FH_ERR_INTERNAL; |
||||||
|
} |
||||||
|
|
||||||
|
if_instr->data = fh->here; |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_until(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t destaddr = 0; |
||||||
|
TRY(cs_pop(fh, &destaddr)); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMPZERO, destaddr)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_begin(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
TRY(cs_push(fh, fh->here)); /* dest */ |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error wp_do(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, w->param ? FH_INSTR_DO_QUESTION : FH_INSTR_DO, MAGICADDR_UNRESOLVED)); |
||||||
|
// R will now contain: limit,index
|
||||||
|
|
||||||
|
TRY(cs_push(fh, fh->here)); // mark the start position (after init)
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error wp_loop(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
struct fh_instruction_s *ii; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t loopendaddr = fh->here; |
||||||
|
|
||||||
|
uint32_t startaddr; |
||||||
|
TRY(cs_pop(fh, &startaddr)); |
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, w->param ? FH_INSTR_LOOP_PLUS : FH_INSTR_LOOP, startaddr)); |
||||||
|
|
||||||
|
// after the end LOOP
|
||||||
|
uint32_t endaddr = fh->here; |
||||||
|
|
||||||
|
// resolve ?DO dest
|
||||||
|
ii = fh_instr_at(fh, startaddr - INSTR_SIZE); |
||||||
|
if (ii->kind == FH_INSTR_DO_QUESTION && ii->data == MAGICADDR_UNRESOLVED) { |
||||||
|
ii->data = endaddr; |
||||||
|
} |
||||||
|
|
||||||
|
while (startaddr < loopendaddr) { |
||||||
|
ii = fh_instr_at(fh, startaddr); |
||||||
|
if (ii->kind == FH_INSTR_LEAVE && ii->data == MAGICADDR_UNRESOLVED) { |
||||||
|
LOG("Resolve leave addr"); |
||||||
|
ii->data = endaddr; |
||||||
|
} |
||||||
|
|
||||||
|
// forward, skipping strings safely
|
||||||
|
if (ii->kind == FH_INSTR_TYPESTR || ii->kind == FH_INSTR_ALLOCSTR) { |
||||||
|
startaddr += INSTR_SIZE + ii->data; |
||||||
|
startaddr = WORDALIGNED(startaddr); |
||||||
|
} else { |
||||||
|
startaddr += INSTR_SIZE; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_leave(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_LEAVE, MAGICADDR_UNRESOLVED)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_while(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t destaddr = 0; |
||||||
|
TRY(cs_pop(fh, &destaddr)); |
||||||
|
|
||||||
|
TRY(cs_push(fh, fh->here)); // orig
|
||||||
|
TRY(cs_push(fh, destaddr)); // dest
|
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMPZERO, MAGICADDR_UNRESOLVED)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_repeat(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t origaddr = 0; |
||||||
|
uint32_t destaddr = 0; |
||||||
|
TRY(cs_pop(fh, &destaddr)); |
||||||
|
TRY(cs_pop(fh, &origaddr)); |
||||||
|
|
||||||
|
struct fh_instruction_s *branch_instr = fh_instr_at(fh, origaddr); |
||||||
|
if (branch_instr->data != MAGICADDR_UNRESOLVED) { |
||||||
|
LOGE("REPEAT control stack corruption"); |
||||||
|
return FH_ERR_INTERNAL; |
||||||
|
} |
||||||
|
branch_instr->data = fh->here + INSTR_SIZE; |
||||||
|
|
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMP, destaddr)); |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_again(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t destaddr = 0; |
||||||
|
TRY(cs_pop(fh, &destaddr)); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_JUMP, destaddr)); |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error wp_ij(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
enum fh_error rv; |
||||||
|
TRY(ds_push(fh, w->param ? fh->loop_j : fh->loop_i)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_control[] = { |
||||||
|
{"i", wp_ij, 0, 0}, |
||||||
|
{"j", wp_ij, 0, 1}, |
||||||
|
{"if", w_if, 1, 0}, |
||||||
|
{"else", w_else, 1, 0}, |
||||||
|
{"then", w_then, 1, 0}, |
||||||
|
{"recurse", w_recurse, 1, 0}, |
||||||
|
{"do", wp_do, 1, 0}, |
||||||
|
{"?do", wp_do, 1, 1}, |
||||||
|
{"loop", wp_loop, 1, 0}, |
||||||
|
{"leave", w_leave, 1, 0}, |
||||||
|
{"loop+", wp_loop, 1, 1}, |
||||||
|
{"begin", w_begin, 1, 0}, |
||||||
|
{"while", w_while, 1, 0}, |
||||||
|
{"repeat", w_repeat, 1, 0}, |
||||||
|
{"again", w_again, 1, 0}, |
||||||
|
{"until", w_until, 1, 0}, |
||||||
|
|
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,137 @@ |
|||||||
|
#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 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; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_aligned(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)); |
||||||
|
TRY(ds_push(fh, WORDALIGNED(addr))); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_allot(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
uint32_t count = 0; |
||||||
|
TRY(ds_pop(fh, &count)); |
||||||
|
TRY(fh_heap_reserve(fh, count, NULL)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_comma(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
if (fh->here & 3) { |
||||||
|
LOGE("HERE not aligned before 'comma'"); |
||||||
|
return FH_ERR_ILLEGAL_STORE; |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t value = 0; |
||||||
|
TRY(ds_pop(fh, &value)); |
||||||
|
TRY(fh_heap_put(fh, &value, CELL)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_align(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
fh->here = WORDALIGNED(fh->here); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_pad(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
uint32_t addr = fh->here + PAD_OFFSET; |
||||||
|
if (addr + 84 >= HEAP_END) { |
||||||
|
LOGE("Heap overflow, PAD is too small!"); |
||||||
|
return FH_ERR_HEAP_FULL; |
||||||
|
} |
||||||
|
|
||||||
|
TRY(ds_push(fh, addr)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_mem[] = { |
||||||
|
{"chars", wp_mul, 0, 1}, |
||||||
|
{"char+", wp_add, 0, 1}, |
||||||
|
{"cells", wp_mul, 0, CELL}, |
||||||
|
{"cell+", wp_add, 0, CELL}, |
||||||
|
{"@", w_fetch, 0, 0}, |
||||||
|
{"!", w_store, 0, 0}, |
||||||
|
{"2!", w_two_store, 0, 0}, |
||||||
|
{"2@", w_two_fetch, 0, 0}, |
||||||
|
{"aligned", w_aligned, 0, 0}, |
||||||
|
{"allot", w_allot, 0, 0}, |
||||||
|
{"align", w_align, 0, 0}, |
||||||
|
{",", w_comma, 0, 0}, |
||||||
|
{"here", wp_const, 0, MAGICADDR_HERE}, |
||||||
|
{"pad", w_pad, 0, 0}, |
||||||
|
|
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,177 @@ |
|||||||
|
#include <string.h> |
||||||
|
#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 w_colon(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_INTERPRET); |
||||||
|
|
||||||
|
char *wordname = NULL; |
||||||
|
size_t namelen = 0; |
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
TRY(fh_input_read_word(fh, &wordname, &namelen)); |
||||||
|
LOG("Name: %.*s", namelen, wordname); |
||||||
|
|
||||||
|
fh_setstate(fh, FH_STATE_COMPILE, 0); |
||||||
|
|
||||||
|
uint32_t ptr; |
||||||
|
TRY(fh_heap_reserve(fh, DICTWORD_SIZE, &ptr)); |
||||||
|
|
||||||
|
struct fh_word_s *new_word = fh_word_at(fh, ptr); |
||||||
|
new_word->previous = fh->dict_last; |
||||||
|
new_word->param = fh->here; |
||||||
|
new_word->handler = w_user_word; |
||||||
|
strncpy(new_word->name, wordname, namelen); |
||||||
|
new_word->name[namelen] = 0; |
||||||
|
new_word->flags = WORDFLAG_WORD; |
||||||
|
|
||||||
|
fh->dict_last = ptr; |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_forget(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_INTERPRET); |
||||||
|
|
||||||
|
char *wordname = NULL; |
||||||
|
size_t namelen = 0; |
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
TRY(fh_input_read_word(fh, &wordname, &namelen)); |
||||||
|
LOG("Name to forget: %.*s", namelen, wordname); |
||||||
|
|
||||||
|
uint32_t addr; |
||||||
|
TRY(fh_find_word(fh, wordname, namelen, &addr)); |
||||||
|
|
||||||
|
struct fh_word_s *removedword = fh_word_at(fh, addr); |
||||||
|
fh->dict_last = removedword->previous; |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_postpone(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
char *wordname; |
||||||
|
size_t namelen = 0; |
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
TRY(fh_input_read_word(fh, &wordname, &namelen)); |
||||||
|
TRY(fh_postpone_word(fh, wordname, namelen)); |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_leftbracket(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
fh_setstate(fh, FH_STATE_INTERPRET, 0); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_rightbracket(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
ENSURE_STATE(FH_STATE_INTERPRET); |
||||||
|
fh_setstate(fh, FH_STATE_COMPILE, 0); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_literal(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
|
||||||
|
uint32_t val; |
||||||
|
TRY(ds_pop(fh, &val)); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_NUMBER, val)); |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_semicolon(struct fh_thread_s *fh, const struct fh_word_s *w0) |
||||||
|
{ |
||||||
|
(void) w0; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
ENSURE_STATE(FH_STATE_COMPILE); |
||||||
|
TRY(fh_put_instr(fh, FH_INSTR_ENDWORD, 0)); |
||||||
|
|
||||||
|
/* Return to interpret state */ |
||||||
|
fh_setstate(fh, FH_STATE_INTERPRET, 0); |
||||||
|
|
||||||
|
// XXX if there was another definition previously and it was used in some other compiled function,
|
||||||
|
// that old implementation will still be called.
|
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_immediate(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
if (fh->dict_last == 0) { |
||||||
|
LOGE("Dict is empty, cannot modify previous word!"); |
||||||
|
return FH_ERR_INVALID_STATE; |
||||||
|
} |
||||||
|
|
||||||
|
fh_word_at(fh, fh->dict_last)->flags |= WORDFLAG_IMMEDIATE; |
||||||
|
|
||||||
|
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_LINE_COMMENT); |
||||||
|
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_PAREN_COMMENT); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_char(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
char *wordname = NULL; |
||||||
|
size_t namelen = 0; |
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
TRY(fh_input_read_word(fh, &wordname, &namelen)); |
||||||
|
TRY(ds_push(fh, (char) *wordname)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_meta[] = { |
||||||
|
{":", w_colon, 0, 0}, |
||||||
|
{";", w_semicolon, 1, 0}, |
||||||
|
{"forget", w_forget, 1, 0}, |
||||||
|
{"\\", w_backslash, 1, 0}, // line comment
|
||||||
|
{"(", w_paren, 1, 0}, // enclosed comment
|
||||||
|
{"immediate", w_immediate, 0, 0}, |
||||||
|
{"postpone", w_postpone, 1, 0}, |
||||||
|
{"[", w_leftbracket, 1, 0}, |
||||||
|
{"]", w_rightbracket, 1, 0}, |
||||||
|
{"literal", w_literal, 1, 0}, |
||||||
|
{"char", w_char, 0, 0}, |
||||||
|
{"[char]", w_char, 1, 0}, |
||||||
|
|
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,260 @@ |
|||||||
|
#include "fh_error.h" |
||||||
|
#include "fh_runtime.h" |
||||||
|
#include "fh_stack.h" |
||||||
|
#include "fh_builtins.h" |
||||||
|
|
||||||
|
static enum fh_error w_dupe(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_nip(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
uint32_t a = 0, discard = 0; |
||||||
|
TRY(ds_pop(fh, &a)); |
||||||
|
TRY(ds_pop(fh, &discard)); |
||||||
|
TRY(ds_push(fh, a)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_question_dupe(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)); |
||||||
|
if (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; |
||||||
|
|
||||||
|
uint32_t a, b, c, d; |
||||||
|
TRY(ds_pop(fh, &a)); |
||||||
|
TRY(ds_pop(fh, &b)); |
||||||
|
TRY(ds_pop(fh, &c)); |
||||||
|
TRY(ds_pop(fh, &d)); |
||||||
|
|
||||||
|
TRY(ds_push(fh, b)); |
||||||
|
TRY(ds_push(fh, a)); |
||||||
|
TRY(ds_push(fh, d)); |
||||||
|
TRY(ds_push(fh, c)); |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_stack[] = { |
||||||
|
/* Stack manip */ |
||||||
|
{"drop", w_drop, 0, 0}, |
||||||
|
{"dup", w_dupe, 0, 0}, |
||||||
|
{"?dup", w_question_dupe, 0, 0}, |
||||||
|
{"nip", w_nip, 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}, |
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,51 @@ |
|||||||
|
#include "forth.h" |
||||||
|
#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 w_depth(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
TRY(ds_push(fh, fh->data_stack_top)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_unused(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
TRY(ds_push(fh, HEAP_SIZE - fh->here)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
// extension
|
||||||
|
static enum fh_error w_reset(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
|
||||||
|
ENSURE_STATE(FH_STATE_INTERPRET); |
||||||
|
|
||||||
|
fh_init(fh); |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_system[] = { |
||||||
|
{"depth", w_depth, 0, 0}, |
||||||
|
{"unused", w_unused, 0, 0}, |
||||||
|
{"reset", w_reset, 1, 0}, |
||||||
|
{"bye", w_bye, 0, 0}, |
||||||
|
|
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,198 @@ |
|||||||
|
#include "fh_error.h" |
||||||
|
#include "fh_runtime.h" |
||||||
|
#include "fh_mem.h" |
||||||
|
#include "fh_stack.h" |
||||||
|
#include "fh_print.h" |
||||||
|
#include "fh_builtins.h" |
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode a code point using UTF-8 |
||||||
|
* |
||||||
|
* Copied from ESPTERM source |
||||||
|
* |
||||||
|
* @param out - output buffer (min 4 characters), will be 0-terminated if shorten than 4 |
||||||
|
* @param utf - code point 0-0x10FFFF |
||||||
|
* @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes) |
||||||
|
*/ |
||||||
|
static int utf8_encode(char *out, uint32_t utf) |
||||||
|
{ |
||||||
|
if (utf <= 0x7F) { |
||||||
|
// Plain ASCII
|
||||||
|
out[0] = (char) utf; |
||||||
|
out[1] = 0; |
||||||
|
return 1; |
||||||
|
} else if (utf <= 0x07FF) { |
||||||
|
// 2-byte unicode
|
||||||
|
out[0] = (char) (((utf >> 6) & 0x1F) | 0xC0); |
||||||
|
out[1] = (char) (((utf >> 0) & 0x3F) | 0x80); |
||||||
|
out[2] = 0; |
||||||
|
return 2; |
||||||
|
} else if (utf <= 0xFFFF) { |
||||||
|
// 3-byte unicode
|
||||||
|
out[0] = (char) (((utf >> 12) & 0x0F) | 0xE0); |
||||||
|
out[1] = (char) (((utf >> 6) & 0x3F) | 0x80); |
||||||
|
out[2] = (char) (((utf >> 0) & 0x3F) | 0x80); |
||||||
|
out[3] = 0; |
||||||
|
return 3; |
||||||
|
} else if (utf <= 0x10FFFF) { |
||||||
|
// 4-byte unicode
|
||||||
|
out[0] = (char) (((utf >> 18) & 0x07) | 0xF0); |
||||||
|
out[1] = (char) (((utf >> 12) & 0x3F) | 0x80); |
||||||
|
out[2] = (char) (((utf >> 6) & 0x3F) | 0x80); |
||||||
|
out[3] = (char) (((utf >> 0) & 0x3F) | 0x80); |
||||||
|
// out[4] = 0;
|
||||||
|
return 4; |
||||||
|
} else { |
||||||
|
// error - use replacement character
|
||||||
|
out[0] = (char) 0xEF; |
||||||
|
out[1] = (char) 0xBF; |
||||||
|
out[2] = (char) 0xBD; |
||||||
|
out[3] = 0; |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
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; |
||||||
|
LOG("Get count,addr"); |
||||||
|
TRY(ds_pop(fh, &count)); |
||||||
|
TRY(ds_pop(fh, &addr)); |
||||||
|
|
||||||
|
FHPRINT("%.*s", count, fh_str_at(fh, addr)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error wp_putc(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) fh; |
||||||
|
FHPRINT("%c", w->param); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_debug_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_emit(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)); |
||||||
|
|
||||||
|
char buf[5]; |
||||||
|
int num = utf8_encode(buf, a); |
||||||
|
FHPRINT("%.*s", num, buf); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_see(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
enum fh_error rv; |
||||||
|
char *wordname; |
||||||
|
size_t namelen = 0; |
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
TRY(fh_input_read_word(fh, &wordname, &namelen)); |
||||||
|
TRY(fh_see_word(fh, wordname, namelen)); |
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_s_quote(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
size_t len; |
||||||
|
uint32_t addr = fh->here + (fh->state == FH_STATE_INTERPRET ? 0 : INSTR_SIZE); |
||||||
|
|
||||||
|
/* read the string straight into HEAP */ |
||||||
|
|
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
char *start = (char *) &fh->heap[addr]; |
||||||
|
TRY(fh_input_read_quotedstring(fh, w->param == 1, start, HEAP_END - addr, &len)); |
||||||
|
fh->here = WORDALIGNED(addr + len); |
||||||
|
|
||||||
|
struct fh_instruction_s instr; |
||||||
|
if (fh->state == FH_STATE_INTERPRET) { |
||||||
|
LOG("Interpret a string alloc: \"%.*s\"", len, start); |
||||||
|
TRY(ds_push(fh, addr)); |
||||||
|
TRY(ds_push(fh, len)); |
||||||
|
} else { |
||||||
|
LOG("Compile a string: \"%.*s\"", len, start); |
||||||
|
instr_init(&instr, FH_INSTR_ALLOCSTR, len); |
||||||
|
fh_heap_write(fh, addr - INSTR_SIZE, &instr, INSTR_SIZE); |
||||||
|
} |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
static enum fh_error w_dot_quote(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
(void) w; |
||||||
|
enum fh_error rv; |
||||||
|
size_t len; |
||||||
|
uint32_t addr = fh->here + (fh->state == FH_STATE_INTERPRET ? 0 : INSTR_SIZE); |
||||||
|
|
||||||
|
/* read the string straight into HEAP, but don't advance the heap pointer, so the string is immediately discarded again */ |
||||||
|
|
||||||
|
fh_input_consume_spaces(fh); |
||||||
|
char *start = (char *) &fh->heap[addr]; |
||||||
|
TRY(fh_input_read_quotedstring(fh, w->param == 1, start, HEAP_END - addr, &len)); |
||||||
|
|
||||||
|
struct fh_instruction_s instr; |
||||||
|
if (fh->state == FH_STATE_INTERPRET) { |
||||||
|
FHPRINT("%.*s", (int) len, start); |
||||||
|
} else { |
||||||
|
LOG("Compile a string: \"%.*s\"", len, start); |
||||||
|
instr_init(&instr, FH_INSTR_TYPESTR, len); |
||||||
|
fh_heap_write(fh, addr - INSTR_SIZE, &instr, INSTR_SIZE); |
||||||
|
fh->here = WORDALIGNED(addr + len); |
||||||
|
} |
||||||
|
|
||||||
|
return FH_OK; |
||||||
|
} |
||||||
|
|
||||||
|
const struct name_and_handler fh_builtins_text[] = { |
||||||
|
{"s\"", w_s_quote, 1, 0}, |
||||||
|
{"s\\\"", w_s_quote, 1, 1}, // escaped
|
||||||
|
{".\"", w_dot_quote, 1, 0}, |
||||||
|
{".\\\"", w_dot_quote, 1, 1}, // escaped, this is non-standard
|
||||||
|
{".", w_dot, 0, 0}, |
||||||
|
{"type", w_type, 0, 0}, |
||||||
|
{"cr", wp_putc, 0, '\n'}, |
||||||
|
{"space", wp_putc, 0, ' '}, |
||||||
|
{"bl", wp_const, 0, ' '}, |
||||||
|
{"??", w_debug_dump, 0, 0}, |
||||||
|
{"emit", w_emit, 0, 0}, |
||||||
|
{"see", w_see, 0, 0}, |
||||||
|
{ /* end marker */ } |
||||||
|
}; |
@ -0,0 +1,106 @@ |
|||||||
|
#include "forth.h" |
||||||
|
#include "fh_runtime.h" |
||||||
|
#include "fh_mem.h" |
||||||
|
#include "fh_print.h" |
||||||
|
|
||||||
|
static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
||||||
|
{ |
||||||
|
if (w->flags & WORDFLAG_WORD) { |
||||||
|
if (w->handler == w_user_word) { |
||||||
|
uint32_t execptr = w->param; |
||||||
|
|
||||||
|
FHPRINT("Compiled word %s\n", w->name); |
||||||
|
while (1) { |
||||||
|
// make sure it's aligned
|
||||||
|
execptr = WORDALIGNED(execptr); |
||||||
|
FHPRINT("0x%08x: ", execptr); |
||||||
|
const struct fh_instruction_s *instr = fh_instr_at(fh, execptr); |
||||||
|
execptr += INSTR_SIZE; |
||||||
|
|
||||||
|
uint32_t strl; |
||||||
|
const struct fh_word_s *w2; |
||||||
|
switch (instr->kind) { |
||||||
|
case FH_INSTR_NUMBER: |
||||||
|
FHPRINT("Number(%d)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_WORD: |
||||||
|
w2 = fh_word_at(fh, instr->data); |
||||||
|
FHPRINT("Call(word %s)\n", w2->name); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_POSTPONED_WORD: |
||||||
|
w2 = fh_word_at(fh, instr->data); |
||||||
|
if (w2->name[0]) { |
||||||
|
FHPRINT("Postpone(word %s)\n", w2->name); |
||||||
|
} else { |
||||||
|
FHPRINT("Postpone(word 0x%08x)\n", instr->data); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_JUMPZERO: |
||||||
|
FHPRINT("JumpIfZero(dest 0x%08x)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_JUMP: |
||||||
|
FHPRINT("Jump(dest 0x%08x)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_DO: |
||||||
|
FHPRINT("DO\n"); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_DO_QUESTION: |
||||||
|
FHPRINT("DO?(end 0x%08x)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_LOOP: |
||||||
|
FHPRINT("LOOP(start 0x%08x)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_LOOP_PLUS: |
||||||
|
FHPRINT("LOOP+(start 0x%08x)\n", instr->data); |
||||||
|
break; |
||||||
|
|
||||||
|
/* special case for strings stored in compile memory */ |
||||||
|
case FH_INSTR_ALLOCSTR: |
||||||
|
case FH_INSTR_TYPESTR: |
||||||
|
strl = instr->data; |
||||||
|
if (instr->kind == FH_INSTR_ALLOCSTR) { |
||||||
|
FHPRINT("AllocStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); |
||||||
|
execptr += strl; |
||||||
|
} else { |
||||||
|
FHPRINT("PrintStr(\"%.*s\")\n", strl, fh_str_at(fh, execptr)); |
||||||
|
execptr += strl; |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case FH_INSTR_ENDWORD: |
||||||
|
FHPRINT("END\n"); |
||||||
|
return; |
||||||
|
|
||||||
|
default: |
||||||
|
FHPRINT("Unknown(kind 0x%08x, data 0x%08x)\n", instr->kind, instr->data); |
||||||
|
} |
||||||
|
} |
||||||
|
} else if (w->flags & WORDFLAG_VARIABLE) { |
||||||
|
FHPRINT("Variable %s = %d (0x%08x)\n", w->name, (int32_t)w->param, w->param); |
||||||
|
} else if (w->flags & WORDFLAG_CONSTANT) { |
||||||
|
FHPRINT("Constant %s = %d (0x%08x)\n", w->name, (int32_t)w->param, w->param); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** Decompile a word */ |
||||||
|
enum fh_error fh_see_word( |
||||||
|
struct fh_thread_s *fh, |
||||||
|
const char *name, |
||||||
|
const size_t wordlen |
||||||
|
) |
||||||
|
{ |
||||||
|
enum fh_error rv; |
||||||
|
uint32_t addr; |
||||||
|
TRY(fh_find_word(fh, name, wordlen, &addr)); |
||||||
|
show_word(fh, fh_word_at(fh, addr)); |
||||||
|
return FH_OK; |
||||||
|
} |
Loading…
Reference in new issue