new words
This commit is contained in:
+1
-1
@@ -3,4 +3,4 @@ cmake-*
|
||||
*.bak
|
||||
.idea/
|
||||
a.out
|
||||
./forth
|
||||
forth
|
||||
|
||||
@@ -16,4 +16,6 @@
|
||||
#define HEAP_SIZE (1024*1024)
|
||||
#define MAXLINE 65535
|
||||
|
||||
#define CELL 4
|
||||
|
||||
#endif //FORTH_FH_CONFIG_H
|
||||
|
||||
@@ -23,6 +23,8 @@ enum fh_error {
|
||||
FH_ERR_INVALID_STATE,
|
||||
FH_ERR_INTERNAL,
|
||||
FH_ERR_UNKNOWN_WORD,
|
||||
FH_ERR_ILLEGAL_FETCH,
|
||||
FH_ERR_DIV_BY_ZERO,
|
||||
FH_ERR_MAX,
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef FORTH_FH_GLOBALS_H
|
||||
#define FORTH_FH_GLOBALS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/** Forth runtime global state */
|
||||
struct fh_global_s {
|
||||
/** Verbose logging enabled */
|
||||
|
||||
@@ -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,
|
||||
|
||||
+12
-6
@@ -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 */
|
||||
/** 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)
|
||||
|
||||
+506
-47
@@ -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_swap(struct fh_thread_s *fh)
|
||||
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_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;
|
||||
|
||||
+3
-1
@@ -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 */
|
||||
|
||||
@@ -1,9 +1,82 @@
|
||||
#include <string.h>
|
||||
|
||||
#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,
|
||||
|
||||
+14
-9
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user