pete286/forp.c

410 lines
6.8 KiB
C
Executable file

#include <stdio.h>
#define MEM_SIZE 16384
#define STACK_SIZE 64
#define RSTACK_SIZE 32
union cell_union;
typedef union cell_union cell;
union cell_union {
int i;
unsigned int u;
cell *p;
char *s;
void (*f)();
};
char mem[MEM_SIZE];
cell *HERE = (cell*)mem;
cell *LATEST = NULL;
cell IP = NULL;
cell W = NULL;
cell STATE = 0;
cell rstack_mem[RSTACK_SIZE];
cell *rstack = rstack_mem;
cell stack_mem[STACK_SIZE];
cell *stack = stack_mem;
char *INPUT = NULL;
#define F_IMMEDIATE 0x80
#define CELL_OFFSET(cp, b) ((cell*)(((char *)(cp)) + b))
#define TOP() (*(stack - 1))
#define ST1() (*(stack - 2))
#define ST2() (*(stack - 3))
#define DROP(n) (stack -= n)
void PUSHC(cell c) { *stack = c; stack++; }
void PUSHI(int i) { stack->i = i; stack++; }
void PUSHU(unsigned int u) { stack->u = u; stack++; }
void PUSHCP(cell *c) { stack->p = c; stack++; }
#define PUSHP(p) PUSHCP((cell*)p)
void PUSHS(char *s) { stack->s = s; stack++; }
void RPUSH(cell c) { *rstack = c; rstack++; }
#define RPOP() (--rstack)
void f_add() {
cell r = TOP();
DROP(1);
TOP().i += r.i;
}
void f_sub() {
cell r = TOP();
DROP(1);
TOP().i -= r.i;
}
void f_get() {
TOP() = (*(TOP().p));
}
void f_set() {
cell *p = TOP().p;
DROP(1);
(*p) = TOP();
}
void f_drop() {
DROP(1);
}
void f_dup() {
PUSHC(TOP());
}
void f_swap() {
cell top = ST1();
cell st1 = TOP();
ST1() = st1;
TOP() = top;
}
void f_rot() { // a b c -- b c a
cell c = TOP();
cell b = ST1();
cell a = ST2();
TOP() = a;
ST1() = c;
ST2() = b;
}
void f_key() {
if (INPUT) {
PUSHI(*INPUT);
INPUT++;
if (TOP().i == 0) {
INPUT = NULL;
}
} else {
PUSHI(0);
}
}
void f_word() {
static char buf[32] = {0};
int key = ' ';
int ibuf = 0;
while (key == ' ' || key == '\n' || key == '\r') {
f_key();
key = TOP().i;
DROP(1);
}
while (key != ' ' && key != '\n' && key != '\r' && key != 0) {
buf[ibuf++] = key;
f_key();
key = TOP().i;
DROP(1);
}
buf[ibuf] = 0;
PUSHS(buf);
}
void f_emit() {
printf("%c", TOP().i);
DROP(1);
}
void f_dot() {
printf("%d ", TOP().i);
DROP(1);
}
void f_puts() {
printf("%s", TOP().s);
DROP(1);
}
void f_cr() {
PUSHI('\n');
f_emit();
}
void f_comma() {
*HERE++ = TOP();
DROP(1);
}
void f_create() { // name --
int namelen;
HERE->p = LATEST;
LATEST = HERE;
HERE++;
namelen = strlen(TOP().s);
HERE->u = namelen; HERE ++;
memcpy(HERE, TOP().s, namelen + 1);
HERE = CELL_OFFSET(HERE, namelen + 1);
DROP(1);
}
void f_cdef() { // func name --
f_create();
HERE->p = TOP().p;
HERE ++;
DROP(1);
}
void f_docolon() {
RPUSH(W);
IP.p = W.p + 1;
while (rstack != rstack_mem) {
cell codeptr;
W = *IP.p;
IP.p++;
codeptr = *W.p;
if (codeptr.f == f_docolon) {
RPUSH(IP);
IP.p = W.p + 1;
} else {
codeptr.f();
}
}
}
void f_noop() {
}
void f_donumber() {
PUSHC(*IP.p);
IP.p++;
}
void f_number() { // str -- num isnum
int num = 0, result;
result = sscanf(TOP().s, "%d", &num);
TOP().i = num;
PUSHI(result == 1);
}
void f_streq() {
int result = strcmp(TOP().s, ST1().s);
DROP(1);
TOP().i = result == 0;
}
void f_lookup() { // name -- (codepointer flags) | (name 0)
cell *entry = LATEST;
while (entry) {
f_dup();
PUSHP(entry + 2);
f_streq();
if (TOP().i) {
unsigned int flags = entry[1].u;
TOP().u = flags;
ST1().p = CELL_OFFSET(entry + 2, (flags & ~F_IMMEDIATE) + 1);
return;
}
DROP(1);
entry = entry->p;
}
PUSHU(0);
}
void f_compileon() {
STATE.i = 1;
}
void f_compileoff() {
STATE.i = 0;
}
void f_immediate() {
cell *flags = LATEST + 1;
flags->u |= F_IMMEDIATE;
}
void f_semicolon() {
PUSHS("_RET");
f_lookup();
DROP(1);
f_comma();
f_compileoff();
}
void f_ret() {
IP = *RPOP();
}
void f_colon() {
f_word();
f_create();
PUSHP(f_docolon);
f_comma();
f_compileon();
}
void f_interpretword() { // codefield flags --
if (!STATE.i || (TOP().u & F_IMMEDIATE)) {
DROP(1);
W = TOP(); // w code
DROP(1);
W.p->f();
} else {
DROP(1);
f_comma();
}
}
void f_interpretnumber() { // number --
if (STATE.i) {
PUSHS("_DONUMBER");
f_lookup();
DROP(1);
f_comma();
f_comma();
}
}
void f_interpretunknown() { // name --
f_puts();
PUSHS("?\n");
f_puts();
}
void f_compileword() { // name --
f_lookup();
if (!TOP().u) { // name 0
DROP(1); // name
f_dup(); // name name
f_number(); // name n isnum
if (TOP().i) {
f_rot(); // name n isnum -- n isnum name
DROP(2); // n isnum w -- n
f_interpretnumber();
} else {
DROP(2); // name
f_interpretunknown();
}
} else { // codepointer flags
f_interpretword();
}
}
void f_interpret(char *input) {
INPUT = input;
while(1) {
f_word(); // w
if (TOP().s[0] == '\0') {
PUSHS("ok\n");
f_puts();
DROP(1);
return;
}
f_compileword();
if (stack < stack_mem) {
stack = stack_mem;
PUSHS("stack underflow!\n");
f_puts();
return;
}
}
}
void f_if() {
if (STATE.i) {
PUSHC(W);
f_comma();
PUSHP(HERE);
PUSHP(NULL);
f_comma();
} else {
if (TOP().u) {
IP.p ++;
} else {
IP.p = IP.p->p; // skip to then
}
DROP(1);
}
}
void f_else() {
if (STATE.i) {
PUSHC(W);
f_comma();
TOP().p->p = HERE + 1;
TOP().p = HERE;
PUSHP(NULL);
f_comma();
} else {
IP.p = IP.p->p;
}
}
void f_then() {
TOP().p->p = HERE;
DROP(1);
}
int DIE = 0;
void f_quit() {
DIE = 1;
}
#define CDEF(name, def) PUSHP(def); PUSHS(name); f_cdef()
void f_init() {
CDEF("[", f_compileoff); f_immediate();
CDEF("]", f_compileon);
CDEF("immediate", f_immediate);
CDEF("create", f_create);
CDEF(":", f_colon);
CDEF(";", f_semicolon); f_immediate();
CDEF("+", f_add);
CDEF("-", f_sub);
CDEF("@", f_get);
CDEF("!", f_set);
CDEF("if", f_if); f_immediate();
CDEF("else", f_else); f_immediate();
CDEF("then", f_then); f_immediate();
CDEF("dup", f_dup);
CDEF("drop", f_drop);
CDEF("swap", f_drop);
CDEF("rot", f_rot);
CDEF("emit", f_emit);
CDEF("number", f_number);
CDEF("_DONUMBER", f_donumber);
CDEF("_RET", f_ret);
CDEF(".", f_dot);
CDEF(".s", f_puts);
CDEF(",", f_comma);
CDEF("noop", f_noop);
CDEF("quit", f_quit);
f_interpret(": -rot rot rot ;");
}
int main() {
char inputbuf[256];
f_init();
while (!DIE) {
f_interpret(gets(inputbuf));
}
return 0;
}