From 1a7d14b056f236674e8119705244515375251090 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Sat, 2 Feb 2019 15:30:18 -0500 Subject: [PATCH] Forp: Loading from file, strings, comments, math, byte ops --- .gitignore | 2 + defs.frp | 31 +++++++ forp.c | 263 +++++++++++++++++++++++++++++++++++++++++++---------- forp.exe | Bin 37047 -> 42985 bytes 4 files changed, 250 insertions(+), 46 deletions(-) create mode 100755 defs.frp diff --git a/.gitignore b/.gitignore index d0dad88..91587d6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.bak *.dsk *.swp +*.log + diff --git a/defs.frp b/defs.frp new file mode 100755 index 0000000..aa44704 --- /dev/null +++ b/defs.frp @@ -0,0 +1,31 @@ +2 const cell +: cells cell * ; + +key ) const ')' + +10 const '\n' +key const sp + +: cr '\n' emit ; +: bl sp emit ; + +: if ' BZ_ , here 0 , ; immediate +: else ' GOTO_ , 0 , here swap ! here cell - ; immediate +: then here swap ! ; immediate + +: begin here ; immediate +: while ' BZ_ , here 0 , ; immediate +: repeat ' GOTO_ , swap , here swap ! ; immediate + +: ( begin key ')' != while repeat ; immediate + +: 2dup over over ; + +: decompile + word lookup drop 1 begin ( cp i ) + 2dup cells + @ ( cp i @cp+i ) + dup ' _RET != ( cp i @cp+i bool ) + while + dup ` dup if .s drop else drop . then bl ( cp i ) + 1 + ( cp i+1 ) + repeat drop drop drop ; diff --git a/forp.c b/forp.c index 1f4ab57..1aca100 100755 --- a/forp.c +++ b/forp.c @@ -13,6 +13,7 @@ union cell_union { cell *p; char *s; void (*f)(); + FILE *fp; }; char mem[MEM_SIZE]; @@ -27,6 +28,10 @@ cell stack_mem[STACK_SIZE]; cell *stack = stack_mem; char *INPUT = NULL; +FILE *INPUT_FILE = NULL; + +FILE *OUTPUT_FILE = NULL; +cell QUIET = 0; #define F_IMMEDIATE 0x80 @@ -55,17 +60,29 @@ void f_latest() { void f_state() { PUSHC(STATE); } +#define BINOP(name, op) \ + void name() { \ + cell r = TOP(); \ + DROP(1); \ + TOP().i = TOP().i op r.i; \ + } -void f_add() { - cell r = TOP(); - DROP(1); - TOP().i += r.i; +BINOP(f_add, +) +BINOP(f_sub, -) +BINOP(f_mul, *) +BINOP(f_div, /) +BINOP(f_eq, ==) +BINOP(f_neq, !=) +BINOP(f_ge, >=) +BINOP(f_gt, >) +BINOP(f_lt, <) +BINOP(f_le, <=) + +void f_eq0() { + TOP().i = (TOP().i == 0); } - -void f_sub() { - cell r = TOP(); - DROP(1); - TOP().i -= r.i; +void f_not() { + TOP().i = !TOP().i; } void f_get() { @@ -79,6 +96,17 @@ void f_set() { DROP(1); } +void f_bget() { + TOP().i = *((char*)TOP().p); +} + +void f_bset() { + char *p = (char*)TOP().p; + DROP(1); + (*p) = TOP().i; + DROP(1); +} + void f_drop() { DROP(1); } @@ -87,6 +115,10 @@ void f_dup() { PUSHC(TOP()); } +void f_over() { + PUSHC(ST1()); +} + void f_swap() { cell top = TOP(); cell st1 = ST1(); @@ -110,9 +142,21 @@ void f_key() { if (TOP().i == 0) { INPUT = NULL; } + } else if (INPUT_FILE) { + int val = fgetc(INPUT_FILE); + if (val == EOF) { + fclose(INPUT_FILE); + INPUT_FILE = NULL; + PUSHI(0); + } else { + PUSHI(val); + } } else { PUSHI(0); } + if (OUTPUT_FILE && TOP().i != 0) { + fputc(TOP().i, OUTPUT_FILE); + } } void f_word() { @@ -137,7 +181,12 @@ void f_word() { } void f_emit() { - printf("%c", TOP().i); + if (!QUIET.i) { + printf("%c", TOP().i); + } + if (OUTPUT_FILE) { + fputc(TOP().i, OUTPUT_FILE); + } DROP(1); } @@ -169,6 +218,12 @@ void f_comma() { DROP(1); } +void f_bcomma() { + *((char*)HERE) = TOP().i; + HERE = CELL_OFFSET(HERE, 1); + DROP(1); +} + void f_create() { // name -- int namelen; HERE->p = LATEST; @@ -206,11 +261,10 @@ void f_docolon() { } } - void f_noop() { } -void f_push_() { +void f_lit_() { PUSHC(*IP.p); IP.p++; } @@ -306,7 +360,7 @@ void f_interpretword() { // codefield flags -- void f_interpretnumber() { // number -- if (STATE.i) { - PUSHS("PUSH_"); + PUSHS("LIT_"); f_compileword(); f_comma(); } @@ -337,8 +391,7 @@ void f_compileword() { // name -- } } -void f_interpret(char *input) { - INPUT = input; +void f_interpreter() { while(1) { f_word(); // w if (TOP().s[0] == '\0') { @@ -357,45 +410,113 @@ void f_interpret(char *input) { } } -void f_if() { - PUSHS("IF_"); - f_compileword(); - PUSHP(HERE); - PUSHP(NULL); +void f_open() { + FILE *fp = fopen(TOP().s, "a+"); + fseek(fp, 0, SEEK_SET); + TOP().fp = fp; +} + +void f_close() { + fclose(TOP().fp); + DROP(1); +} + +void f__loadfile() { + INPUT_FILE = TOP().fp; + DROP(1); + f_interpreter(); + if (INPUT_FILE != NULL) { + fclose(INPUT_FILE); + INPUT_FILE = NULL; + } +} + +void f_loadstring() { + INPUT = TOP().s; + DROP(1); + f_interpreter(); + INPUT = NULL; +} + +void f_appendlog() { + OUTPUT_FILE = TOP().fp; + fseek(OUTPUT_FILE, 0, SEEK_END); + DROP(1); +} + +void f_doconst() { + PUSHC(*(W.p + 1)); +} + +void f_const() { + f_word(); + f_create(); + PUSHP(f_doconst); + f_comma(); f_comma(); } -void f_if_() { - if (TOP().u) { - IP.p ++; +void f_bz_() { + if (!TOP().u) { + IP.p = IP.p->p; // branch } else { - IP.p = IP.p->p; // skip to else or then + IP.p ++; // skip branch destination cell } DROP(1); } -void f_else() { - PUSHS("GOTO_"); - f_compileword(); - PUSHP(NULL); - f_comma(); - - TOP().p->p = HERE; // make false condition of IF come here - TOP().p = HERE - 1; // make THEN patch our goto +void f_bnz_() { + if (TOP().u) { + IP.p = IP.p->p; // branch + } else { + IP.p ++; // skip branch destination cell + } + DROP(1); } void f_goto_() { IP.p = IP.p->p; } -void f_then() { - TOP().p->p = HERE; - DROP(1); +void f_string_() { + PUSHP(IP.p + 1); + IP.p = CELL_OFFSET(IP.p + 1, IP.p->i + 1); +} + +void f_string() { + cell *length; + char *s; + char b; + if (STATE.i) { + PUSHS("S\"_"); + f_compileword(); + length = HERE; + PUSHI(0); + f_comma(); + } + s = (char*)HERE; + while(1) { + f_key(); + b = TOP().i; + DROP(1); + if (b == '\"') { + *s++ = 0; + break; + } else { + *s++ = b; + } + } + if (STATE.i) { + length->i = (int)((s - ((char*)HERE)) - 1); + HERE = (cell *)s; + } else { + PUSHP(HERE); + } } void f_quote() { if (STATE.i) { - PUSHS("PUSH_"); + PUSHS("LIT_"); f_compileword(); } else { f_word(); @@ -404,9 +525,23 @@ void f_quote() { } } -int DIE = 0; -void f_quit() { - DIE = 1; +void f_loadfile(char *filename) { + PUSHS(filename); + f_open(); + f__loadfile(); +} + +void f_runstring(char *s) { + PUSHS(s); + f_loadstring(); +} + +void f_quiet() { + QUIET.i = 1; +} + +void f_loud() { + QUIET.i = 0; } #define CDEF(name, def) PUSHP(def); PUSHS(name); f_cdef() @@ -423,39 +558,75 @@ void f_init() { CDEF("state", f_state); CDEF("'", f_quote); f_immediate(); CDEF("`", f_revlookup); + CDEF("lookup", f_lookup); CDEF(":", f_colon); CDEF(";", f_semicolon); f_immediate(); + CDEF("const", f_const); CDEF("+", f_add); CDEF("-", f_sub); + CDEF("*", f_mul); + CDEF("/", f_div); + CDEF("=0", f_eq0); + CDEF("not", f_not); + CDEF("=", f_eq); + CDEF("!=", f_neq); + CDEF(">=", f_ge); + CDEF(">", f_gt); + CDEF("=", f_eq); + CDEF("<", f_lt); + CDEF("<=", f_le); CDEF("@", f_get); CDEF("!", f_set); + CDEF("b@", f_bget); + CDEF("b!", f_bset); CDEF("dup", f_dup); + CDEF("over", f_over); CDEF("drop", f_drop); CDEF("swap", f_swap); CDEF("rot", f_rot); CDEF("emit", f_emit); CDEF("number", f_number); - CDEF("PUSH_", f_push_); + CDEF("LIT_", f_lit_); CDEF("GOTO_", f_goto_); - CDEF("IF_", f_if_); + CDEF("BZ_", f_bz_); + CDEF("BNZ_", f_bnz_); CDEF("_RET", f_ret); CDEF(".", f_dot); CDEF(".s", f_puts); CDEF(",", f_comma); + CDEF("b,", f_bcomma); + CDEF("s\"", f_string); f_immediate(); + CDEF("S\"_", f_string_); CDEF("noop", f_noop); - CDEF("quit", f_quit); - f_interpret(": if ' IF_ , here 0 , ; immediate"); - f_interpret(": else ' GOTO_ , 0 , here swap ! here 2 - ; immediate"); - f_interpret(": then here swap ! ; immediate"); + CDEF("open", f_open); + CDEF("close", f_close); + CDEF("loadfile", f__loadfile); + CDEF("loadstring", f_loadstring); + CDEF("quiet", f_quiet); + CDEF("loud", f_loud); + CDEF("appendlog", f_appendlog); + + PUSHS("forp.log"); + f_open(); + f_appendlog(); + + + f_loadfile("defs.frp"); +} + +int DIE = 0; +void f_quit() { + DIE = 1; } int main() { char inputbuf[256]; f_init(); + CDEF("quit", f_quit); while (!DIE) { - f_interpret(gets(inputbuf)); + f_runstring(gets(inputbuf)); } return 0; } \ No newline at end of file diff --git a/forp.exe b/forp.exe index 37caadb18330c8fff68ebf6ee4246c65b69186dc..577e287415c262ec8d0c5004341578363f8a4625 100755 GIT binary patch delta 15146 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 aLi+gO_yq(msqmUOHg)9K(ek=2J^u&dv(xzi delta 9652 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