168 lines
4.5 KiB
C
168 lines
4.5 KiB
C
#define PRINT_ERRORS 0
|
|
|
|
#define NEXT w = *ip++; goto **(void **) w
|
|
#define CELL_LEN(n) (((n) + sizeof(cell_t) - 1) / sizeof(cell_t))
|
|
#define FIND(name) find(name, sizeof(name) - 1)
|
|
#define LOWER(ch) ((ch) & 0x5F)
|
|
|
|
#if PRINT_ERRORS
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
static struct {
|
|
const char *tib;
|
|
cell_t ntib, tin, state, base;
|
|
cell_t *heap, *last, notfound;
|
|
int argc;
|
|
char **argv;
|
|
cell_t DOLIT_XT, DOEXIT_XT, YIELD_XT;
|
|
cell_t *ip, *sp, *rp; // Parked alternates
|
|
} g_sys;
|
|
|
|
static cell_t convert(const char *pos, cell_t n, cell_t *ret) {
|
|
*ret = 0;
|
|
cell_t negate = 0;
|
|
cell_t base = g_sys.base;
|
|
if (!n) { return 0; }
|
|
if (pos[0] == '-') { negate = -1; ++pos; --n; }
|
|
if (pos[0] == '$') { base = 16; ++pos; --n; }
|
|
for (; n; --n) {
|
|
uintptr_t d = pos[0] - '0';
|
|
if (d > 9) {
|
|
d = LOWER(d) - 7;
|
|
if (d < 10) { return 0; }
|
|
}
|
|
if (d >= base) { return 0; }
|
|
*ret = *ret * base + d;
|
|
++pos;
|
|
}
|
|
if (negate) { *ret = -*ret; }
|
|
return -1;
|
|
}
|
|
|
|
static cell_t same(const char *a, const char *b, cell_t len) {
|
|
for (;len && LOWER(*a) == LOWER(*b); --len, ++a, ++b);
|
|
return len;
|
|
}
|
|
|
|
static cell_t find(const char *name, cell_t len) {
|
|
cell_t *pos = g_sys.last;
|
|
cell_t clen = CELL_LEN(len);
|
|
while (pos) {
|
|
if (len == pos[-3] &&
|
|
same(name, (const char *) &pos[-3 - clen], len) == 0) {
|
|
return (cell_t) pos;
|
|
}
|
|
pos = (cell_t *) pos[-2]; // Follow link
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void create(const char *name, cell_t length, cell_t flags, void *op) {
|
|
char *pos = (char *) g_sys.heap;
|
|
for (cell_t n = length; n; --n) { *pos++ = *name++; } // name
|
|
g_sys.heap += CELL_LEN(length);
|
|
*g_sys.heap++ = length; // length
|
|
*g_sys.heap++ = (cell_t) g_sys.last; // link
|
|
*g_sys.heap++ = flags; // flags
|
|
g_sys.last = g_sys.heap;
|
|
*g_sys.heap++ = (cell_t) op; // code
|
|
}
|
|
|
|
static char spacefilter(char ch) {
|
|
return ch == '\t' || ch == '\n' || ch == '\r' ? ' ' : ch;
|
|
}
|
|
|
|
static cell_t parse(cell_t sep, cell_t *ret) {
|
|
while (g_sys.tin < g_sys.ntib &&
|
|
spacefilter(g_sys.tib[g_sys.tin]) == sep) { ++g_sys.tin; }
|
|
*ret = (cell_t) (g_sys.tib + g_sys.tin);
|
|
while (g_sys.tin < g_sys.ntib &&
|
|
spacefilter(g_sys.tib[g_sys.tin]) != sep) { ++g_sys.tin; }
|
|
cell_t len = g_sys.tin - (*ret - (cell_t) g_sys.tib);
|
|
if (g_sys.tin < g_sys.ntib) { ++g_sys.tin; }
|
|
return len;
|
|
}
|
|
|
|
static cell_t *evaluate1(cell_t *sp) {
|
|
cell_t call = 0;
|
|
cell_t name;
|
|
cell_t len = parse(' ', &name);
|
|
cell_t xt = find((const char *) name, len);
|
|
if (xt) {
|
|
if (g_sys.state && !(((cell_t *) xt)[-1] & 1)) { // bit 0 of flags is immediate
|
|
*g_sys.heap++ = xt;
|
|
} else {
|
|
call = xt;
|
|
}
|
|
} else {
|
|
cell_t n;
|
|
cell_t ok = convert((const char *) name, len, &n);
|
|
if (ok) {
|
|
if (g_sys.state) {
|
|
*g_sys.heap++ = g_sys.DOLIT_XT;
|
|
*g_sys.heap++ = n;
|
|
} else {
|
|
*++sp = n;
|
|
}
|
|
} else {
|
|
#if PRINT_ERRORS
|
|
write(2, (void *) name, len);
|
|
write(2, "\n", 1);
|
|
#endif
|
|
*++sp = name;
|
|
*++sp = len;
|
|
*++sp = -1;
|
|
call = g_sys.notfound;
|
|
}
|
|
}
|
|
*++sp = call;
|
|
return sp;
|
|
}
|
|
|
|
static void ueforth_run() {
|
|
if (!g_sys.ip) {
|
|
#define X(name, op, code) create(name, sizeof(name) - 1, name[0] == ';', && OP_ ## op);
|
|
PLATFORM_OPCODE_LIST
|
|
OPCODE_LIST
|
|
#undef X
|
|
return;
|
|
}
|
|
register cell_t *ip = g_sys.ip, *rp = g_sys.rp, *sp = g_sys.sp, tos, w;
|
|
DROP; NEXT;
|
|
#define X(name, op, code) OP_ ## op: { code; } NEXT;
|
|
PLATFORM_OPCODE_LIST
|
|
OPCODE_LIST
|
|
#undef X
|
|
OP_DOCOLON: ++rp; *rp = (cell_t) ip; ip = (cell_t *) (w + sizeof(cell_t)); NEXT;
|
|
OP_DOCREATE: DUP; tos = w + sizeof(cell_t) * 2; NEXT;
|
|
OP_DODOES: DUP; tos = w + sizeof(cell_t) * 2;
|
|
++rp; *rp = (cell_t) ip; ip = (cell_t *) *(cell_t *) (w + sizeof(cell_t)); NEXT;
|
|
}
|
|
|
|
static void ueforth(int argc, char *argv[], void *heap,
|
|
const char *src, cell_t src_len) {
|
|
g_sys.ip = 0;
|
|
g_sys.heap = (cell_t *) heap + 4; // Leave a little room.
|
|
ueforth_run();
|
|
g_sys.sp = g_sys.heap + 1; g_sys.heap += STACK_SIZE;
|
|
g_sys.rp = g_sys.heap + 1; g_sys.heap += STACK_SIZE;
|
|
g_sys.last[-1] = 1; // Make ; IMMEDIATE
|
|
g_sys.DOLIT_XT = FIND("DOLIT");
|
|
g_sys.DOEXIT_XT = FIND("EXIT");
|
|
g_sys.YIELD_XT = FIND("YIELD");
|
|
g_sys.notfound = FIND("DROP");
|
|
g_sys.ip = g_sys.heap;
|
|
*g_sys.heap++ = FIND("EVALUATE1");
|
|
*g_sys.heap++ = FIND("BRANCH");
|
|
*g_sys.heap++ = (cell_t) g_sys.ip;
|
|
g_sys.argc = argc;
|
|
g_sys.argv = argv;
|
|
g_sys.base = 10;
|
|
g_sys.tib = src;
|
|
g_sys.ntib = src_len;
|
|
for (;;) {
|
|
ueforth_run();
|
|
}
|
|
}
|