|
|
@ -37,10 +37,19 @@ static const char *substatenames[FH_SUBSTATE_MAX] = { |
|
|
|
/** Add a word to the dictionary. */ |
|
|
|
/** Add a word to the dictionary. */ |
|
|
|
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) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (fh->dict_top == DICT_SIZE) { |
|
|
|
enum fh_error rv; |
|
|
|
return FH_ERR_DICT_FULL; |
|
|
|
|
|
|
|
} |
|
|
|
fh_align(fh); |
|
|
|
memcpy(&fh->dict[fh->dict_top++], w, sizeof(struct fh_word_s)); |
|
|
|
uint32_t ptr = fh->here; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TRY(fh_heap_put(fh, w, DICTWORD_SIZE)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//LOG("Added word \"%s\" at 0x%08x", w->name, ptr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// thread it onto the linked list
|
|
|
|
|
|
|
|
fh_word_at(fh, ptr)->previous = fh->dict_last; |
|
|
|
|
|
|
|
fh->dict_last = ptr; |
|
|
|
|
|
|
|
|
|
|
|
return FH_OK; |
|
|
|
return FH_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -83,7 +92,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) |
|
|
|
LOG("Run user word: %s", w->name); |
|
|
|
LOG("Run user word: %s", w->name); |
|
|
|
|
|
|
|
|
|
|
|
TRY(rs_push(fh, fh->execptr)); |
|
|
|
TRY(rs_push(fh, fh->execptr)); |
|
|
|
fh->execptr = w->start; |
|
|
|
fh->execptr = w->param; |
|
|
|
|
|
|
|
|
|
|
|
instr:; |
|
|
|
instr:; |
|
|
|
if (fh->state == FH_STATE_QUIT) { |
|
|
|
if (fh->state == FH_STATE_QUIT) { |
|
|
@ -108,8 +117,8 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) |
|
|
|
|
|
|
|
|
|
|
|
case FH_INSTR_POSTPONED_WORD: |
|
|
|
case FH_INSTR_POSTPONED_WORD: |
|
|
|
if (fh->state == FH_STATE_COMPILE) { |
|
|
|
if (fh->state == FH_STATE_COMPILE) { |
|
|
|
w2 = &fh->dict[instr->data]; |
|
|
|
w2 = fh_word_at(fh, instr->data); |
|
|
|
if (w2->immediate) { |
|
|
|
if (w2->flags & WORDFLAG_IMMEDIATE) { |
|
|
|
LOG("Call immediate postponed word: %s", w2->name); |
|
|
|
LOG("Call immediate postponed word: %s", w2->name); |
|
|
|
TRY(w2->handler(fh, w2)); |
|
|
|
TRY(w2->handler(fh, w2)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -124,8 +133,8 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) |
|
|
|
goto instr; |
|
|
|
goto instr; |
|
|
|
|
|
|
|
|
|
|
|
case FH_INSTR_WORD: |
|
|
|
case FH_INSTR_WORD: |
|
|
|
w2 = &fh->dict[instr->data]; |
|
|
|
w2 = fh_word_at(fh, instr->data); |
|
|
|
if (w2->builtin) { |
|
|
|
if (w2->flags & WORDFLAG_BUILTIN) { |
|
|
|
LOG("Exec: builtin-word \"%s\"", w2->name); |
|
|
|
LOG("Exec: builtin-word \"%s\"", w2->name); |
|
|
|
w2->handler(fh, w2); |
|
|
|
w2->handler(fh, w2); |
|
|
|
if (fh->substate == FH_SUBSTATE_EXIT) { |
|
|
|
if (fh->substate == FH_SUBSTATE_EXIT) { |
|
|
@ -139,7 +148,7 @@ enum fh_error w_user_word(struct fh_thread_s *fh, const struct fh_word_s *w0) |
|
|
|
goto instr; |
|
|
|
goto instr; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
LOG("Exec: user-word %s (CALL)", w2->name); |
|
|
|
LOG("Exec: user-word %s (CALL)", w2->name); |
|
|
|
w = &fh->dict[instr->data]; |
|
|
|
w = fh_word_at(fh, instr->data); |
|
|
|
goto call; |
|
|
|
goto call; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -202,6 +211,7 @@ enum fh_error fh_init(struct fh_thread_s *fh) |
|
|
|
/* Make sure we have a clean state */ |
|
|
|
/* Make sure we have a clean state */ |
|
|
|
memset(fh, 0, sizeof(struct fh_thread_s)); |
|
|
|
memset(fh, 0, sizeof(struct fh_thread_s)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fh->dict_last = MAGICADDR_DICTFIRST; |
|
|
|
TRY(register_builtin_words(fh)); |
|
|
|
TRY(register_builtin_words(fh)); |
|
|
|
|
|
|
|
|
|
|
|
fh->execptr = MAGICADDR_INTERACTIVE; |
|
|
|
fh->execptr = MAGICADDR_INTERACTIVE; |
|
|
@ -248,13 +258,14 @@ static enum fh_error fh_handle_quoted_string( |
|
|
|
return FH_OK; |
|
|
|
return FH_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
enum fh_error fh_handle_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
enum fh_error fh_handle_word(struct fh_thread_s *fh, uint32_t addr) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct fh_instruction_s instr; |
|
|
|
struct fh_instruction_s instr; |
|
|
|
enum fh_error rv; |
|
|
|
enum fh_error rv; |
|
|
|
if (fh->state == FH_STATE_COMPILE && !w->immediate) { |
|
|
|
struct fh_word_s *w = fh_word_at(fh, addr); |
|
|
|
|
|
|
|
if (fh->state == FH_STATE_COMPILE && 0 == (w->flags & WORDFLAG_IMMEDIATE)) { |
|
|
|
LOG("Compile word call: %s", w->name); |
|
|
|
LOG("Compile word call: %s", w->name); |
|
|
|
instr_init(&instr, FH_INSTR_WORD, w->index); |
|
|
|
instr_init(&instr, FH_INSTR_WORD, addr); |
|
|
|
TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); |
|
|
|
TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* interpret or immediate in compiled code */ |
|
|
|
/* interpret or immediate in compiled code */ |
|
|
@ -264,16 +275,18 @@ enum fh_error fh_handle_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
return FH_OK; |
|
|
|
return FH_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct fh_word_s *find_word(struct fh_thread_s *fh, const char *name, const size_t wordlen) |
|
|
|
static struct fh_word_s *find_word(struct fh_thread_s *fh, const char *name, const size_t wordlen, uint32_t *addr_out) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct fh_word_s *w = &fh->dict[0]; |
|
|
|
uint32_t addr = fh->dict_last; |
|
|
|
uint32_t cnt = 0; |
|
|
|
while (addr != MAGICADDR_DICTFIRST) { |
|
|
|
while (w->handler) { |
|
|
|
struct fh_word_s *w = fh_word_at(fh, addr); |
|
|
|
if (0 == strncasecmp(name, w->name, wordlen) && w->name[wordlen] == 0) { |
|
|
|
if (0 == strncasecmp(name, w->name, wordlen) && w->name[wordlen] == 0) { |
|
|
|
|
|
|
|
if (addr_out) { |
|
|
|
|
|
|
|
*addr_out = addr; |
|
|
|
|
|
|
|
} |
|
|
|
return w; |
|
|
|
return w; |
|
|
|
} |
|
|
|
} |
|
|
|
w++; |
|
|
|
addr = w->previous; |
|
|
|
cnt++; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
@ -292,9 +305,10 @@ enum fh_error fh_handle_ascii_word( |
|
|
|
|
|
|
|
|
|
|
|
/* First, try if it's a known word */ |
|
|
|
/* First, try if it's a known word */ |
|
|
|
|
|
|
|
|
|
|
|
struct fh_word_s *w = find_word(fh, name, wordlen); |
|
|
|
uint32_t wadr = MAGICADDR_UNRESOLVED; |
|
|
|
if (w) {// word found!
|
|
|
|
find_word(fh, name, wordlen, &wadr); |
|
|
|
TRY(fh_handle_word(fh, w)); |
|
|
|
if (wadr != MAGICADDR_UNRESOLVED) { |
|
|
|
|
|
|
|
TRY(fh_handle_word(fh, wadr)); |
|
|
|
return FH_OK; |
|
|
|
return FH_OK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -316,7 +330,7 @@ enum fh_error fh_handle_ascii_word( |
|
|
|
|
|
|
|
|
|
|
|
long v = strtol(name, &endptr, base); // XXX if base is 0, this will use auto-detection
|
|
|
|
long v = strtol(name, &endptr, base); // XXX if base is 0, this will use auto-detection
|
|
|
|
if (errno != 0 || (endptr - name) != wordlen) { |
|
|
|
if (errno != 0 || (endptr - name) != wordlen) { |
|
|
|
LOGE("Unknown word and fail to parse as number: %.*s", (int) wordlen, name); |
|
|
|
LOGE("Unknown word and fail to parse as number: \"%.*s\"", (int) wordlen, name); |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -337,7 +351,7 @@ enum fh_error fh_handle_ascii_word( |
|
|
|
static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (w->handler == w_user_word) { |
|
|
|
if (w->handler == w_user_word) { |
|
|
|
uint32_t execptr = w->start; |
|
|
|
uint32_t execptr = w->param; |
|
|
|
|
|
|
|
|
|
|
|
instr:; |
|
|
|
instr:; |
|
|
|
// make sure it's aligned
|
|
|
|
// make sure it's aligned
|
|
|
@ -355,7 +369,7 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
goto instr; |
|
|
|
goto instr; |
|
|
|
|
|
|
|
|
|
|
|
case FH_INSTR_WORD: |
|
|
|
case FH_INSTR_WORD: |
|
|
|
w2 = &fh->dict[instr->data]; |
|
|
|
w2 = fh_word_at(fh, instr->data); |
|
|
|
if (w2->name[0]) { |
|
|
|
if (w2->name[0]) { |
|
|
|
FHPRINT("Call(%s)\n", w2->name); |
|
|
|
FHPRINT("Call(%s)\n", w2->name); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -364,7 +378,7 @@ static void show_word(struct fh_thread_s *fh, const struct fh_word_s *w) |
|
|
|
goto instr; |
|
|
|
goto instr; |
|
|
|
|
|
|
|
|
|
|
|
case FH_INSTR_POSTPONED_WORD: |
|
|
|
case FH_INSTR_POSTPONED_WORD: |
|
|
|
w2 = &fh->dict[instr->data]; |
|
|
|
w2 = fh_word_at(fh, instr->data); |
|
|
|
if (w2->name[0]) { |
|
|
|
if (w2->name[0]) { |
|
|
|
FHPRINT("Postpone(%s)\n", w2->name); |
|
|
|
FHPRINT("Postpone(%s)\n", w2->name); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -410,7 +424,7 @@ static enum fh_error fh_see_word( |
|
|
|
const size_t wordlen |
|
|
|
const size_t wordlen |
|
|
|
) |
|
|
|
) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct fh_word_s *w = find_word(fh, name, wordlen); |
|
|
|
struct fh_word_s *w = find_word(fh, name, wordlen, NULL); |
|
|
|
if (!w) { |
|
|
|
if (!w) { |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
} |
|
|
|
} |
|
|
@ -425,7 +439,8 @@ static enum fh_error fh_postpone_word( |
|
|
|
const size_t wordlen |
|
|
|
const size_t wordlen |
|
|
|
) |
|
|
|
) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct fh_word_s *w = find_word(fh, name, wordlen); |
|
|
|
uint32_t wadr; |
|
|
|
|
|
|
|
struct fh_word_s *w = find_word(fh, name, wordlen, &wadr); |
|
|
|
if (!w) { |
|
|
|
if (!w) { |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
return FH_ERR_UNKNOWN_WORD; |
|
|
|
} |
|
|
|
} |
|
|
@ -433,7 +448,7 @@ static enum fh_error fh_postpone_word( |
|
|
|
enum fh_error rv; |
|
|
|
enum fh_error rv; |
|
|
|
struct fh_instruction_s instr; |
|
|
|
struct fh_instruction_s instr; |
|
|
|
LOG("Postpone %s", w->name); |
|
|
|
LOG("Postpone %s", w->name); |
|
|
|
instr_init(&instr, FH_INSTR_POSTPONED_WORD, w->index); |
|
|
|
instr_init(&instr, FH_INSTR_POSTPONED_WORD, wadr); |
|
|
|
TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); |
|
|
|
TRY(fh_heap_put(fh, &instr, INSTR_SIZE)); |
|
|
|
|
|
|
|
|
|
|
|
return FH_OK; |
|
|
|
return FH_OK; |
|
|
@ -491,7 +506,7 @@ enum fh_error fh_process_line(struct fh_thread_s *fh, const char *linebuf) |
|
|
|
case FH_SUBSTATE_COLON_NAME: |
|
|
|
case FH_SUBSTATE_COLON_NAME: |
|
|
|
/* new word's name is found */ |
|
|
|
/* new word's name is found */ |
|
|
|
LOG("New word name = \"%.*s\"", (int) length, rp); |
|
|
|
LOG("New word name = \"%.*s\"", (int) length, rp); |
|
|
|
strncpy(fh->dict[fh->dict_top].name, rp, length); |
|
|
|
strncpy(fh_word_at(fh, fh->dict_last)->name, rp, length); |
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_NONE); |
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_NONE); |
|
|
|
break; |
|
|
|
break; |
|
|
|
case FH_SUBSTATE_SEE_NAME: |
|
|
|
case FH_SUBSTATE_SEE_NAME: |
|
|
|