master
Ondřej Hruška 3 years ago
parent e63c2287af
commit bc6d7e5d25
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      .gitignore
  2. BIN
      forth
  3. 2
      include/fh_config.h
  4. 2
      include/fh_error.h
  5. 2
      include/fh_globals.h
  6. 8
      include/fh_mem.h
  7. 18
      include/fh_runtime.h
  8. 553
      src/fh_builtins.c
  9. 4
      src/fh_error.c
  10. 73
      src/fh_mem.c
  11. 23
      src/fh_runtime.c
  12. 5
      src/main.c

2
.gitignore vendored

@ -3,4 +3,4 @@ cmake-*
*.bak *.bak
.idea/ .idea/
a.out a.out
./forth forth

BIN
forth

Binary file not shown.

@ -16,4 +16,6 @@
#define HEAP_SIZE (1024*1024) #define HEAP_SIZE (1024*1024)
#define MAXLINE 65535 #define MAXLINE 65535
#define CELL 4
#endif //FORTH_FH_CONFIG_H #endif //FORTH_FH_CONFIG_H

@ -23,6 +23,8 @@ enum fh_error {
FH_ERR_INVALID_STATE, FH_ERR_INVALID_STATE,
FH_ERR_INTERNAL, FH_ERR_INTERNAL,
FH_ERR_UNKNOWN_WORD, FH_ERR_UNKNOWN_WORD,
FH_ERR_ILLEGAL_FETCH,
FH_ERR_DIV_BY_ZERO,
FH_ERR_MAX, FH_ERR_MAX,
}; };

@ -7,6 +7,8 @@
#ifndef FORTH_FH_GLOBALS_H #ifndef FORTH_FH_GLOBALS_H
#define FORTH_FH_GLOBALS_H #define FORTH_FH_GLOBALS_H
#include <stdbool.h>
/** Forth runtime global state */ /** Forth runtime global state */
struct fh_global_s { struct fh_global_s {
/** Verbose logging enabled */ /** Verbose logging enabled */

@ -7,6 +7,14 @@
#ifndef FORTH_FH_MEM_H #ifndef FORTH_FH_MEM_H
#define 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( enum fh_error fh_heap_reserve(
struct fh_thread_s *fh, struct fh_thread_s *fh,
size_t len, size_t len,

@ -19,7 +19,7 @@ struct fh_instruction_s;
struct fh_thread_s; struct fh_thread_s;
/** Word handler typedef */ /** 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 */ /** Bytecode instruction type marker */
enum fb_instruction_kind { enum fb_instruction_kind {
@ -62,6 +62,7 @@ _Static_assert(sizeof(struct fh_instruction_s) % 4 == 0, "Instruction struct is
enum fh_state { enum fh_state {
FH_STATE_INTERPRET = 0, FH_STATE_INTERPRET = 0,
FH_STATE_COMPILE, FH_STATE_COMPILE,
FH_STATE_QUIT,
FH_STATE_SHUTDOWN, FH_STATE_SHUTDOWN,
FH_STATE_MAX, FH_STATE_MAX,
}; };
@ -93,8 +94,11 @@ struct fh_word_s {
/** Indicates that this instruction should always be treated as interpreted, /** Indicates that this instruction should always be treated as interpreted,
* in practice this is only used for `;` */ * in practice this is only used for `;` */
bool immediate; 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 start;
uint32_t param;
};
}; };
/** /**
@ -139,9 +143,8 @@ struct fh_thread_s {
/** Forth sub-state */ /** Forth sub-state */
enum fh_substate substate; enum fh_substate substate;
/** Word currently being executed - a pointer is placed here /** The numeric base register */
* before calling the handler */ uint32_t base;
struct fh_word_s *exec_word;
}; };
enum fh_error fh_add_word(const struct fh_word_s *w, struct fh_thread_s *fh); 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_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); 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 */ /* 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_INTERACTIVE 0xFFFFFFFFULL
#define MAGICADDR_BASE 0xFFFBA5EFULL
/** Get a value rounded up to multiple of word size */ /** Get a value rounded up to multiple of word size */
#define WORDALIGNED(var) (((var) + 3) & ~3) #define WORDALIGNED(var) (((var) + 3) & ~3)

