From bc6d7e5d25632e8f29781b2a834020b617015b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 13 Nov 2021 20:10:05 +0100 Subject: [PATCH] new words --- .gitignore | 2 +- forth | Bin 31640 -> 0 bytes include/fh_config.h | 2 + include/fh_error.h | 2 + include/fh_globals.h | 2 + include/fh_mem.h | 8 + include/fh_runtime.h | 20 +- src/fh_builtins.c | 553 +++++++++++++++++++++++++++++++++++++++---- src/fh_error.c | 4 +- src/fh_mem.c | 73 ++++++ src/fh_runtime.c | 23 +- src/main.c | 5 + 12 files changed, 629 insertions(+), 65 deletions(-) delete mode 100755 forth diff --git a/.gitignore b/.gitignore index 113722a..d7d093a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ cmake-* *.bak .idea/ a.out -./forth +forth diff --git a/forth b/forth deleted file mode 100755 index ce9449ae009bc374fc735a315ace6cb417eb9026..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31640 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 + /** Forth runtime global state */ struct fh_global_s { /** Verbose logging enabled */ diff --git a/include/fh_mem.h b/include/fh_mem.h index 096a569..52e129f 100644 --- a/include/fh_mem.h +++ b/include/fh_mem.h @@ -7,6 +7,14 @@ #ifndef FORTH_FH_MEM_H #define FORTH_FH_MEM_H +enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst); + +enum fh_error fh_fetch_char(struct fh_thread_s *fh, uint32_t addr, char *dst); + +enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val); + +enum fh_error fh_store_char(struct fh_thread_s *fh, uint32_t addr, char val); + enum fh_error fh_heap_reserve( struct fh_thread_s *fh, size_t len, diff --git a/include/fh_runtime.h b/include/fh_runtime.h index 3db86f6..0ded4e7 100644 --- a/include/fh_runtime.h +++ b/include/fh_runtime.h @@ -19,7 +19,7 @@ struct fh_instruction_s; struct fh_thread_s; /** Word handler typedef */ -typedef enum fh_error (*word_exec_t)(struct fh_thread_s *fh); +typedef enum fh_error (*word_exec_t)(struct fh_thread_s *fh, const struct fh_word_s *w); /** Bytecode instruction type marker */ enum fb_instruction_kind { @@ -62,6 +62,7 @@ _Static_assert(sizeof(struct fh_instruction_s) % 4 == 0, "Instruction struct is enum fh_state { FH_STATE_INTERPRET = 0, FH_STATE_COMPILE, + FH_STATE_QUIT, FH_STATE_SHUTDOWN, FH_STATE_MAX, }; @@ -93,8 +94,11 @@ struct fh_word_s { /** Indicates that this instruction should always be treated as interpreted, * in practice this is only used for `;` */ bool immediate; - /** Start address in case of user words */ - uint32_t start; + /** Start address in case of user words, or param for builtins */ + union { + uint32_t start; + uint32_t param; + }; }; /** @@ -139,9 +143,8 @@ struct fh_thread_s { /** Forth sub-state */ enum fh_substate substate; - /** Word currently being executed - a pointer is placed here - * before calling the handler */ - struct fh_word_s *exec_word; + /** The numeric base register */ + uint32_t base; }; enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh); @@ -149,10 +152,13 @@ enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh); void fh_setstate(struct fh_thread_s *fh, enum fh_state state, enum fh_substate substate); void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate); -enum fh_error w_user_word(struct fh_thread_s *fh); +enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w); /* if the return address is this, we should drop back to interactive mode */ + +// SFR and magic addresses are "negative" #define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL +#define MAGICADDR_BASE 0xFFFBA5EFULL /** Get a value rounded up to multiple of word size */ #define WORDALIGNED(var) (((var) + 3) & ~3) diff --git a/src/fh_builtins.c b/src/fh_builtins.c index b56314b..6148a59 100644 --- a/src/fh_builtins.c +++ b/src/fh_builtins.c @@ -8,8 +8,11 @@ #include "fh_stack.h" #include "fh_mem.h" -static enum fh_error w_add(struct fh_thread_s *fh) +#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)); @@ -18,8 +21,9 @@ static enum fh_error w_add(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_sub(struct fh_thread_s *fh) +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)); @@ -28,8 +32,9 @@ static enum fh_error w_sub(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_mul(struct fh_thread_s *fh) +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)); @@ -38,8 +43,176 @@ static enum fh_error w_mul(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_colon(struct fh_thread_s *fh) +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; } @@ -54,8 +227,9 @@ static enum fh_error w_colon(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_semicolon(struct fh_thread_s *fh) +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; @@ -73,8 +247,9 @@ static enum fh_error w_semicolon(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_dup(struct fh_thread_s *fh) +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)); @@ -82,30 +257,76 @@ static enum fh_error w_dup(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_drop(struct fh_thread_s *fh) +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) +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_rot(struct fh_thread_s *fh) +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) +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)); @@ -113,8 +334,22 @@ static enum fh_error w_over(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_tuck(struct fh_thread_s *fh) +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; @@ -126,8 +361,9 @@ static enum fh_error w_tuck(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_pick(struct fh_thread_s *fh) +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; @@ -137,8 +373,9 @@ static enum fh_error w_pick(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_roll(struct fh_thread_s *fh) +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)); @@ -146,8 +383,78 @@ static enum fh_error w_roll(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_dot(struct fh_thread_s *fh) +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)); @@ -156,8 +463,9 @@ static enum fh_error w_dot(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_type(struct fh_thread_s *fh) +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)); @@ -167,59 +475,167 @@ static enum fh_error w_type(struct fh_thread_s *fh) return FH_OK; } -static enum fh_error w_cr(struct fh_thread_s *fh) +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) +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) +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_s_quote(struct fh_thread_s *fh) +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) +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) +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) +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) +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) { @@ -227,37 +643,79 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) const char *name; word_exec_t handler; bool immediate; + uint32_t param; }; const struct name_and_handler builtins[] = { - {"s\"", w_s_quote, 1}, - {".\"", w_dot_quote, 1}, + {"s\"", w_s_quote, 1, 0}, + {".\"", w_dot_quote, 1, 0}, /* Compiler control words */ - {"bye", w_bye, 0}, + {"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 */ - {"+", w_add, 0}, - {"-", w_sub, 0}, - {"*", w_mul, 0}, + {"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 */ - {"dup", w_dup, 0}, - {"drop", w_drop, 0}, - {"swap", w_swap, 0}, - {"rot", w_rot, 0}, - {"over", w_over, 0}, - {"tuck", w_tuck, 0}, - {"pick", w_pick, 0}, - {"roll", w_roll, 0}, + {"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}, - {"type", w_type, 0}, - {"cr", w_cr, 0}, - {"space", w_space, 0}, - {"dump", w_dump, 0}, - /* Control words */ - {":", w_colon, 0}, - {";", w_semicolon, 1}, - {"\\", w_backslash, 1}, // line comment - {"(", w_paren, 1}, // enclosed comment + {".", 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 */ } }; @@ -270,6 +728,7 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh) 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; diff --git a/src/fh_error.c b/src/fh_error.c index fddbf3b..f0d7ae3 100644 --- a/src/fh_error.c +++ b/src/fh_error.c @@ -1,7 +1,7 @@ #include "fh_error.h" /** Error names */ -static const char *errornames[] = { +static const char *errornames[FH_ERR_MAX] = { [FH_OK] = "OK", [FH_ERR_CS_OVERFLOW] = "CS_OVERFLOW", [FH_ERR_DS_OVERFLOW] = "DS_OVERFLOW", @@ -16,6 +16,8 @@ static const char *errornames[] = { [FH_ERR_INVALID_STATE] = "INVALID_STATE", [FH_ERR_INTERNAL] = "INTERNAL", [FH_ERR_UNKNOWN_WORD] = "UNKNOWN_WORD", + [FH_ERR_ILLEGAL_FETCH] = "ILLEGAL_FETCH", + [FH_ERR_DIV_BY_ZERO] = "DIV_BY_ZERO", }; /** Get error name from code, returns Unknown if not defined */ diff --git a/src/fh_mem.c b/src/fh_mem.c index bca4561..d33bd23 100644 --- a/src/fh_mem.c +++ b/src/fh_mem.c @@ -1,9 +1,82 @@ #include +#include "fh_print.h" #include "fh_error.h" #include "fh_runtime.h" #include "fh_mem.h" +enum fh_error fh_fetch(struct fh_thread_s *fh, uint32_t addr, uint32_t *dst) +{ + switch (addr) { + case MAGICADDR_BASE: + *dst = fh->base; + break; + // TODO more magic + + default: + if (addr & 3) { + LOGE("Address 0x%08x is not aligned!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + if (addr < HEAP_SIZE - 4) { + *dst = *((uint32_t*)&fh->heap[addr]); + } else { + LOGE("Address 0x%08x too high!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + } + + return FH_OK; +} + +enum fh_error fh_fetch_char(struct fh_thread_s *fh, uint32_t addr, char *dst) +{ + if (addr < HEAP_SIZE - 4) { + *dst = (char) fh->heap[addr]; + } else { + LOGE("Address 0x%08x too high!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + + return FH_OK; +} + +enum fh_error fh_store(struct fh_thread_s *fh, uint32_t addr, uint32_t val) +{ + switch (addr) { + case MAGICADDR_BASE: + fh->base = val; + break; + // TODO more magic + + default: + if (addr & 3) { + LOGE("Address 0x%08x is not aligned!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + if (addr <= HEAP_SIZE - 4) { + *((uint32_t*)&fh->heap[addr]) = val; + } else { + LOGE("Address 0x%08x too high!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + } + + return FH_OK; +} + +enum fh_error fh_store_char(struct fh_thread_s *fh, uint32_t addr, char val) +{ + if (addr < HEAP_SIZE) { + fh->heap[addr] = val; + } else { + LOGE("Address 0x%08x too high!", addr); + return FH_ERR_ILLEGAL_FETCH; + } + + return FH_OK; +} + /** Allocate a heap region, e.g. for a string. The address is stored to `addr` */ enum fh_error fh_heap_reserve( struct fh_thread_s *fh, diff --git a/src/fh_runtime.c b/src/fh_runtime.c index 15465e3..bd35291 100644 --- a/src/fh_runtime.c +++ b/src/fh_runtime.c @@ -13,14 +13,14 @@ struct fh_global_s fh_globals = {}; /** State names */ -static const char *statenames[] = { +static const char *statenames[FH_STATE_MAX] = { [FH_STATE_INTERPRET] = "INTERPRET", [FH_STATE_COMPILE] = "COMPILE", [FH_STATE_SHUTDOWN] = "SHUTDOWN", }; /** Sub-state names */ -static const char *substatenames[] = { +static const char *substatenames[FH_SUBSTATE_MAX] = { [FH_SUBSTATE_NONE] = "NONE", [FH_SUBSTATE_COLONNAME] = "COLONNAME", [FH_SUBSTATE_SQUOTE] = "SQUOTE", @@ -65,15 +65,15 @@ void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate) } /** Execute a user word */ -enum fh_error w_user_word(struct fh_thread_s *fh) +enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) { enum fh_error rv; const struct fh_word_s *w; const struct fh_word_s *w2; uint32_t wn; + w = w0; call: - w = fh->exec_word; if (!w) { return FH_ERR_INTERNAL; } LOG("Run user word: %s", w->name); @@ -82,6 +82,11 @@ enum fh_error w_user_word(struct fh_thread_s *fh) fh->execptr = w->start; instr:; + if (fh->state == FH_STATE_QUIT) { + /* abort or quit was called, return to interactive mode */ + fh_setstate(fh, FH_STATE_INTERPRET, FH_SUBSTATE_NONE); + return FH_OK; + } // make sure it's aligned fh->execptr = WORDALIGNED(fh->execptr); const struct fh_instruction_s *instr = (const struct fh_instruction_s *) &fh->compile[fh->execptr]; @@ -128,11 +133,11 @@ enum fh_error w_user_word(struct fh_thread_s *fh) w2 = &fh->dict[instr->data]; if (w2->builtin) { LOG("Exec: builtin-word %s", w2->name); - w2->handler(fh); + w2->handler(fh, w2); goto instr; } else { LOG("Exec: user-word %s (CALL)", w2->name); - fh->exec_word = &fh->dict[instr->data]; + w = &fh->dict[instr->data]; goto call; } } @@ -154,6 +159,7 @@ enum fh_error fh_init(struct fh_thread_s *fh) TRY(register_builtin_words(fh)); fh->execptr = MAGICADDR_INTERACTIVE; + fh->base = 10; return FH_OK; } @@ -229,8 +235,7 @@ static enum fh_error fh_handle_word( } else { /* interpret */ LOG("Interpret word: %s", w->name); - fh->exec_word = w; - TRY(w->handler(fh)); + TRY(w->handler(fh, w)); } return FH_OK; } @@ -241,7 +246,7 @@ static enum fh_error fh_handle_word( /* word not found, try parsing as number */ errno = 0; char *endptr; - long v = strtol(start, &endptr, 0); + long v = strtol(start, &endptr, (int) fh->base); // XXX if base is 0, this will use auto-detection if (errno != 0 || endptr == start) { LOGE("Unknown word and fail to parse as number: %.*s", (int) len, start); return FH_ERR_UNKNOWN_WORD; diff --git a/src/main.c b/src/main.c index e376bc4..d6278e0 100644 --- a/src/main.c +++ b/src/main.c @@ -49,9 +49,12 @@ int main(int argc, char *argv[]) } } + const char *prompt = "> "; + /* process input line by line */ int linecnt = 0; char linebuf[MAXLINE]; + FHPRINT("%s", prompt); while (fh.state != FH_STATE_SHUTDOWN && fgets(linebuf, MAXLINE, infile)) { linecnt++; @@ -76,6 +79,8 @@ int main(int argc, char *argv[]) /* reset state */ fh_setstate(&fh, FH_STATE_INTERPRET, FH_SUBSTATE_NONE); } + + FHPRINT("%s", prompt); } // Show resource usage