implement IF-THEN-ELSE

master
Ondřej Hruška 3 years ago
parent f013e52c94
commit 1be97e4f0e
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 20
      include/fh_runtime.h
  2. 75
      src/fh_builtins.c
  3. 4
      src/fh_mem.c
  4. 165
      src/fh_runtime.c

@ -28,16 +28,21 @@ enum fb_instruction_kind {
/* Data = numeric value to push onto the data stack */
FH_INSTR_NUMBER,
};
/** Bytecode word indices that are not in the dict, have special effect */
enum compiler_word {
/** End of a user defined word, pop address and jump back */
CPLWORD_ENDWORD = DICT_SIZE + 1,
FH_INSTR_ENDWORD,
/** This is the `s"` instruction, the length (u32) and string data immediately follow */
CPLWORD_ALLOCSTR,
FH_INSTR_ALLOCSTR,
/** This is the `."` instruction, same format as above. */
CPLWORD_TYPESTR,
FH_INSTR_TYPESTR,
/* Unconditional jump */
FH_INSTR_JUMP,
/* Jump if zero */
FH_INSTR_JUMPZERO,
};
/** One instruction in bytecode */
@ -160,7 +165,8 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w);
// SFR and magic addresses are "negative"
#define MAGICADDR_INTERACTIVE 0xFFFFFFFFULL
#define MAGICADDR_BASE 0xFFFBA5EFULL
#define MAGICADDR_BASE 0xFFFFBA5EULL
#define MAGICADDR_UNRESOLVED 0xFFFFFBADULL
/** Get a value rounded up to multiple of word size */
#define WORDALIGNED(var) (((var) + 3) & ~3)

@ -1,5 +1,6 @@
#include <string.h>
#include <stdbool.h>
#include "forth.h" // for fh_init
#include "fh_runtime.h"
#include "fh_config.h"
#include "fh_error.h"
@ -310,7 +311,7 @@ static enum fh_error w_semicolon(struct fh_thread_s *fh, const struct fh_word_s
ENSURE_STATE(FH_STATE_COMPILE);
instr_init(&instr, FH_INSTR_WORD, CPLWORD_ENDWORD);
instr_init(&instr, FH_INSTR_ENDWORD, 0);
TRY(fh_compile_put(fh, &instr, INSTR_SIZE));
/* Return to interpret state */
@ -700,6 +701,64 @@ static enum fh_error w_bye(struct fh_thread_s *fh, const struct fh_word_s *w)
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;
struct fh_instruction_s instr;
ENSURE_STATE(FH_STATE_COMPILE);
TRY(cs_push(fh, fh->compile_top));
instr_init(&instr, FH_INSTR_JUMPZERO, MAGICADDR_UNRESOLVED);
TRY(fh_compile_put(fh, &instr, INSTR_SIZE));
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;
struct fh_instruction_s instr;
ENSURE_STATE(FH_STATE_COMPILE);
uint32_t ifaddr = 0;
TRY(cs_pop(fh, &ifaddr));
struct fh_instruction_s *if_instr = (void*) &fh->compile[ifaddr];
if (if_instr->data != MAGICADDR_UNRESOLVED) {
LOGE("IF-ELSE control stack corruption");
return FH_ERR_INTERNAL;
}
if_instr->data = fh->compile_top + INSTR_SIZE;
TRY(cs_push(fh, fh->compile_top));
instr_init(&instr, FH_INSTR_JUMP, MAGICADDR_UNRESOLVED);
TRY(fh_compile_put(fh, &instr, INSTR_SIZE));
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;
struct fh_instruction_s instr;
ENSURE_STATE(FH_STATE_COMPILE);
uint32_t ifaddr = 0;
TRY(cs_pop(fh, &ifaddr));
struct fh_instruction_s *if_instr = (void*) &fh->compile[ifaddr];
if (if_instr->data != MAGICADDR_UNRESOLVED) {
LOGE("IF-ELSE control stack corruption");
return FH_ERR_INTERNAL;
}
if_instr->data = fh->compile_top;
return FH_OK;
}
static enum fh_error wp_setbase(struct fh_thread_s *fh, const struct fh_word_s *w)
{
fh_setbase(fh, w->param);
@ -749,16 +808,7 @@ static enum fh_error w_reset(struct fh_thread_s *fh, const struct fh_word_s *w)
ENSURE_STATE(FH_STATE_INTERPRET);
fh->data_stack_top = 0;
fh->return_stack_top = 0;
fh->control_stack_top = 0;
fh->data_stack_hwm = 0;
fh->return_stack_hwm = 0;
fh->control_stack_hwm = 0;
fh->heap_top = 0;
fh->dict_top = 0;
TRY(ds_push(fh, w->param));
fh_init(fh);
return FH_OK;
}
@ -909,6 +959,9 @@ enum fh_error register_builtin_words(struct fh_thread_s *fh)
{"abort", w_abort, 0, 0},
{"quit", w_quit, 0, 0},
{"exit", w_exit, 0, 0},
{"if", w_if, 1, 0},
{"else", w_else, 1, 0},
{"then", w_then, 1, 0},
/* Syntax */
{":", w_colon, 0, 0},
{";", w_semicolon, 1, 0},

