Trying to build a forth runtime in C
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
forth/src/fh_builtins.c

750 lines
17 KiB

3 years ago
#include <string.h>
#include <stdbool.h>
3 years ago
#include "fh_runtime.h"
#include "fh_config.h"
#include "fh_error.h"
#include "fh_print.h"
3 years ago
#include "fh_builtins.h"
#include "fh_stack.h"
#include "fh_mem.h"
3 years ago
#define TOBOOL(a) (a == 0 ? 0 : 0xFFFFFFFF)
static enum fh_error w_plus(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
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;
}
3 years ago
static enum fh_error w_minus(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
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;
}
3 years ago
static enum fh_error w_star(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
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;
}
3 years ago
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)
3 years ago
{
3 years ago
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;
3 years ago
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;
}
3 years ago
static enum fh_error w_semicolon(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
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;
}
3 years ago
static enum fh_error w_dup(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
enum fh_error rv;
uint32_t a = 0;
TRY(ds_peek(fh, &a));
TRY(ds_push(fh, a));
return FH_OK;
}
3 years ago
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)
{
3 years ago
(void) w;
enum fh_error rv;
uint32_t a = 0;
TRY(ds_pop(fh, &a));
3 years ago
TRY(ds_pop(fh, &a));
return FH_OK;
}
3 years ago
static enum fh_error w_swap(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
enum fh_error rv;
TRY(ds_roll(fh, 1));
return FH_OK;
}
3 years ago
static enum fh_error w_two_swap(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(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;
}
3 years ago
static enum fh_error w_over(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
enum fh_error rv;
uint32_t a = 0;
TRY(ds_peek_n(fh, &a, 1));
TRY(ds_push(fh, a));
return FH_OK;
}
3 years ago
static enum fh_error w_two_over(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(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;
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;
}
3 years ago
static enum fh_error w_pick(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
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;
}
3 years ago
static enum fh_error w_roll(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
enum fh_error rv;
uint32_t n = 0;
TRY(ds_pop(fh, &n));
TRY(ds_roll(fh, n));
return FH_OK;
}
3 years ago
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)
3 years ago
{
3 years ago
(void) w;
3 years ago
enum fh_error rv;
uint32_t a = 0;
TRY(ds_pop(fh, &a));
FHPRINT("%d ", (int32_t) a);
return FH_OK;
}
3 years ago
static enum fh_error w_type(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
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;
}
3 years ago
static enum fh_error w_cr(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
(void) fh;
FHPRINT("\n");
return FH_OK;
}
3 years ago
static enum fh_error w_space(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
(void) fh;
FHPRINT(" ");
return FH_OK;
}
3 years ago
static enum fh_error w_dump(struct fh_thread_s *fh, const struct fh_word_s *w)
{
3 years ago
(void) w;
(void) fh;
3 years ago
FHPRINT("DS ");
for (int i = 0; i < fh->data_stack_top; i++) {
FHPRINT("%d ", fh->data_stack[i]);
}
3 years ago
FHPRINT("\nRS ");
for (int i = 0; i < fh->return_stack_top; i++) {
FHPRINT("%d ", fh->return_stack[i]);
}
FHPRINT("\n");
return FH_OK;
}
3 years ago
static enum fh_error w_abort(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
fh->data_stack_top = 0;
fh->return_stack_top = 0;
3 years ago
fh_setstate(fh, FH_STATE_QUIT, 0);
3 years ago
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;
3 years ago
fh_setstate(fh, FH_STATE_QUIT, 0);
return FH_OK;
}
static enum fh_error w_exit(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
fh_setsubstate(fh, FH_SUBSTATE_EXIT);
3 years ago
return FH_OK;
}
static enum fh_error w_s_quote(struct fh_thread_s *fh, const struct fh_word_s *w)
{
(void) w;
3 years ago
fh_setsubstate(fh, FH_SUBSTATE_SQUOTE);
return FH_OK;
}
3 years ago
static enum fh_error w_dot_quote(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
fh_setsubstate(fh, FH_SUBSTATE_DOTQUOTE);
return FH_OK;
}
3 years ago
static enum fh_error w_backslash(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
fh_setsubstate(fh, FH_SUBSTATE_LINECOMMENT);
return FH_OK;
}
3 years ago
static enum fh_error w_paren(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
fh_setsubstate(fh, FH_SUBSTATE_PARENCOMMENT);
return FH_OK;
}
3 years ago
static enum fh_error w_bye(struct fh_thread_s *fh, const struct fh_word_s *w)
3 years ago
{
3 years ago
(void) w;
3 years ago
fh_setstate(fh, FH_STATE_SHUTDOWN, 0);
return FH_OK;
}
3 years ago
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;
}
3 years ago
/** 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;
3 years ago
uint32_t param;
3 years ago
};
const struct name_and_handler builtins[] = {
3 years ago
{"s\"", w_s_quote, 1, 0},
{".\"", w_dot_quote, 1, 0},
3 years ago
/* Compiler control words */
3 years ago
{"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 */
3 years ago
{"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 */
3 years ago
{"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 */
3 years ago
{".", 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 */
3 years ago
{"abort", w_abort, 0, 0},
3 years ago
{"quit", w_quit, 0, 0},
3 years ago
{"exit", w_exit, 0, 0},
3 years ago
/* Syntax */
{":", w_colon, 0, 0},
{";", w_semicolon, 1, 0},
{"\\", w_backslash, 1, 0}, // line comment
{"(", w_paren, 1, 0}, // enclosed comment
3 years ago
{ /* 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;
3 years ago
w.param = p->param;
3 years ago
rv = fh_add_word(&w, fh);
if (rv != FH_OK) {
return rv;
}
p++;
}
return FH_OK;
}