From 769bb9e9aa78095631e994114d21f9ace00f0c1f Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Fri, 1 Feb 2019 19:05:02 -0500 Subject: [PATCH] Forp: Rewrite if/else/then in Forth --- forp.c | 145 +++++++++++++++++++++++++++++++++++++------------------ forp.exe | Bin 35752 -> 37047 bytes 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/forp.c b/forp.c index 3be75fe..1f4ab57 100755 --- a/forp.c +++ b/forp.c @@ -44,6 +44,18 @@ void PUSHS(char *s) { stack->s = s; stack++; } void RPUSH(cell c) { *rstack = c; rstack++; } #define RPOP() (--rstack) +void f_here() { + PUSHCP(HERE); +} + +void f_latest() { + PUSHCP(LATEST); +} + +void f_state() { + PUSHC(STATE); +} + void f_add() { cell r = TOP(); DROP(1); @@ -64,6 +76,7 @@ void f_set() { cell *p = TOP().p; DROP(1); (*p) = TOP(); + DROP(1); } void f_drop() { @@ -75,10 +88,10 @@ void f_dup() { } void f_swap() { - cell top = ST1(); - cell st1 = TOP(); - ST1() = st1; - TOP() = top; + cell top = TOP(); + cell st1 = ST1(); + TOP() = st1; + ST1() = top; } void f_rot() { // a b c -- b c a @@ -128,16 +141,24 @@ void f_emit() { DROP(1); } -void f_dot() { - printf("%d ", TOP().i); +void f_puts() { + char *s = TOP().s; + while (s && *s) { + PUSHI(*s); + f_emit(); + s++; + } DROP(1); } -void f_puts() { - printf("%s", TOP().s); - DROP(1); +void f_dot() { + static char num[16]; + sprintf(num, "%d ", TOP().i); + TOP().s = num; + f_puts(); } + void f_cr() { PUSHI('\n'); f_emit(); @@ -189,7 +210,7 @@ void f_docolon() { void f_noop() { } -void f_donumber() { +void f_push_() { PUSHC(*IP.p); IP.p++; } @@ -225,6 +246,21 @@ void f_lookup() { // name -- (codepointer flags) | (name 0) PUSHU(0); } +void f_revlookup() { // codepointer -- name + cell *entry = LATEST; + while (entry) { + unsigned int length = entry[1].u & ~F_IMMEDIATE; + cell *name = entry + 2; + cell *cp = CELL_OFFSET(name, length + 1); + if (cp == TOP().p) { + TOP().p = name; + return; + } + entry = entry->p; + } + TOP().p = NULL; +} + void f_compileon() { STATE.i = 1; } @@ -236,12 +272,11 @@ void f_immediate() { cell *flags = LATEST + 1; flags->u |= F_IMMEDIATE; } +void f_compileword(); void f_semicolon() { PUSHS("_RET"); - f_lookup(); - DROP(1); - f_comma(); + f_compileword(); f_compileoff(); } @@ -271,10 +306,8 @@ void f_interpretword() { // codefield flags -- void f_interpretnumber() { // number -- if (STATE.i) { - PUSHS("_DONUMBER"); - f_lookup(); - DROP(1); - f_comma(); + PUSHS("PUSH_"); + f_compileword(); f_comma(); } } @@ -325,37 +358,34 @@ void f_interpret(char *input) { } void f_if() { - if (STATE.i) { - PUSHC(W); - f_comma(); - PUSHP(HERE); - PUSHP(NULL); - f_comma(); + PUSHS("IF_"); + f_compileword(); + PUSHP(HERE); + PUSHP(NULL); + f_comma(); +} + +void f_if_() { + if (TOP().u) { + IP.p ++; } else { - if (TOP().u) { - IP.p ++; - } else { - IP.p = IP.p->p; // skip to then - } - DROP(1); + IP.p = IP.p->p; // skip to else or then } + DROP(1); } void f_else() { - if (STATE.i) { + PUSHS("GOTO_"); + f_compileword(); + PUSHP(NULL); + f_comma(); - PUSHC(W); - f_comma(); + TOP().p->p = HERE; // make false condition of IF come here + TOP().p = HERE - 1; // make THEN patch our goto +} - TOP().p->p = HERE + 1; - TOP().p = HERE; - - PUSHP(NULL); - f_comma(); - - } else { - IP.p = IP.p->p; - } +void f_goto_() { + IP.p = IP.p->p; } void f_then() { @@ -363,6 +393,17 @@ void f_then() { DROP(1); } +void f_quote() { + if (STATE.i) { + PUSHS("PUSH_"); + f_compileword(); + } else { + f_word(); + f_lookup(); + DROP(1); + } +} + int DIE = 0; void f_quit() { DIE = 1; @@ -372,31 +413,41 @@ void f_quit() { void f_init() { CDEF("[", f_compileoff); f_immediate(); CDEF("]", f_compileon); + CDEF("key", f_key); + CDEF("emit", f_emit); + CDEF("word", f_word); CDEF("immediate", f_immediate); CDEF("create", f_create); + CDEF("here", f_here); + CDEF("latest", f_latest); + CDEF("state", f_state); + CDEF("'", f_quote); f_immediate(); + CDEF("`", f_revlookup); 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("swap", f_swap); CDEF("rot", f_rot); CDEF("emit", f_emit); CDEF("number", f_number); - CDEF("_DONUMBER", f_donumber); + CDEF("PUSH_", f_push_); + CDEF("GOTO_", f_goto_); + CDEF("IF_", f_if_); 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 ;"); + f_interpret(": if ' IF_ , here 0 , ; immediate"); + f_interpret(": else ' GOTO_ , 0 , here swap ! here 2 - ; immediate"); + f_interpret(": then here swap ! ; immediate"); + } int main() { diff --git a/forp.exe b/forp.exe index ee516466f09bee1d8c2ebe3da8f1205b47d407ab..37caadb18330c8fff68ebf6ee4246c65b69186dc 100755 GIT binary patch delta 9037 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 delta 7830 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