@ -89,7 +89,7 @@ enum fh_error fh_heap_reserve(
uint32_t *addr
)
{
uint32_t p = WORDALIGNED(fh->heap_top); // FIXME this shouldn't be needed
uint32_t p = fh->heap_top;
if (p + len > HEAP_SIZE) {
return FH_ERR_HEAP_FULL;
@ -131,7 +131,7 @@ enum fh_error fh_compile_reserve(
uint32_t *addr
)
{
uint32_t p = WORDALIGNED(fh->compile_top); // FIXME this shouldn't be needed
uint32_t p = fh->compile_top; // FIXME this shouldn't be needed
if (p + len > COMPILED_BUFFER_SIZE) {
return FH_ERR_HEAP_FULL;

@ -72,7 +72,6 @@ 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:
@ -95,6 +94,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
fh->execptr += INSTR_SIZE;
uint32_t strl;
uint32_t val;
uint32_t addr = 0;
switch (instr->kind) {
case FH_INSTR_NUMBER:
@ -102,54 +102,60 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0)
goto instr;
case FH_INSTR_WORD:
wn = instr->data;
switch (wn) {
/* special case for strings stored in compile memory */
case CPLWORD_ALLOCSTR:
case CPLWORD_TYPESTR:
strl = *((uint32_t *) &fh->compile[fh->execptr]);
fh->execptr += 4; // advance past the length
if (wn == CPLWORD_ALLOCSTR) {
TRY(fh_heap_reserve(fh, strl, &addr));
fh_heap_copy_from_compile(fh, addr, fh->execptr, strl);
LOG("Exec: alloc-str \"%.*s\"", strl, &fh->heap[addr]);
TRY(ds_push(fh, addr));
TRY(ds_push(fh, strl));
} else {
LOG("Exec: type-str \"%.*s\"", strl, &fh->compile[fh->execptr]);
FHPRINT("%.*s", (int) strl, &fh->compile[fh->execptr]);
}
fh->execptr += strl;
goto instr;
case CPLWORD_ENDWORD:
LOG("Exec: word-end (RETURN)");
w2 = &fh->dict[instr->data];
if (w2->builtin) {
LOG("Exec: builtin-word %s", w2->name);
w2->handler(fh, w2);
if (fh->substate == FH_SUBSTATE_EXIT) {
fh_setsubstate(fh, 0);
LOG("Exec: early return");
TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) {
goto end;
}
goto instr;
default:
w2 = &fh->dict[instr->data];
if (w2->builtin) {
LOG("Exec: builtin-word %s", w2->name);
w2->handler(fh, w2);
if (fh->substate == FH_SUBSTATE_EXIT) {
fh_setsubstate(fh, 0);
LOG("Exec: early return");
TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) {
goto end;
}
}
goto instr;
} else {
LOG("Exec: user-word %s (CALL)", w2->name);
w = &fh->dict[instr->data];
goto call;
}
}
goto instr;
} else {
LOG("Exec: user-word %s (CALL)", w2->name);
w = &fh->dict[instr->data];
goto call;
}
case FH_INSTR_JUMPZERO:
TRY(ds_pop(fh, &val));
if (0 == val) {
fh->execptr = instr->data;
}
goto instr;
case FH_INSTR_JUMP:
fh->execptr = instr->data;
goto instr;
/* 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) {
TRY(fh_heap_reserve(fh, strl, &addr));
fh_heap_copy_from_compile(fh, addr, fh->execptr, strl);
LOG("Exec: alloc-str \"%.*s\"", strl, &fh->heap[addr]);
TRY(ds_push(fh, addr));
TRY(ds_push(fh, strl));
} else {
LOG("Exec: type-str \"%.*s\"", strl, &fh->compile[fh->execptr]);
FHPRINT("%.*s", (int) strl, &fh->compile[fh->execptr]);
}
fh->execptr += strl;
goto instr;
case FH_INSTR_ENDWORD:
LOG("Exec: word-end (RETURN)");
TRY(rs_pop(fh, &fh->execptr));
if (fh->execptr == MAGICADDR_INTERACTIVE) {
goto end;
}
goto instr;
}
end:
@ -201,18 +207,12 @@ static enum fh_error fh_handle_quoted_string(
LOG("Compile a string");
/* compile */
if (fh->substate == FH_SUBSTATE_SQUOTE) {
instr_init(&instr, FH_INSTR_WORD, CPLWORD_ALLOCSTR);
instr_init(&instr, FH_INSTR_ALLOCSTR, len);
} else {
instr_init(&instr, FH_INSTR_WORD, CPLWORD_TYPESTR);
instr_init(&instr, FH_INSTR_TYPESTR, len);
}
uint32_t len32 = len;
/* string is encoded as a special compiler command, the size,
* and then the string, all 4-byte aligned. */
TRY(fh_compile_put(fh, &instr, INSTR_SIZE));
TRY(fh_compile_reserve(fh, len + 4, &addr));
fh_compile_write(fh, addr, &len32, 4);
fh_compile_write(fh, addr + 4, start, len);
TRY(fh_compile_put(fh, start, len));
}
return FH_OK;
}
@ -289,13 +289,12 @@ static enum fh_error fh_handle_word(
static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) {
if (w->handler == w_user_word) {
FHPRINT("addr 0x%08x ", w->start);
uint32_t execptr = w->start;
instr:;
// make sure it's aligned
execptr = WORDALIGNED(execptr);
FHPRINT("0x%08x: ", execptr);
const struct fh_instruction_s *instr = (const struct fh_instruction_s *) &fh->compile[execptr];
execptr += INSTR_SIZE;
@ -304,39 +303,39 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) {
const struct fh_word_s *w2;
switch (instr->kind) {
case FH_INSTR_NUMBER:
FHPRINT("Value(%d) ", instr->data);
FHPRINT("Number(%d)\n", instr->data);
goto instr;
case FH_INSTR_WORD:
wn = instr->data;
switch (wn) {
/* special case for strings stored in compile memory */
case CPLWORD_ALLOCSTR:
case CPLWORD_TYPESTR:
strl = *((uint32_t *) &fh->compile[execptr]);
execptr += 4; // advance past the length
if (wn == CPLWORD_ALLOCSTR) {
FHPRINT("AllocStr(\"%.*s\") ", strl, &fh->compile[execptr]);
execptr += strl;
} else {
FHPRINT("PrintStr(\"%.*s\") ", strl, &fh->compile[execptr]);
execptr += strl;
}
goto instr;
case CPLWORD_ENDWORD:
FHPRINT("END");
return;
default:
w2 = &fh->dict[instr->data];
if (w2->name[0]) {
FHPRINT("Call(%s) ", w2->name);
} else {
FHPRINT("Call(0x%08x) ", instr->data);
}
goto instr;
w2 = &fh->dict[instr->data];
FHPRINT("Call(%s, 0x%08x)\n", w2->name, instr->data);
goto instr;
case FH_INSTR_JUMPZERO:
FHPRINT("JumpIfZero(0x%08x)\n", instr->data);
goto instr;
case FH_INSTR_JUMP:
FHPRINT("Jump(0x%08x)\n", instr->data);
goto instr;
/* 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->compile[execptr]);
execptr += strl;
} else {
FHPRINT("PrintStr(\"%.*s\")\n", strl, &fh->compile[execptr]);
execptr += strl;
}
goto instr;
case FH_INSTR_ENDWORD:
FHPRINT("END\n");
return;
}
} else {

Loading…
Cancel
Save