@ -8,8 +8,11 @@
#include "fh_stack.h" #include "fh_stack.h"
#include "fh_mem.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; enum fh_error rv;
uint32_t a = 0, b = 0; uint32_t a = 0, b = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
@ -18,8 +21,9 @@ static enum fh_error w_add(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0, b = 0; uint32_t a = 0, b = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
@ -28,8 +32,9 @@ static enum fh_error w_sub(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0, b = 0; uint32_t a = 0, b = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
@ -38,8 +43,176 @@ static enum fh_error w_mul(struct fh_thread_s *fh)
return FH_OK; 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) { if (fh->state != FH_STATE_INTERPRET) {
return FH_ERR_INVALID_STATE; return FH_ERR_INVALID_STATE;
} }
@ -54,8 +227,9 @@ static enum fh_error w_colon(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
struct fh_instruction_s instr; struct fh_instruction_s instr;
@ -73,8 +247,9 @@ static enum fh_error w_semicolon(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
TRY(ds_peek(fh, &a)); TRY(ds_peek(fh, &a));
@ -82,30 +257,76 @@ static enum fh_error w_dup(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
TRY(ds_pop(fh, &a));
return FH_OK; 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; enum fh_error rv;
TRY(ds_roll(fh, 1)); TRY(ds_roll(fh, 1));
return FH_OK; 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; enum fh_error rv;
TRY(ds_roll(fh, 2)); TRY(ds_roll(fh, 2));
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
TRY(ds_peek_n(fh, &a, 1)); 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; 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; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
uint32_t b = 0; uint32_t b = 0;
@ -126,8 +361,9 @@ static enum fh_error w_tuck(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t nth = 0; uint32_t nth = 0;
uint32_t a = 0; uint32_t a = 0;
@ -137,8 +373,9 @@ static enum fh_error w_pick(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t n = 0; uint32_t n = 0;
TRY(ds_pop(fh, &n)); TRY(ds_pop(fh, &n));
@ -146,8 +383,78 @@ static enum fh_error w_roll(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t a = 0; uint32_t a = 0;
TRY(ds_pop(fh, &a)); TRY(ds_pop(fh, &a));
@ -156,8 +463,9 @@ static enum fh_error w_dot(struct fh_thread_s *fh)
return FH_OK; 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; enum fh_error rv;
uint32_t count = 0, addr = 0; uint32_t count = 0, addr = 0;
TRY(ds_pop(fh, &count)); TRY(ds_pop(fh, &count));
@ -167,59 +475,167 @@ static enum fh_error w_type(struct fh_thread_s *fh)
return FH_OK; 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; (void) fh;
FHPRINT("\n"); FHPRINT("\n");
return FH_OK; 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; (void) fh;
FHPRINT(" "); FHPRINT(" ");
return FH_OK; 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; (void) fh;
FHPRINT("DS ");
for (int i = 0; i < fh->data_stack_top; i++) { for (int i = 0; i < fh->data_stack_top; i++) {
FHPRINT("%d ", fh->data_stack[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; 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); fh_setsubstate(fh, FH_SUBSTATE_SQUOTE);
return FH_OK; 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); fh_setsubstate(fh, FH_SUBSTATE_DOTQUOTE);
return FH_OK; 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); fh_setsubstate(fh, FH_SUBSTATE_LINECOMMENT);
return FH_OK; 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); fh_setsubstate(fh, FH_SUBSTATE_PARENCOMMENT);
return FH_OK; 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); fh_setstate(fh, FH_STATE_SHUTDOWN, 0);
return FH_OK; 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 */ /** Add pointers to built-in word handlers to a runtime struct */
enum fh_error register_builtin_words(struct fh_thread_s *fh) 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; const char *name;
word_exec_t handler; word_exec_t handler;
bool immediate; bool immediate;
uint32_t param;
}; };
const struct name_and_handler builtins[] = { const struct name_and_handler builtins[] = {
{"s\"", w_s_quote, 1}, {"s\"", w_s_quote, 1, 0},
{".\"", w_dot_quote, 1}, {".\"", w_dot_quote, 1, 0},
/* Compiler control words */ /* 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 */ /* Arithmetics */
{"+", w_add, 0}, {"dec", wp_setbase, 0, 10},
{"-", w_sub, 0}, {"hex", wp_setbase, 0, 16},
{"*", w_mul, 0}, {"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 */ /* Stack manip */
{"dup", w_dup, 0}, {"drop", w_drop, 0, 0},
{"drop", w_drop, 0}, {"dup", w_dup, 0, 0},
{"swap", w_swap, 0}, {"over", w_over, 0, 0},
{"rot", w_rot, 0}, {"swap", w_swap, 0, 0},
{"over", w_over, 0}, {"rot", w_rot, 0, 0},
{"tuck", w_tuck, 0}, {"tuck", w_tuck, 0, 0},
{"pick", w_pick, 0}, {"pick", w_pick, 0, 0},
{"roll", w_roll, 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 */ /* Printing */
{".", w_dot, 0}, {".", w_dot, 0, 0},
{"type", w_type, 0}, {"type", w_type, 0, 0},
{"cr", w_cr, 0}, {"cr", w_cr, 0, 0},
{"space", w_space, 0}, {"space", w_space, 0, 0},
{"dump", w_dump, 0}, {"dump", w_dump, 0, 0},
/* Control words */ /* Control flow */
{":", w_colon, 0}, {"abort", w_abort, 0, 0},
{";", w_semicolon, 1}, {"quit", w_quit, 0, 0},
{"\\", w_backslash, 1}, // line comment /* Syntax */
{"(", w_paren, 1}, // enclosed comment {":", w_colon, 0, 0},
{";", w_semicolon, 1, 0},
{"\\", w_backslash, 1, 0}, // line comment
{"(", w_paren, 1, 0}, // enclosed comment
{ /* end marker */ } { /* end marker */ }
}; };
@ -270,6 +728,7 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh)
w.handler = p->handler; w.handler = p->handler;
w.builtin = 1; w.builtin = 1;
w.immediate = p->immediate; w.immediate = p->immediate;
w.param = p->param;
rv = fh_add_word(&w, fh); rv = fh_add_word(&w, fh);
if (rv != FH_OK) { if (rv != FH_OK) {
return rv; return rv;

@ -1,7 +1,7 @@
#include "fh_error.h" #include "fh_error.h"
/** Error names */ /** Error names */
static const char *errornames[] = { static const char *errornames[FH_ERR_MAX] = {
[FH_OK] = "OK", [FH_OK] = "OK",
[FH_ERR_CS_OVERFLOW] = "CS_OVERFLOW", [FH_ERR_CS_OVERFLOW] = "CS_OVERFLOW",
[FH_ERR_DS_OVERFLOW] = "DS_OVERFLOW", [FH_ERR_DS_OVERFLOW] = "DS_OVERFLOW",
@ -16,6 +16,8 @@ static const char *errornames[] = {
[FH_ERR_INVALID_STATE] = "INVALID_STATE", [FH_ERR_INVALID_STATE] = "INVALID_STATE",
[FH_ERR_INTERNAL] = "INTERNAL", [FH_ERR_INTERNAL] = "INTERNAL",
[FH_ERR_UNKNOWN_WORD] = "UNKNOWN_WORD", [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 */ /** Get error name from code, returns Unknown if not defined */

@ -1,9 +1,82 @@
#include <string.h> #include <string.h>
#include "fh_print.h"
#include "fh_error.h" #include "fh_error.h"
#include "fh_runtime.h" #include "fh_runtime.h"
#include "fh_mem.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` */ /** Allocate a heap region, e.g. for a string. The address is stored to `addr` */
enum fh_error fh_heap_reserve( enum fh_error fh_heap_reserve(
struct fh_thread_s *fh, struct fh_thread_s *fh,

@ -13,14 +13,14 @@
struct fh_global_s fh_globals = {}; struct fh_global_s fh_globals = {};
/** State names */ /** State names */
static const char *statenames[] = { static const char *statenames[FH_STATE_MAX] = {
[FH_STATE_INTERPRET] = "INTERPRET", [FH_STATE_INTERPRET] = "INTERPRET",
[FH_STATE_COMPILE] = "COMPILE", [FH_STATE_COMPILE] = "COMPILE",
[FH_STATE_SHUTDOWN] = "SHUTDOWN", [FH_STATE_SHUTDOWN] = "SHUTDOWN",
}; };
/** Sub-state names */ /** Sub-state names */
static const char *substatenames[] = { static const char *substatenames[FH_SUBSTATE_MAX] = {
[FH_SUBSTATE_NONE] = "NONE", [FH_SUBSTATE_NONE] = "NONE",
[FH_SUBSTATE_COLONNAME] = "COLONNAME", [FH_SUBSTATE_COLONNAME] = "COLONNAME",
[FH_SUBSTATE_SQUOTE] = "SQUOTE", [FH_SUBSTATE_SQUOTE] = "SQUOTE",
@ -65,15 +65,15 @@ void fh_setsubstate(struct fh_thread_s *fh, enum fh_substate substate)
} }
/** Execute a user word */ /** 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; enum fh_error rv;
const struct fh_word_s *w; const struct fh_word_s *w;
const struct fh_word_s *w2; const struct fh_word_s *w2;
uint32_t wn; uint32_t wn;
w = w0;
call: call:
w = fh->exec_word;
if (!w) { return FH_ERR_INTERNAL; } if (!w) { return FH_ERR_INTERNAL; }
LOG("Run user word: %s", w->name); 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; fh->execptr = w->start;
instr:; 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 // make sure it's aligned
fh->execptr = WORDALIGNED(fh->execptr); fh->execptr = WORDALIGNED(fh->execptr);
const struct fh_instruction_s *instr = (const struct fh_instruction_s *) &fh->compile[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]; w2 = &fh->dict[instr->data];
if (w2->builtin) { if (w2->builtin) {
LOG("Exec: builtin-word %s", w2->name); LOG("Exec: builtin-word %s", w2->name);
w2->handler(fh); w2->handler(fh, w2);
goto instr; goto instr;
} else { } else {
LOG("Exec: user-word %s (CALL)", w2->name); LOG("Exec: user-word %s (CALL)", w2->name);
fh->exec_word = &fh->dict[instr->data]; w = &fh->dict[instr->data];
goto call; goto call;
} }
} }
@ -154,6 +159,7 @@ enum fh_error fh_init(struct fh_thread_s *fh)
TRY(register_builtin_words(fh)); TRY(register_builtin_words(fh));
fh->execptr = MAGICADDR_INTERACTIVE; fh->execptr = MAGICADDR_INTERACTIVE;
fh->base = 10;
return FH_OK; return FH_OK;
} }
@ -229,8 +235,7 @@ static enum fh_error fh_handle_word(
} else { } else {
/* interpret */ /* interpret */
LOG("Interpret word: %s", w->name); LOG("Interpret word: %s", w->name);
fh->exec_word = w; TRY(w->handler(fh, w));
TRY(w->handler(fh));
} }
return FH_OK; return FH_OK;
} }
@ -241,7 +246,7 @@ static enum fh_error fh_handle_word(
/* word not found, try parsing as number */ /* word not found, try parsing as number */
errno = 0; errno = 0;
char *endptr; 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) { if (errno != 0 || endptr == start) {
LOGE("Unknown word and fail to parse as number: %.*s", (int) len, start); LOGE("Unknown word and fail to parse as number: %.*s", (int) len, start);
return FH_ERR_UNKNOWN_WORD; return FH_ERR_UNKNOWN_WORD;

@ -49,9 +49,12 @@ int main(int argc, char *argv[])
} }
} }
const char *prompt = "> ";
/* process input line by line */ /* process input line by line */
int linecnt = 0; int linecnt = 0;
char linebuf[MAXLINE]; char linebuf[MAXLINE];
FHPRINT("%s", prompt);
while (fh.state != FH_STATE_SHUTDOWN && fgets(linebuf, MAXLINE, infile)) { while (fh.state != FH_STATE_SHUTDOWN && fgets(linebuf, MAXLINE, infile)) {
linecnt++; linecnt++;
@ -76,6 +79,8 @@ int main(int argc, char *argv[])
/* reset state */ /* reset state */
fh_setstate(&fh, FH_STATE_INTERPRET, FH_SUBSTATE_NONE); fh_setstate(&fh, FH_STATE_INTERPRET, FH_SUBSTATE_NONE);
} }
FHPRINT("%s", prompt);
} }
// Show resource usage // Show resource usage

Loading…
Cancel
Save