|
|
|
#include <string.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include "fh_runtime.h"
|
|
|
|
#include "fh_config.h"
|
|
|
|
#include "fh_error.h"
|
|
|
|
#include "fh_print.h"
|
|
|
|
#include "fh_builtins.h"
|
|
|
|
#include "fh_stack.h"
|
|
|
|
#include "fh_mem.h"
|
|
|
|
|
|
|
|
static enum fh_error w_add(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0, b = 0;
|
|
|
|
TRY(ds_pop(fh, &a));
|
|
|
|
TRY(ds_pop(fh, &b));
|
|
|
|
TRY(ds_push(fh, a + b));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_sub(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0, b = 0;
|
|
|
|
TRY(ds_pop(fh, &a));
|
|
|
|
TRY(ds_pop(fh, &b));
|
|
|
|
TRY(ds_push(fh, a - b));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_mul(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0, b = 0;
|
|
|
|
TRY(ds_pop(fh, &a));
|
|
|
|
TRY(ds_pop(fh, &b));
|
|
|
|
TRY(ds_push(fh, a * b));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_colon(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
if (fh->state != FH_STATE_INTERPRET) {
|
|
|
|
return FH_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fh_setstate(fh, FH_STATE_COMPILE, FH_SUBSTATE_COLONNAME);
|
|
|
|
|
|
|
|
if (fh->dict_top >= DICT_SIZE) {
|
|
|
|
return FH_ERR_DICT_FULL;
|
|
|
|
}
|
|
|
|
fh->dict[fh->dict_top].start = fh->compile_top;
|
|
|
|
fh->dict[fh->dict_top].handler = w_user_word;
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_semicolon(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
struct fh_instruction_s instr;
|
|
|
|
|
|
|
|
if (fh->state != FH_STATE_COMPILE) {
|
|
|
|
return FH_ERR_INVALID_STATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
instr.kind = FH_INSTR_WORD;
|
|
|
|
instr.data = CPLWORD_ENDWORD;
|
|
|
|
TRY(fh_compile_put(fh, &instr, INSTR_SIZE));
|
|
|
|
|
|
|
|
/* Return to interpret state */
|
|
|
|
fh_setstate(fh, FH_STATE_INTERPRET, 0);
|
|
|
|
fh->dict_top++;
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_dup(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0;
|
|
|
|
TRY(ds_peek(fh, &a));
|
|
|
|
TRY(ds_push(fh, a));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_drop(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
TRY(ds_roll(fh, 1));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_rot(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
TRY(ds_roll(fh, 2));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_over(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0;
|
|
|
|
TRY(ds_peek_n(fh, &a, 1));
|
|
|
|
TRY(ds_push(fh, a));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_tuck(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0;
|
|
|
|
uint32_t b = 0;
|
|
|
|
TRY(ds_pop(fh, &a));
|
|
|
|
TRY(ds_pop(fh, &b));
|
|
|
|
TRY(ds_push(fh, a));
|
|
|
|
TRY(ds_push(fh, b));
|
|
|
|
TRY(ds_push(fh, a));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_pick(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t nth = 0;
|
|
|
|
uint32_t a = 0;
|
|
|
|
TRY(ds_pop(fh, &nth));
|
|
|
|
TRY(ds_peek_n(fh, &a, nth));
|
|
|
|
TRY(ds_push(fh, a));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_roll(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t n = 0;
|
|
|
|
TRY(ds_pop(fh, &n));
|
|
|
|
TRY(ds_roll(fh, n));
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_dot(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t a = 0;
|
|
|
|
TRY(ds_pop(fh, &a));
|
|
|
|
|
|
|
|
FHPRINT("%d ", (int32_t) a);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_type(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
enum fh_error rv;
|
|
|
|
uint32_t count = 0, addr = 0;
|
|
|
|
TRY(ds_pop(fh, &count));
|
|
|
|
TRY(ds_pop(fh, &addr));
|
|
|
|
|
|
|
|
FHPRINT("%.*s", count, &fh->heap[addr]);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_cr(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
(void) fh;
|
|
|
|
FHPRINT("\n");
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_space(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
(void) fh;
|
|
|
|
FHPRINT(" ");
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_dump(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
(void) fh;
|
|
|
|
for (int i = 0; i < fh->data_stack_top; i++) {
|
|
|
|
FHPRINT("%d ", fh->data_stack[i]);
|
|
|
|
}
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_s_quote(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_SQUOTE);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_dot_quote(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_DOTQUOTE);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_backslash(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_LINECOMMENT);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_paren(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
fh_setsubstate(fh, FH_SUBSTATE_PARENCOMMENT);
|
|
|
|
return FH_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static enum fh_error w_bye(struct fh_thread_s *fh)
|
|
|
|
{
|
|
|
|
fh_setstate(fh, FH_STATE_SHUTDOWN, 0);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
struct name_and_handler {
|
|
|
|
const char *name;
|
|
|
|
word_exec_t handler;
|
|
|
|
bool immediate;
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct name_and_handler builtins[] = {
|
|
|
|
{"s\"", w_s_quote, 1},
|
|
|
|
{".\"", w_dot_quote, 1},
|
|
|
|
/* Compiler control words */
|
|
|
|
{"bye", w_bye, 0},
|
|
|
|
/* Arithmetics */
|
|
|
|
{"+", w_add, 0},
|
|
|
|
{"-", w_sub, 0},
|
|
|
|
{"*", w_mul, 0},
|
|
|
|
/* 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},
|
|
|
|
/* 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
|
|
|
|
{ /* end marker */ }
|
|
|
|
};
|
|
|
|
|
|
|
|
// foreach
|
|
|
|
struct fh_word_s w;
|
|
|
|
const struct name_and_handler *p = builtins;
|
|
|
|
enum fh_error rv;
|
|
|
|
while (p->handler) {
|
|
|
|
strcpy(w.name, p->name);
|
|
|
|
w.handler = p->handler;
|
|
|
|
w.builtin = 1;
|
|
|
|
w.immediate = p->immediate;
|
|
|
|
rv = fh_add_word(&w, fh);
|
|
|
|
if (rv != FH_OK) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return FH_OK;
|
|
|
|
}
|