From 791e4644aadfd0e48e370077563e76d1213e19e9 Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Fri, 1 Sep 2023 19:10:50 -0400 Subject: [PATCH] First cut at stripping down minijort --- .gitignore | 4 + boot.jor | 66 ++++ main.c | 11 + minijort.c | 936 +++++++++++++++++++++++++++++++++++++++++++++++++++ minijort.exe | Bin 0 -> 79411 bytes minijort.h | 73 ++++ minijort.prj | Bin 0 -> 3743 bytes 7 files changed, 1090 insertions(+) create mode 100644 .gitignore create mode 100755 boot.jor create mode 100755 main.c create mode 100755 minijort.c create mode 100755 minijort.exe create mode 100755 minijort.h create mode 100755 minijort.prj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c440dfc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.bak +*.obj +*.dsk + diff --git a/boot.jor b/boot.jor new file mode 100755 index 0000000..d0b75d9 --- /dev/null +++ b/boot.jor @@ -0,0 +1,66 @@ +0 const 0 +1 const 1 +2 const cell +: cells cell * ; + +10 const '\n' +13 const '\r' +key const sp + +128 const F_IMMEDIATE +0x100 const F_USERWORD + +: 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 +: again ' GOTO_ , , ; immediate +: until ' BZ_ , , ; immediate + +: lit ' LIT_ , , ; +: ( begin key [ key ) lit ] = until ; immediate + +: inline| ' INLINEDATA_ , here 0 , ; +: |inline [ ' then , ] ; + +' cells @ const $DOCOLON ( get the colon execution token ) +: :| inline| $DOCOLON , ; immediate +: |; ' ret , |inline ; immediate + +: s" state if inline| else here then + begin key dup [ key " lit ] != over 0 != and while b, repeat drop 0 b, + state if |inline else dup here! then ; immediate + +: interpretword F_IMMEDIATE & state not or if execute else , then ; +: interpretnumber state if lit then ; +: interpretunknown type s" ?" type cr ; +: compileword lookup dup + if interpretword + else drop number + if interpretnumber + else interpretunknown + then + then ; +: interpreter + begin word dup b@ while compileword repeat drop ; +: loadfp ( -- ) + infile @ >r + fdeactivate infile ! + interpreter + infile @ factivate + r open loadfp close +#include +#include +#include +#include +#include "minijort.h" + +#define STACK_OFFSET 0 +#define RSTACK_OFFSET STACK_SIZE + +char mem[MEM_SIZE] = { 0 }; +cell *HERE = ((cell*)mem) + STACK_SIZE + RSTACK_SIZE; +cell *LATEST = NULL; +cell IP = NULL; +cell W = NULL; +cell STATE = 0; +cell *stack = ((cell*)mem); +cell *rstack = ((cell*)mem) + STACK_SIZE; +#ifdef TRACE +int TRACING = 0; +#endif + +FILE *ACTIVE_FILE = NULL; +FILE *IN_FILE = stdin; +FILE *OUT_FILE = stdout; + +void DROP(n) { + stack -= n; + if (stack < mem + STACK_OFFSET) { + stack = mem + STACK_OFFSET; + PUSHS("underflow!\n"); + f_puts(); + } +} + +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++; } +void PUSHS(char *s) { stack->s = s; stack++; } +void RPUSH(cell c) { *rstack = c; rstack++; } + +void f_here() { + PUSHCP(HERE); +} + +void f_here_set() { + HERE = TOP().p; + DROP(1); +} +void f_there() { + PUSHCP(&mem[MEM_SIZE]); +} + +void f_latest() { + PUSHCP(LATEST); +} + +void f_latest_set() { + LATEST = TOP().p; + DROP(1); +} + +void f_state() { + PUSHC(STATE); +} + +#define BINOP(name, type, op) \ + void name() { \ + cell r = TOP(); \ + DROP(1); \ + TOP().type = TOP().type op r.type; \ + } + +BINOP(f_add, i, +) +BINOP(f_sub, i, -) +BINOP(f_mul, i, *) +BINOP(f_div, i, /) +BINOP(f_mod, u, %) +BINOP(f_eq, i, ==) +BINOP(f_neq, i, !=) +BINOP(f_ge, i, >=) +BINOP(f_gt, i, >) +BINOP(f_lt, i, <) +BINOP(f_le, i, <=) +BINOP(f_uge, u, >=) +BINOP(f_ugt, u, >) +BINOP(f_ult, u, <) +BINOP(f_ule, u, <=) +BINOP(f_and, u, &&) +BINOP(f_or, u, ||) +BINOP(f_bitand, u, &) +BINOP(f_bitor, u, |) +BINOP(f_bitxor, u, ^) +BINOP(f_shr, u, >>) +BINOP(f_shl, u, <<) + +#define RATIO_FRACTIONAL_BITS 14 + +void f_toratio() { // a/b ( a b -- r ) + ST1().i = ((long)ST1().i * (1 << RATIO_FRACTIONAL_BITS)) / TOP().i; + DROP(1); +} + +void f_fromratio() { // a*r ( a r -- b ) + ST1().i = ((long)ST1().i * (long)TOP().i) / (1 << RATIO_FRACTIONAL_BITS); + DROP(1); +} + +void f_eq0() { + TOP().i = (TOP().i == 0); +} +void f_not() { + TOP().i = !TOP().i; +} + +void f_get() { + TOP() = (*(TOP().p)); +} + +void f_set() { + cell *p = TOP().p; + DROP(1); + (*p) = TOP(); + DROP(1); +} + +void f_bget() { + TOP().i = *((char*)TOP().p); +} + +void f_ubget() { + TOP().u = *((unsigned char*)TOP().p); +} + +void f_bset() { + char *p = (char*)TOP().p; + DROP(1); + (*p) = TOP().i; + DROP(1); +} + +void f_farset() { + *((cell far *)MK_FP(TOP().u, ST1().u)) = ST2(); + DROP(3); +} + +void f_farget() { + ST1() = *((cell far *)MK_FP(TOP().u, ST1().u)); + DROP(1); +} + +void f_farbset() { + *((char far *)MK_FP(TOP().u, ST1().u)) = ST2().i; + DROP(3); +} + +void f_farbget() { + ST1().i = *((char far *)MK_FP(TOP().u, ST1().u)); + DROP(1); +} + +void f_addset() { + TOP().p->i += ST1().i; + DROP(2); +} + +void f_drop() { + DROP(1); +} + +void f_dup() { + PUSHC(TOP()); +} + +void f_over() { + PUSHC(ST1()); +} + +void f_swap() { + cell top = TOP(); + cell st1 = ST1(); + TOP() = st1; + ST1() = 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_rput() { + RPUSH(TOP()); + DROP(1); +} + +void f_rtake() { + PUSHC(*RPOP()); +} + +void f_rtop() { + PUSHC(*(rstack - 1)); +} + +void f_rdrop() { + RPOP(); +} + +void f_rswap() { + cell top = *(rstack - 1); + cell under = *(rstack - 2); + *(rstack - 1) = under; + *(rstack - 2) = top; +} + +void f_cexecute(); + +void f_emit() { + if (OUT_FILE) { + fprintf(OUT_FILE, "%c", TOP().i); + } + DROP(1); +} + +void f_key() { + if (IN_FILE) { + PUSHI(fgetc(IN_FILE)); + } else { + PUSHI(EOF); + } +} + +void f_word() { + static char buf[32] = {0}; + int key = ' '; + int ibuf = 0; + + while (key == ' ' || key == '\t' || key == '\n' || key == '\r') { + f_key(); + key = TOP().i; + DROP(1); + } + + while (key != ' ' && key != '\t' && key != '\n' && key != '\r' && key != 0 && key != EOF) { + buf[ibuf++] = key; + f_key(); + key = TOP().i; + DROP(1); + } + buf[ibuf] = 0; + PUSHS(buf); +} + +void f_fputc() { + if (ACTIVE_FILE) { + fwrite(&TOP().i, 1, 1, ACTIVE_FILE); + } + DROP(1); +} + +void f_gets() { + gets(TOP().s); +} + +void f_fput() { + if (ACTIVE_FILE) { + fwrite(&TOP().u, 2, 1, ACTIVE_FILE); + } + DROP(1); +} + +void f_fwrite() { // ( length p ) + if (ACTIVE_FILE) { + fwrite(TOP().p, ST1().u, 1, ACTIVE_FILE); + } + DROP(2); +} + +void f_fgetc() { + int result = EOF; + if (ACTIVE_FILE) { + result = fgetc(ACTIVE_FILE); + } + PUSHI(result); +} + +void f_fget() { + unsigned int result = 0; + if (ACTIVE_FILE) { + int low = fgetc(ACTIVE_FILE); + int high = fgetc(ACTIVE_FILE); + if (low != EOF && high != EOF) { + result = low | (high << 8); + } + } + PUSHU(result); +} + +void f_fread() { // ( length p ) + if (ACTIVE_FILE) { + fread(TOP().p, ST1().u, 1, ACTIVE_FILE); + } + DROP(2); +} + +void f_feof() { + if (ACTIVE_FILE) { + PUSHI(feof(ACTIVE_FILE)); + } else { + PUSHI(1); + } +} + +void f_puts() { + char *s = TOP().s; + while (s && *s) { + PUSHI(*s); + f_emit(); + s++; + } + DROP(1); +} + +void f_dot() { + static char num[16]; + sprintf(num, "%d ", TOP().i); + TOP().s = num; + f_puts(); +} + +void f_udot() { + static char num[16]; + sprintf(num, "%u ", TOP().i); + TOP().s = num; + f_puts(); +} + +void f_printstack() { + cell *v = mem + STACK_OFFSET; + while (v != stack) { + PUSHC(*v++); + f_dot(); + } +} + +void f_printrstack() { + cell *v = mem + RSTACK_OFFSET; + while (v != rstack) { + PUSHC(*v++); + f_dot(); + } +} + +void f_cr() { + PUSHI('\n'); + f_emit(); +} + +void f_comma() { + *HERE++ = TOP(); + DROP(1); +} + +void f_allot() { + memset(HERE, 0, TOP().u); + HERE = CELL_OFFSET(HERE, TOP().u); + 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; + 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(); + f_comma(); +} + +void f_revlookup(); + +#ifdef TRACE +void f_traceon() { + TRACING = 1; +} +void f_traceoff() { + TRACING = 0; +} + +void f_colondispatch() { + static int printing = 0; + + if (TRACING && !printing) { + printing = 1; + PUSHCP(W.p); + f_revlookup(); + if (TOP().s) { + f_puts(); + PUSHU(' '); + f_emit(); + } else { + TOP().p = W.p; + f_dot(); + } + printing = 0; + } + W.p->f(); +} +#else +#define f_colondispatch() W.p->f() +#endif + +void f_colonloop() { + while (IP.p) { + W = *IP.p; + IP.p++; + f_colondispatch(); + } +} + +// this version of f_execute can be run from a colon word +void f_execute() { + W = TOP(); + DROP(1); + f_colondispatch(); +} + +// C code must always call a colon word through f_cexecute() +void f_cexecute() { + cell oldW = W; + cell oldIP = IP; + IP.p = NULL; + f_execute(); + f_colonloop(); + W = oldW; + IP = oldIP; +} + +void f_docolon() { + RPUSH(IP); + IP.p = W.p + 1; +} + +void f_dodeferred() { + W = *(W.p + 1); + f_colondispatch(); +} + +void f_lit_() { + PUSHC(*IP.p); + IP.p++; +} + +void f_number() { // str -- (num 1 | str 0) + int num = 0, result; + result = sscanf(TOP().s, "0x%x", &num); + if (result != 1) { + result = sscanf(TOP().s, "%d", &num); + } + if (result == 1) { + TOP().i = num; + PUSHI(result == 1); + } else { + PUSHI(0); + } +} + +void f_streq() { + int result = strcmp(TOP().s, ST1().s); + DROP(1); + TOP().i = result == 0; +} + +void f_wordname() { + TOP().p = TOP().p + 2; +} +void f_wordflags() { + TOP().p = TOP().p + 1; +} + +void f_codepointer() { + unsigned int flags = TOP().p[1].u; + TOP().p = CELL_OFFSET(TOP().p + 2, (flags & F_NAMELEN_MASK) + 1); +} + +void f_lookup() { // name -- (codepointer flags) | (name 0) + cell *entry = LATEST; + char *name = TOP().s; + int len = strlen(name); + DROP(1); + + while (entry) { + PUSHP(entry); + f_wordflags(); f_get(); + if (len == (TOP().u & F_NAMELEN_MASK)) { + PUSHS(name); + PUSHP(entry); + f_wordname(); + f_streq(); + if (TOP().i) { + TOP().p = entry; + f_codepointer(); + f_swap(); + return; + } + DROP(2); + } else { + DROP(1); + } + entry = entry->p; + } + PUSHS(name); + PUSHU(0); +} + +void f_revlookup() { // codepointer -- name + cell *entry = LATEST; + while (entry) { + PUSHCP(entry); + f_codepointer(); + if (TOP().p == ST1().p) { + DROP(1); + TOP().p = entry; + f_wordname(); + return; + } + DROP(1); + entry = entry->p; + } + TOP().p = NULL; +} + +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_compileword(); + +void f_semicolon() { + PUSHS("ret"); + f_compileword(); + f_compileoff(); +} + +void f_ret() { + if (rstack == mem + RSTACK_OFFSET) { + IP.p = NULL; + } else { + 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); + f_cexecute(); + } else { + DROP(1); + f_comma(); + } +} + +void f_interpretnumber() { // number -- + if (STATE.i) { + PUSHS("LIT_"); + f_compileword(); + 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_number(); // n isnum + if (TOP().i) { + DROP(1); + f_interpretnumber(); + } else { + DROP(1); + f_interpretunknown(); + } + } else { // codepointer flags + f_interpretword(); + } +} + +void f_interpreter() { + while(1) { + f_word(); // w + if (TOP().s[0] == '\0') { + PUSHS("ok\n"); + f_puts(); + DROP(1); + return; + } + f_compileword(); + } +} + +void f_close() { + if (ACTIVE_FILE) { + fclose(ACTIVE_FILE); + ACTIVE_FILE = NULL; + } +} + +void f_open() { + FILE *fp; + fp = fopen(TOP().s, "ab+"); + fseek(fp, 0, SEEK_SET); + ACTIVE_FILE = fp; + DROP(1); +} + +void f_overwrite() { + f_close(); + ACTIVE_FILE = fopen(TOP().s, "wb+"); + DROP(1); +} + +void f_deactivate() { + PUSHP(ACTIVE_FILE); + ACTIVE_FILE = NULL; +} + +void f_activate() { + f_close(); + ACTIVE_FILE = TOP().fp; + DROP(1); +} + +void f_seek() { + fseek(ACTIVE_FILE, TOP().u, SEEK_SET); + DROP(1); +} + +void f_seekend() { + fseek(ACTIVE_FILE, 0, SEEK_END); +} + +void f_tell() { + PUSHU(ftell(ACTIVE_FILE)); +} + +void f_exists() { + struct stat statbuf; + int rc = stat(TOP().s, &statbuf); + TOP().i = rc == 0; +} + +struct ffblk findfile; +void f_findfirst() { + int result = findfirst(TOP().s, &findfile, 0); + if (result == 0) { + TOP().s = findfile.ff_name; + } else { + TOP().u = 0; + } +} + +void f_findnext() { + int result = findnext(&findfile); + if (result == 0) { + PUSHS(findfile.ff_name); + } else { + PUSHU(0); + } +} + +void f_chdir() { + chdir(TOP().s); + 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_dovar() { + PUSHCP(W.p + 1); +} + +void f_var() { + f_word(); + f_create(); + PUSHP(f_dovar); + f_comma(); + PUSHI(0); + f_comma(); +} + +void f_docreate() { + PUSHCP(W.p + 2); + RPUSH(IP); + IP = *(W.p + 1); +} + +void f_bz_() { + if (!TOP().u) { + IP.p = IP.p->p; // branch + } else { + IP.p ++; // skip branch destination cell + } + DROP(1); +} + +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_inline_data_() { + PUSHCP(IP.p + 1); + IP = *IP.p; +} + +void f_memmove() { // ( dst src size -- ) + memmove(ST2().p, ST1().p, TOP().u); + DROP(3); +} + +void f_quote() { + if (STATE.i) { + PUSHS("LIT_"); + f_compileword(); + } else { + f_word(); + f_lookup(); + DROP(1); + } +} + +void f_rand() { + PUSHI(rand()); +} + +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("execute", f_execute); + CDEF("new-word", f_create); + CDEF("here", f_here); + CDEF("here!", f_here_set); + CDEF("there", f_there); + CDEF("latest", f_latest); + CDEF("latest!", f_latest_set); + CDEF("state", f_state); + CDEF("'", f_quote); f_immediate(); + CDEF("`", f_revlookup); + CDEF("wordname", f_wordname); + CDEF("wordflags", f_wordflags); + CDEF("codepointer", f_codepointer); + CDEF("lookup", f_lookup); + CDEF(":", f_colon); + CDEF(";", f_semicolon); f_immediate(); + CDEF("const", f_const); + CDEF("var", f_var); + CDEF("allot", f_allot); + CDEF("+", f_add); + CDEF("-", f_sub); + CDEF("*", f_mul); + CDEF("/", f_div); + CDEF("%", f_mod); + 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("u>=", f_uge); + CDEF("u>", f_ugt); + CDEF("u<", f_ult); + CDEF("u<=", f_ule); + CDEF("and", f_and); + CDEF("or", f_or); + CDEF("&", f_bitand); + CDEF("|", f_bitor); + CDEF("^", f_bitxor); + CDEF("<<", f_shl); + CDEF(">>", f_shr); + CDEF("/>ratio", f_toratio); + CDEF("*r", f_rput); + CDEF("HmPLZVbFsG=vO*y&INNkq(izqR)yBG2=_&-4B9UElRy*9>dVZ~fN2 zPWN7id)<3ahK;?>y+8uR5|P*2AT$f#?9&HMTpc%)+?zYlC!54#@$@e5;_9+bE=(TK z=FtF0dDhXaiZiZ|Y}&=qi3`p`z4Jn)D`q(@KO6U#*oQVR@e-e|+e^HQMT!?}u{|X8 zxwXmGVu$9$wZRG3Yz>`AAiK^9mK-5_$&_$yzD~U77D`{{#NUOpu9)}Gj1Or2N{TzZ zvLOHQw4==@p154K^0;{UZhS$)LoH^3B`_+j!IPwWlyY=_?*(74C|m-A}5DkpJ>Z0;R}z zJZxzgEnboT43lGBQdwJHAVihu{FNH zP2&rZQ?zJG&b8AX&Rx>yaBcymn~Q-9NUF?Dkw=nM9&S*@Vh-m*)TMJGng9QQ`mUz< z?|j93yBFlj-*~O}>l*CYP>?He=!L~cO9g1=7?24fq$?!dlt5|0uhrR<>g9e=2uYt?asr%>N|Z zr&c)rctwUPo%TOA*;Ff?VDUHt&}BD|>GQw$^XGdtIzcA;f0=1>-AoJr%S`{MnI+)1v<}ldf*2#s6idR$nWdlk7Pm|Az^1 zwyNg7GwE{=O0yXHvTkIGimKP`2$4$?N2bUziK=9^va-BUrLJS~1-mIJWn_&o`%Xdr zk?XAE{YhJQZLB!mxFAW*?77cR^oY8;WGah@^VRjvd#9#r zE{)R6zwcNl)XkftTU$4?l6RsfN0$%dL|Gjb;Rnk6NG&sGuqRtB^R1dP6|t3AQCSNn zR*T*7HL$9UOQ&pQ=`~_3`My+}n&zu|9Ck<5wHxS1YY&d$ZblhU&Jy&+%NcNBXLlH0x8m-H+$W0~$CF zXqAS%TcK*v+2}PNdwx4h}&9Qj0Up|>@kzcQ$t*I|tjFK%{$rh$$3&NG`Z0+(o z_7)*GNhe`UOsud@sJS(LzDJuIdb@wG*buB4>ksD!c+loAqn!uzO1r);S36j92QEg} zbojx{7*aKvpRdil*q7O<)YPP=CbcYO)UX>hM3HA>a=1@Eb&uDp<}t85@|qS_@p`KK zY`JgtLX~OIC6Ou=rwG{~RH>jDOx)@9+QXb4uRT~S+M&m~_LK3LE7jx8@W|cDtrH(q z!vEB?F;PqptZDhT>-O6$#(a;_!?%t_(uv#bRx`8hTc1$Pg5eIz(X368Kf7&}cigiW z%k2SKiR5rAvQOWxvlKxMl5Ty9bSy7LKHC_Bi>au1u;*Bw{HeEg!D3QINS%XJejTZE zd9q8DO5IaH?qKmZiv<(nAyoUGHv!9#x*)+^sPUD zYjrV-Ad(Mx5OaKq-`v?{Gq z1l8q&Xoba-B89H6>8;$f5mWPZr-!pQP|_mqr*XAuj;2aS*jna+Xzjk5BDcP2b?b1? zZAo?U@@^@ey=#Q<~hb z3r><%H>~ozBp+8t?~*>>`o^}1DVea~%FBF7NX zRjVUi5f70XqY>>UED*rrZFvu77~s z;Purt6_M>;w;)eZ+b920$;8Ep9=Hk|ky1-k@i~*JQVQ&L-RcgIS9#q(`I^UepAcoW z-x`GTKcYTGN^S4Yhc2OP9OI707sMY=8JQ|4n6aL_d>fv8?pn@6LW!?HW)6%!_q@rT!dS0#kbah!k2Ic-^FotY#2eKB{ z8JDRnhdj5DTCzb3*^(l6z2;jhgc?n;Oz4yBj8+Y?cmJ;03$RGe=jD7~Tn?^~AFh(l zgkwMZ8@t~f`I9?J@07(bMLt*~cd=aNt0X=GyCmdXchGeCC7{K%;#gl&SQa~kwDz228fQkV%22?vx`IS9gR+7871WGM>2Xkd zK|K%ZFsRX$(qvHEKrI2a6IB07=^6&cI#A0%Z3NY+Qa)BCeQrvTonT#HSAuO=DIE<> zk)H!4f_f2@woovU-5p3aUS-qZQI*=%*E^ z9iTda+Fc>Vfii>o98?ofc@^?wRZ=O2_g%MD`U0#L>}wU084Z>}eFf^K+bU;PNJoR= zkp#6D)HzVIDx|sS>3&cLK^+A(rb2oP)Tf||LG1=Ls6r|N^$w_SLFIw!S|OEza)CMm z>UB`fDx_wb6gdObQBX@j1yxAV`V{$TP(Og03+hg})D2V$sNpiY5$ z4AhBo=_ODPgE|eW8>oVEX(y-#pne9`0@TOl(iKn|P``l+1@)F%){Vcc(m7Doe_7>a z8 zcw5Q{#AFB61k`3wU2aP*NM(a+25L2^nA_6(pd6rDfXV`8ye)kRY6_?}pyq(8ye0h# zYB;ENpvHo_cuUft_(V`0K@A3V{Fc-XR69`dpdJCW_m-3bDhgCjP|ZPYyCvm<5#|iE0P3!6m6zU&?lgPH|u5~vJN+$|{+ z)EH3HK|KxX@0-#JV~RWo)ND`~9rDjNrQM*qg0g|?4eHQMDGp0TGf?wEJq+rLn^FT% zL7*~0H30R&O=&%*`<=^H$q7mW>Xn<)C{UL`xj@~xY?T+@lwJUJ0@Mmnzk!;0Q~DHC z0jO1=j(|$NDfPh`^D(IRKuMqm+>|1)bi4)X15lelb-pR}0<{d(Mo_CjHN7ca4oZ>j zpz=U124%P@O@h>9P}@Mw231ieEe4eg>QhiwP=A(5pMXjL^*JaDsFE`2E~tk zvXx0kA@wb&lb}w5nph_72K6PV-$3mHHMC5+3~B?Yzd(Hgs%M#GL|Lzbx(4cPP;JVj zR-hJvssNP@D!fd&wa32$QT1E3{*Q%`8T9hkTQa52r3HH`Ww=8G@|k%<|8Np)XE#u+n_FjdI;3@ zi`f5eNc%t?2h|1Cub^h!kcu$?_JZmG>M*F$H>9XY?0=y8g4zkH{|&`}S_f(%sEwdH z-H^H<<5Ix!*Ok;4k(!KDMwxFYmedTuzG~`tq>e@^qi$Z8c((rmHdj;oB6TuS8TI3J z=~ym|eLz7?ZI09#NM+Q{>(X(gh5%l?rqnAS^*N+6YTb1ydm}pgClsfqUi{N4WgwMN zFJ70{BK0`nhu0LlYUt4Qx7ab-o1u}v2dyn*rj&A2FfgR}8WFw!G#r#f)B7UKosbc0Bevcz2@;i}m7Zti$-pjOZ%iIt)zuGpnXQxj6urVTg1 z{!J*hhoCg#9l9k$c@w$ciZAfBpw?@*H-h$LZ*+%2P9VEJRi5azdMzGjkx48b4t-t5 z9j|rJDGq@QeY{t3_{Dz<=T?p`=UAf6q2J4~mjT?dSyl5L0egADtSDc_>-eaA(Pig&r zEqiher!z*79z%e6YgSmQvA%j;19{x&ChW#8YU$0WhF8*?p_Mz~c&g1Fs4)~Q3TAgz zxzFf9KUKj2p=@{rK(EA0#HT2Fu6?3~(_~7jyj6>HB&2ky@@x03?)~Z@C}QqTv?mpM zS4IE3i$xRIAWoHk^5S?|pv)LUDq7Ck7Vn!ftTSx%upFVOa{GJM z8VPfagfkQ4HBf%-ekrCLiw6Bt=crb`?DHT=ecP}(i{e*UV4l3!#J4(NtY+#-~%qNk3l5;U;&{$O{eWVlKgJIreExhbOkP+rR3>zg*G>C=cyn_wmY4*s-tz+~2CnNJ$_4axl1&Z&TcYo^4L<@z|&TtZH|7B!o zF(-Lxpvn)#;*91!o69mx?a1J_e`CQQmc& zrP`e8aig+8R#|n!RF8=Nmg*Wss0A>sV!-I#UG6LPix&448?7id?7m`ix%wJa7M@Iv zSmD;PfuOOh&))dhhU|^F^&w)+s*PUls*TER*DIUf?}5Jit~_%wIF2ZHU!PE+Oe1rV zhAOl<8%?B49G)%9HQpLALn~??b7@jBNiZw}$m(-TLEETW^TAVFoQd8=Jw#2COCvsI z@D4QOKD8xVr!3m`rdfTS+G4Ql*jKOvGcv4--5o9NPH8@sZX<}jN)9H?<4awX&$Bgz zQ}&*LxOaA_^XEJ2-cyVvzT))1si@%t6(Prmz8r73A5)SX%}_@YIii_!Ln`0o+ZJA7 zZjs*DfK~pfEk1s}kGC6;4f};qI>n2A<@@}fY^X82AyvNRsZoe}OSDLFWqOcHPxdzM zMycWiz1O10!_O4?5M-4>6<<(Vfz6L?C%>2e#gu@S38hX_Iz6rDLT&m(zMlV4srLN4 zGz?O8;Qic0*~-#+_s-IfNz@3%3mZY&VSrZS25MazHUK~L<$Imw!@E!NOKbyV!Y&QB z(BO95FHiK9CzMY2y2mR`=!ZGaZm6+fQIvX9N7eLWTsB)xLTme#BL8$x?Uqp5#;bO! z&>eNZ_#b(-xk9OqJ&35Y#=xA}P`RmCTeXS#N5zn;O=3*trrl#XsavwVu~`5|&f^3L zS5(!e^;MhJwe~J9%w4__np~@gRvAU`KJ_iKU)jtX<;uF3wPf?`AyT^RRdImUz}~ zWNvTICT#cN&OX&3gO+%*H#)S%+G>#OPMX=Ut8w&>yo(BO(`&4#{!Oe{lWt;1h0&xK zHZEmlVpZCE8@(Ali?uIp92CcvYDZL>{6`baX13_F38NvrBRGex-mrpLzJ++Ks>eeW zr0Ma3p3lBvyA~Up%5Zo@w(D_IxJ0o@kxsS3RC@r6F9_+^hhPh6u=}Z7--bwK_4}7Z zj4XMXnug(^5qo%b%w91RsLQ4%XMfFnfd%3XRSIEysZy>cMH<&GMM`X!A~!WU52!D? zsS7cyyEc((6Yr~#ZDpI8Euj?2RwAsZ!k$T6u#idoW=zWu%vLLVVhC;GRXt{UB1@7E zStKn>e+lWZD8}#C)b1S4J`=XE1s|h9KvkS}!j|JAB^N4Sd&3073eNTwR(0Ek(0A!hHF-%MO!Ir}j#(;^8wia&(Huv2!oJ4~!Xwu(R2EGwxvziN$87+&HN41i$zAHx>vD$Z7%cAlm2zJbrQ zzpUoHM2ki|x#Tb66ZWU;HoS$|p&q*Q?9io-aY&?U1?^jG=@AbZk2_3D_7QJ0Bz%{y zT?V>-23GvW`^Dp3BzdRTs-C9u6U0=_(dIU0jlwIrSr}iK-|%SjwM-59Avr8Cy6if&)6`Gr0aZLB4-!vvBqa*M#b5xkL)aH~N+=3H zA!xOE;ZgcLXCFfz*;}WKRE`YQ%CxJJ(@a>Z0whz2^1|cwv18(jaDUW&K$(8*)tB07 z<6FdsN;FXId7twAS&nWJ*B>@$2{h4hWQxT5BC5?a)@o}gQGcX`C8T<6f%5|rEY&uQ zVO3Whd7m*8li%rRbM2`7Mo`z$=K0BDvR={nJJ!|tjm9=R+I+;juxVMQQSu#5QGcB* zxC{Bik2e2z!rws{V_!WvhKmFF)+F>M!GRgl{05sL>b7{vHv=&KF@vyO33xp3wQCckNiB(t8Ch-vWD&(X&U6t zG$}Tmx|8SVN?mMETF8#VCQdQFU;qXBigVAy#*w93B0;HgvKKdxcVBXUQ`6)~uVO;Y ztud8e)u6%Hjbl~oq@%|QdkR@TeW1mg+#9m`%!LuiY(1QecCgOn&Q&ccWvd?UwXy;4 zvutB@Mz6imcFJkJ%j?CP_7x>V@PN2aQJ&EY^U7g_ULJN@JiLh4bg@O+ujK?73hbr5 z&N)iOGg&=*JI+JPH#aXk;y5$7jy;<{kWDk}Rmlc1RnO*?vZ-ps{cbIrb-eFEEi%Kc z66y4e$rSdak*j;q=A4&9Hm?=0yUk)z#cAfmX}S1fu{LP4*X!!OO7+^P=a8C_yQ+1T zTADJr)kQzQe~v{t{IH>iL5NX`rw7Zu>y**vywV~yO$&=7MhA1tdAHU4F_^fvQKBVC zOb#)AyU3iyPHV=ZfDVHz&S054Ln|_VyAb+X-0_N=uT|X4j<8$^bl+exK-`ntE0TY! zI3s*tot&d-Z%Ef@dbtJOqS<=>+IHHi6D66pstYWhNkRnhV7)J4E)y=oV*OG>xx-cEPFFmC^c<4e!d{$=z@bqvc9CW z`sSu|ZX+u6t=F~b$v9rony@#>t7O)cGhB5;vnYkad!i{9%&TwDB=8Z$*uE$lP@J;Cf!gZl?V|DG; z!HP$R<;`_#z4YGb3=Hq14U{JDzGHPaP`crf`>BG@mS&UUuwu>;`DGmG zSpJ2hP*$3JrkYh-{UPd$S@J!_qQoqFOlvP;=}BQNOq0K?hQ8efr0{l4nhXaYdz&vp zX;TOjQH+W z&R6Wykb~b&SfY1aZ;`Au?91TJx*Xnjnh@Xy}QttIK+hE&TSB7B??sUVP zcV}$w>UG|Y%n(ZTLdk`W-aNkNn$iW{(hwml*~__4IZcwFll?KEAx7IF=mx z9E&$dlWp;?uvFq^RKW{Xj*#^l+NHwNANOH>2$tsf0s-z_bz6%gCCjL%N~inIjC;>*yTUF8?*G${5YhUMvkhR zI&Q2|qe*_;gGyJiDr4>Z>W@lCdrB{GHBFYhi(6XC)fG)SG3>=VH`tue;z!ZFwI5=O zZYS$l5lWi_Bpm#L0ri+#&U!fqjW1WPwg_%&5yR>wqHw} z;0VBtH*L!&c)lxPf?nID<60a(eo;T`)Ha-?+a!*+w@&Qf_@h_E{9m&WIlb-S{q~Fe zv113FKM{mHha9)uKbF2j7?nyt(K25v4^<~GOsUtn;ctq+p_ac{Ek}-DeEHc^Z?3lM zk-=owyF-=lKqdQut?qpf>cNtbQNBn`)S^pFAxo+il1)y|p#=jTx`Uafst+eI&N-o) zu=iG%;#YTdW@l!29lhHxTAlj@?;rL`t9x(U@m(6ieONeXt{XV8awi7mxI4_GQ%)&trKnlK@RLJDExu)G z#@f~8g;{uHvSb502wqt2O%7T(HZjhw!+nnOSiCI$_ybwG#g$`0PBvT^=DgDihr~O) ztzBYg$E>V7CdX7J-u1qC;sX1K#4+|^?sP1kI35QmYiR9=#>pFp(b7E35lZY_Y%v(f z(UKK$?S2tp^@MUXiDMic5W(Wp0JX1{Z+lkTw!i5%yjd~bAY2cxaD>`p(1?Wny^z2c<+N2#@3VF0NGP@8z=tsW>%&b58QkQTQM_4oKVd* z6=Bs+sB$%RM`3jB_AcfvUi=CZ$5wO?K8(|~+luo_`_!}*sVDOrVf*ZY?Q~ZZVK``*kh`x>8s3_8&8sO+{h7>?H78nVsE30RBgFw2%~SosA?)$ejWn}zu9OdzgDZ#Koo9Du*pVdjUMqz8K4n=udcJC0Sa9tvw$5 z!ReV`3&M>Eu+WDBIk@Cv3*4!0L3vK6ExFKhr@T3%%-tM01e>u|&@OmkaZS)Z0gG~( zyqUA0B(28wB0Qv-TEqNw$802)T)<;PQ)Vbjas-O6T-xm1r*mt>SLDqw=9UzGrYkQL z?A#DU29(?_xhtGu{*>t&p%5>K#vlJmM-?~Y4#OT*3J6KqH$TeJFe}r*+rr&J3Hxk% zhY>OSIvEp(ZRI%A>)Dwszn|(7@_CS^-WXq)Q-nim&i<38rRM;ap3}VAHX^C*R<_PA zx$-9bk;Rt3nVEPc1(&~|081K%bJqgp2tBc|J02Q(lCL;AjT$jhyJG3H-ndG3#Z6}h zfB|PlERTO-2(bdV%)eLcdDg2NYaIu}l0jD{CM--$Ei*C0U}Bnm1up(u-sW|emi{fc zGOlk!!exlYf9pyvb0vGSlW!MWD!q704wKQ%ZR`4{cuYKL;6)v#(rMl$$sRn90P}z#i-5AK-y*&mDaN)_U1-}cko4Sh)lxUPre(~P+UR$GdV`baD?nMEF<`Q~$ zcSZ7Utk^%Gz=V>;yjW6-zgUo=t?dZYKQs2e>iTDQR{-9PDBX2GU8%$o++D(nhS9@YSf1m_+z} zD^3BP4{^v2gn5i|3~n5dG;sf89h(@SGz67GP0?a%rSW*CSw2CdysQ(8Rtwbqv36`1LSShVg=Lqgi0xZRnHpGY{fxEvI`W5(^B z*)FR*76s3u>?3Ovof!wEE4e4UFXdF3nLV^2zz4ix3a}!5zFiQ zTHjy#zSGx`)F5ee(o;#3lMeRHNt%%~JL$P3ZNJa@rS{9{ccuSB1K7WveZT38Wej7_ z_XtIA53ln}1RS4tT*2`shRLL5-vW(>=irKX2i`F;6|ZT8h{-17 zw+_AWxP7MaXZtkfHgYsE9)I58Gsv7j1R1|Y>`cYaaL73;G-BzlSi-ZC_;Th+FF956 zQ^Gx)alR(urY#`uX5)KF=P!?|C}i(`iACa1CGLts_9W0(8Z4H>dTbXJ#Sq|D#UFQH z9TzeRc5S*zJbmKaiSy-Wvi6xyxQ!={WR;p$#TT47e}srVhq@&`rFFVBwvdFF{5*Sr z+#j2tEWpuT*fZv{JbO$0zNuWp*|o0j`FZZxgzn(*YdrZ$Vn0{_g-CqChR^bVH+-2l zN6zm3vt!MRz`;pux{;jYWUi@%}#uEb(uz!uKV6>>VULb&dFiWh$u z7i;l%H$q%}zRVNnYg`Tuo=X-MYrll0P$+i)G7rBuG>HqfuBWuF@fz1+t!uuf&=vD# zo@=7UHBk$1I=VBEJ>wjSx4vxMTYJ2{^^`8Kx!mV7JY;AlLKwFrSUk~Fm)=O6s7*NQ zxGhg7cXK(1+)d;rFwx;J3x}t+NZ+$ZdZ|3i>(z;DLxx7!BSE|!dTHFa*03)FnX^;& zUK}@WOiKLEqf+EsfOt}Gj}TA0(0>;cIwlD}Gc44Ig@xnd3y`0Q9rcMtiKo}+=eY*+ z4+@TfU^|_7Q|KXjgi1V4hi0HRXOTuMDip7bN*RH7SH0uJ)97Y17|?ig4Sz-=2wpm>h7J*rIrj%R&*QxweY&t) zPYH)@LGuHU#f?Y2?3Yl(y<(vouisAdxV59?SK*`_hbL@>sc)|OC!P;fT(}VMTE!({ z-M ztF%2OUe-2?(v28$b7R+ntt)?BR<`VnSSTJFAUCA>I$M$)M)U7r$<)Jdr%4QS$XyHE zf1>xg{#&ttaRZi~>soNq9G zpvc=lTr(xbl9fMiyaUb7uz9rz`W<4x6OQJhCQ}R&z_xQ`_Hq@o;-JI?2x(k*&Qj_ zF?)9GbMt1-wNJCfPEJps`OMro)8^WP4FhLp%$zzccACvL&lYUxH)ZZT+nmV|wat6R zHhE4g#OKVMJJ~*S-rQhAZMFX^Sg>WmmbwB{=FPKre0H9VY<5!Wf6g`y#nu(^W4{Lc z8t`ktuK~XX{2K6Uz^?(n2K*ZEYrwAozXtpo@N2-Y0lxb#)!0z}9*%}zsyJUNm28fe}u15KV1 zNAnRBZXAuLS<{}UX>(@UY5qLhRGK+w&a|mBC)=mdv<1_icHn#NwD}#Bq#4s}(}-P~ zlU>2HA(n0@^{Y9h+gY}@G)XCG?&LYs6fk}E3LJ9JvVRWT>CT|&7L=Jmg70< zMG2tiqJ)geHkv$p_B=bqQ3raMI#Fxt-I?Zs=uORgQy=^XN~FZzHw53yfn$n);JvVKxQuBP< zOz7|F+4Itw@@J-_@adDEw$IF9YMnlHS}jhWHfG##yaTDj76 zwZ!SRX_KeY^qF&~PMP#EWnKow*`b{>b%2or14;VS9-;;wFO6@n2 zeGMFB88mX_pn)`Vu99t@L(QIUpE`3cZu(RZ%J__}`7~#rn#lccF6qG!U;FX#5z0sN zZ$7F(wDQsan-5EmRT}aC=jHbp_Kzr#zu$^%%wYpxJGF_;Y4p2RU<={{c%e2fA>N%}YU#r2yW%pYAZ{!qR6qxIsC)r*g*7oSltzMx(_yIy>4z4(@T zacL75%j2IWm(TV7uOCYCLM_2mt6S5P!&0bYt5&TPWrg#+CP0g^5)l~??u`mC^AD63 z5b!`0kx*|-9v6JVy>#_9-KmW1reFTniLRU{Q_21=N0OMR=Vd z(hwBL^F}@*L}B$jAI9@0{9_-j&R|f|gL!iZIugpO=}IC|Gc25AX#uUFFX$xQBs15U zOXlWq&uy`9NwE+#^5j?=H0ntjH1J8HhvqtF&u&K)5y3@7vKhuxgrJECtZkM$?UZY1 zgHSzyE+VRy46a2HCPQdwsNN6}p^XSLhD1b|BZ49#YSQUB8&>z&^rt7!ogUjO78?>) z;knPmDvN&X^m(>9lkMrTSkhx>&zw7J+SFh}?U;TL{4n68^6x>`ANx-lxH~eC-yA~p z9d`vA=v!PbZYZ(@bBD0nuz%NYswLFS7xo>>E^IOC$N*b~wlJVUh-GvDLN^Aq2t63k zVT0}o5Ur<|D4l^o+CpzJV4ytum;obgrUC|nXg!@^Aec7MB?dz1SGvPMC>2u>DvUPK zThx#NGv!lf2Eyn)>dinn<bfW1rjDgNHjixZrg=BIu(3OtU`wYa>W%`nVM`$no z%0M^TLz+N#uz-Qy^c$5i z(1*UJM=?{Q`_chQVIYZ)(o_cekwkU|`qLT8WMBaOOxqb4NHgdR1B2)gRWo3rPich_ zU@+~c-3&ZNU(sO(hR{1y!NBA63AGIZc!Dm{UczkaT1k@_7)eWLF$1IMAM_prPf`JW!oXTqP=E=vj~XyAk#9mvtGr%*HO(6`-pvBaXftmDAieuneno4~b zm_=XGWCmta2ED+*9J0}e49ulDRLH<_0Hc#alPqcDJf&}Z}*12+1TrZA9BnY4xh zJ3UXk8F0{YI?6x>U7*Vh%%`}l`^oHej+{sAd6;`nSmuFQWpkZq9Pi_fRjF_7Z`XM8{2vY{z)&;rwlBm zRaDHtGWwXVF_29^P*fyu$Gc3xFx_k zdW;Gfc#EE-7Oeo@rZMz11Mkpq+Qz`U2obGuc@Lo@1MefmwZSD9p)UjL5&qE@mk($J zy~MxAO=1~n9jg7xcrW=kAZUt*#mI- zgVN}42F@egVBkUx_!HnZV=f|8GH|H|Tn4zu7#V>EB9zvEzW@Rl<3`XkaHR%ZMP2VO z=5K`e8Msyht^*V><_5wmgK#NBxMacQCUW%{3~&n}nSt8~BN-@1NM)b`VJric2q-{9 zckpFnpb8*^fx7@NFi;JU$-q5;ml*H>yv%?XU?~IaypYWR2av-6JDn|OKmb_DfCk`I z1_Ek;7T`6;=m1tRpa*!Jfk1$@3>X03V!#OS4g)~|xeNpYY-AvWTa6J65XxrwzGEPYJ51j*(14py#~6s_oOGOlhMb1V z8EAw`GdBP<2FPNd3BXGm0h$85%s>plQU;oFsqi=f#DY1r37|Q^bp~1hlrhi};1&a| z0BAEnYk(jI+5m(w&=x>u;2{7$51<`@mVt)>3=G5pe8xa~fP4lz0DQ>+vqL2YIsxov zpff-b16=?PG0+v@Faz;iI$dYr5im`*0CWSGz(9A7Esq$lJ-{g7(HhVbAc!UPVvGr( zFBh#CxP~OC4kLsN|H_Qu3`o$Bb|lAEdw@}#Rs~OTO;nKLOVXv)lv4}F;8rRn*Mi4u zWNN_^s6vsc1!K4#HMx9X826~k)PmXqYk?JYc`)Aj|I=V7*HgJEnxR}T6^uo{s#(9r z)pYPFfGWm}uSsG`Q2IWhhN%^v2!$(mY!ZMXGnq@ElWe9;sY!ae222IevAa42H$@R1 z#wDuRr*XaM7#nrdxIT1_f$3adHEBARq=IK^%9&BqjF~kJtF3DqWR#L?nf|CtY2mXq zNwc_qYBOeY{nez|+yE8y=LV`^I5$WI&(~D?0%xJ~Of9t~*MeExV0HXVscBCw^CB2! z_|*b+%yVqavz-?}9rFNBa%?*TaB{o~QhYMHmoO_?l5PQ-p@2l+)I&`9^x?R`zFYug z)PJdnujcf`BhJFh_2mCqFTS*1d|ADCcD=Z(UOcB>T&x#gUN63)UVLS}_$&3|uhxsd zRxiG)UVL@E`0MrJZ`6ywSueh(UVLr6__})Wx9Y{;t`~o&Ui{s9@%QS*->(cuzLi|5sgD?W^x!G`Y->!ok47yqbUd|SQv$Mxc$)Qf*wFTTBA zd`G?bXZ7Nr*Nf-Zi+@os{$;)R&U$gFUVK-*`0je~uj<9Wt{4BNUVKlz_}+T)f_m|N z_2T>M#S81j57dhvtQRk;7cZ_CKU6RNZN2#6dhsLm;@{Pa_vWhK4Nn`*4Spv)O@Q}H zLy3F<_2soRoY&DvUQc8BK$^rGXbx|rfACG=7>l6{z8Nj%V`&-RoL2BH=ncLVt>xRm zSJoD8vWMUyYX|4p!|;p6!6nuK-ms1oDs-X-LKis1x>6G%p4teHP)DH~{9@fHUg$vy zLQlBHdQp;)K#vK%;T`Kk!-T$+CM3~Bp+B5t18Ax+kY)?R;3rFli)=W&V<~Wqjet*V zB-~-6;0b#YPO#DNf2G3pl?JcZ7&yGF@O6!an`<0ATu;HdH6DJg322PJ)=~2Cd zp3u*SH){c<=%1%a`WNBQT1eCNi)fBMlN|cRl&R06rTUlP-*VD&{mb;OekojB%jg4r zHs$Mc;N=o&w|+V8)32a!^(*PP{uMf_e+^ErRrH5`HQmv_PF&!d@O`ZzUEo@37PyYu z2EGj!*gMoA@Ld`d_#O=l%!MaxJ&g+dfMy47Aba2@IK(#7^MQHf3fw}k1#X33>?3+J za2vfB_z7HNpVEfF?et0DXYh`FPM-(n)1JUD;UL>dMS&6>3*1F#19#J(fnU+zf#1Mi zwudSM_Y!X?pdiCOiZbk{SVJK_Y&bxV7>eLVE2ad)A+i|0rDVeqc+5z42PRczZgpCg5fW^Zg5kX;VM-buEGCygLq>Z>5R9@Xe_4?V+CBawgF11`gSv35 zg1T~V1jTdj1a;%2pzd5j(4*Y`pq|{ppkCZ}K?&T?L5bY2L4CN3K}p=@pnjY?XaILB zXdqV|G>G#C_2(#fFc%p77-tTCoQnt^$~6cc#4e5ZtigCRqkl$-`ug#Yuq29*SQO!H@HioWn6jaEv_>3Hdh^5&S^~*Tr<-hu7#@XwmG{2Y^xf6k=mUoZvoOH2m- zWs{L#W(wwArV#!$Qz*aMWai&CdAWB@;rx121i#r7$$xBWz<+Lv=69MJ@!yyl^ZQLr z_=BdV{Ewy>{#R2o{!ddZf7#T6FEzE~Z%-Z)+`x8t?uhxs6L93NtC z&zsF1_y*=qd_!|*zNxtj-^$#Tf5_a8k281YJDPj&-OZ2kJ zYo5fHm?!fm%}?{E%v1R@=4t#d=IQ(;^E3S4<{A7A^GyD(`B`2Fo5gFxX7l>6IlL)s z9v>d|93L5GKeJ~nIt-#+Yl{*ka3_#R;|@_oY=@%_RU^OmqB{9|D+ z@lS*~`H^8S^JBx7@{_`{`6*#J{PZx9Ul6vO&kkF`FArPEzaI7~zb5Q8{;jZ8{JUYR z`R!q^^HSKG{O+(d{5N51`GaBW_##@gd<`_!i+?`Bvc{@omGm@sEUm!gmkf&i4-A!4D7rjGr9-1wTFf zOa9sLoqSff#J?QAi(e7Gn|~$zYkqC`9{%m{z5M&(1^kEM`}mK;_w!$b7xFv95Au7$ zi}`)whxh~G-||0%ALf4w|BgQsew6^NS+N z`DGCm{Hqa_{Hlm5eoe$({{4u1{Q3wFzcIqge;mOHpGNS)XAy$%b%aJZ7@-x4BXq*y z2)%GIB2c&*VHB=K1PNsk!NQ%05CM~2&_tR9ZKPQUj0_WkA|r%|$S5HyvVqVrGFoUJ z*+^&^*;r^3*+fW;Y$^orSNWx(FpvU4=iR;)RN+ zM+8HIZbH)r-G$B#dI$p=JSwC%=qb!>&`Vg@AVGMgL89 zqmzZo=;4B~VTusbaD>pM;YeX%!%;$7!zYDj8;%whHB1#=ZI~u(XgEgrvY}P@w&7Ue zmxkknYYm?g_(tP}$VL-{hZ;>35*kesk{eAHCO4WQ*c&}9ENe7Xc&pJg;p0Zrg@Q)U z2qzlN5H2;EDcouFtPs?Ame8#6Y@uu8Il`dEbA>UD=LxeKKPO~1{)g~dW1FzCak{Xx zv0XUa*dhGdI77JJc)lPsSs+9;d0uGOUCf(8Sj-xsVa!^gNz6K-P0ZUu=a_edM`PXvs^a0Gt7f*y7{g;=^e$ zZ~*vsc@sV6<39#J1eiHvwu67%#}|Nq0yq$SA^4#_{sj18z((+=z$g3oOW=nC2ZJvK zpW@^1fFA)I3cebA%_m4;l6cI55GpX=pZaMiG*Cb|u1$mpA4{;%Re3y!f~9_6zPFEO zxsvMekNe7L2!2?dawhxa8-t%(M}Dr*o<^dbO~I!NZE;mUZ-E~Lz8RwL*Wru6KMB4$ z_#<`rGNA*F2Hz5Vg`he~SxL<_9SMFIym*HvK^pdONc{}cbfYxztj3X=&NVbn5#4AE zcqX~54!;w;6+C-T^mQHn3iz?$JAl7Yhi@LxjmCjzk8Ron+%G>B{8QlBvzBpncoF<~ z@a*}@t9AGS@Dspy1Anj%e;fQn@IAm+)!`r3cB4t)*~6Gl+WYlR)b^yw;MsGRsaodb zQa@|KPXW&!y1ZM5FVVKAr@{9He@c7*zT5*p6?{MNyzV~VPS+leLyiW3?^uT)t?LLs zB1eP3kJa7RzZ3j3;0J@xuEX!pscjwtK3~VQs(${^v7Qnhq~TeZ?tc5D^=#x|tRXbk zH&QUWbkj#GcsQ<)>e=X3Kf`=@1fnVWuo@aCx3)9`?HL7Tx}J?9_2beU>E<^aK6<`SK;onTc|&;CI(4=U4FTGY;X8I=m*3jZDG|3U~)4kh$R1PrE=> zej=hB0`IpcC9sVmFd5fTb@+@xRS!>te?IWO9##jc^LHBfHv{j_-`qfxQqD8DZt%%4 zV!Mx@3H*5-z96tGJ&Sd37WksT_Dodylm%L7HYd;=#3}=mR1()m4XXa<0Vf#l>p#Vy z>gpfhNBuv|Tz!lrMHR1II5_5JXKp@D0>ZMv^N3u$?45V_2MLB@K6ZzluT0M_cl^`N zN6+qXGt+xLJ+pTU2McF{ARbb2~AzFpxX@x|e0mS8y=uA0oNOT^8Ukja05I;AB z_9+|stU>yCDA4EOkoeef;E#sHR`kMiA+h0g;GYl85X8@$p;PK8^gjVk{}oU0CMG?La;o7CkBRiLm(69pIk|2fp+Y z${a(TcLM)ISnNaPlT*9Yao~4>KX)qdvCDw31OE*0%g6AKOw$j`;>j`m3sYjNdw}0J71-(_l&9zO`2U+zLEoR5qJNH;!vm+Mg8u$}idK6$Lhz5N zY33=pAaYopK)d&YpNY^6m1h{)#>@jqk43g>RN?fC*yJlfPDVrr%Dg`!bLXqzzZ?nX z&f}3i>IT^V>%gCi1bfOKBjV2w0)H(MtRa(8!5;#?B^u!8M#bkJ27Z1t@cG@*uG&ET zj{x5rZ6lTE?&v{vGy3%{i1$YKc`#1h$XfJmAg80jTJ$^J?stK|IM(hP(M#1y)bkkd zH>1H^xOn?1{4L@P97|B@L)*!_LN4nk9;GZ6A_t{v6viV@cb1~Y{UQY=GVp5?f&TXU;YIC z`9v_^f3Nj?4fv~LdQK)qx7UGhNrsWi6HCr8^Jk>Vq|8kM_9jJ#zkuJL4Cb$ql)dr| z;7dud6_sDt_}{>v7{l*Nich`?{DGwSHkJQIQu;-QD;`M({rYiI&;1GbA|G#}(l`sE z>z@Sv`dIz%+aY~F6Zm;MLQ)v%2X?%`ljkhpyLS9$>m9HyJ!el}rap~v*$Oc{eL$Vk zcxpPT?gAeIo|z8pQ<)Z>!@!Mc`un2%E|I@7%5RXt)CIb2@)M`zZ-;bqa2j+Mg-knuZ1 zzXb2#!mvJ93ag?%egjnI1gfFmMBE5^$rLk?-@}MZsx!}1LMQoKA76c1zCdATKob*M z-nxlipv%i|1f?!k7gb;$R4w>m&js{6#}%uUDUbe+v$vkkV>%eK<$LxK}^Uo^bu1 zzI!&+zt1l(?eEw6Z`b8E>%ZxJ{I2or0DWf2G-ERCFiCnc72GTDQLnrwZ>G@a*aS>^ zkzcR$&+F$^8sD$`;o+NUNat7nbv+xpyhq_0UOQrET|ewDxL2PiZ+_pyy>a;er_(o2 zz{M}6@#3KZ#nkcq+w(uq&hLJI#6SLf^?UQe^FvSeD2?-%#`^2w?=Ib={pYRrdpo_} zY5VV1J@2&L_p1E=%5UDQ{{5$R-)_8B3MZBnoqAGf+F>#{1B8DZ1eTk?*UTKPs`JR* z$P-5AEixvDa-z*jpd09|quZ}27GgB>Blv!Cc=F>v*LKZcs zGYw@{sgN?;CWq*1Y7Q)yFp1j*qeFLn&MP1>ynySi7QHYSHi-0wT_UZ{h$WlztfM6K zg)CbnEORSeNf{YR#!zyGk~KsaDoRttDG1_skv2N6mcjYZG2sR)TxPJsY9N~ zv3tH?9i63`C~O!6aj-;m&l_4CdQ3xSAPzX-bRl44+1?v4i7v^Jz^I#IhCw)Nn3|%X zVNePiCPLx3MBVxk?yut_vX}txeF-K8!tvLj6pIbQ;ntuM)(ZxD4Jd;ne2GeAFLB6f za+aq%NBdHaWw$8*NQ≈;0F74>_H1Jk(JLafS>qtq9a#g6fv+3|&2w>di5QMsUj^!o zj1L3~`_Qm|q;Ic{xA&H}EU_<#dZT&{0Vj(1bAM#V0=|*u2Y-X-_-{=q1RN|!frIL} zac~mvjUlCM5-9GQJH=t&0BJBN`W~#$v}}sS2cike_ygTo=OJqJg)ZB!%|NG*h)&CF z)!jPFUPL)+IXbk(NjSP3K&Ow320&$en!c|HcXUX(^=8u=z-8fISTmI=5%Ii$;#DoR z+uh+{1u_x%Cpc|I$I?toQ}%Qka6L1$`LxNjy=8{^Gmhi?MOq<)n7PVgt)$F>bVO2G zTZXH+YJiwgV~92eUSlJl8*oUhGDjXG4V%Sx!+-Lb)_oE2og*+E`Jr z4G@tO?$TUES*QyZ8=lnz3u=!%nJ*~NvqTdaOHB1Tb&O2hr%A;eTZ?uwRO&iSkM`hg zBy(e~)3q=~A@><@*SS$MZ)6ZSZ4Sw&$;?ZYYQ9vOCxG z?6z$hlQ!m}1&Ys<#a^8zD))xn5#^5v)50wv+8SW9j$=DD+gL*3p51p>GIh)tcU|^H z7nWML`>3>4Ki=&uuaJuE4o_!%>CqC8ZxXuO1ig^a1Hsq@16PGVrAMwm%myY@&2D+J ze|d;!2Dd?@KugyUQ>*9PvrVgNs+3ViwzgQwmx(T2xtLRiuE8+UsS?E60+p|2(Gafxz>cb6drV16ad#<6Dbl-y{e&p#L`xEqYFZQAVL}pW z1EIcwlt`>yLv=6Gok9!B- + +#define MEM_SIZE 40960 +#define STACK_SIZE 64 +#define RSTACK_SIZE 64 + +void f_init(); + +void f_cdef(); +void f_immediate(); + +void f_quiet(); +void f_loud(); +void f_interpreter(); + +union cell_union; +typedef union cell_union cell; + +union cell_union { + int i; + unsigned int u; + cell *p; + char *s; + void (*f)(); + FILE *fp; +}; + +extern char mem[MEM_SIZE]; +extern cell *HERE; +extern cell *LATEST; +extern cell IP; +extern cell W; +extern cell *rstack; +extern cell *stack; +extern FILE *IN_FILE; +extern FILE *OUT_FILE; +#define F_NAMELEN_MASK 0x7f +#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)) +void DROP(int n); +void PUSHC(cell c); +void PUSHI(int i); +void PUSHU(unsigned int u); +void PUSHCP(cell *c); +#define PUSHP(p) PUSHCP((cell*)p) +void PUSHS(char *s); +void RPUSH(cell c); +#define RPOP() (--rstack) +#define RTOP() (*(rstack - 1)) + +void f_key(); +void f_word(); +void f_emit(); +void f_puts(); +void f_dot(); +void f_cr(); +void f_comma(); +void f_bcomma(); +void f_create(); // name -- +void f_cdef(); // func name -- +void f_doconst(); +void f_compileword(); + +cell f_lookupcp(char *name); +void f_execcp(cell cp); + +#define CDEF(name, def) PUSHP(def); PUSHS(name); f_cdef() +#define ICONST(name, v) CDEF(name, f_doconst); PUSHI(v); f_comma() +#define PCONST(name, p) CDEF(name, f_doconst); PUSHP(p); f_comma() diff --git a/minijort.prj b/minijort.prj new file mode 100755 index 0000000000000000000000000000000000000000..b52d00d328252d11dc6f9168dd4202f56b3d0247 GIT binary patch literal 3743 zcmeI#Sx*yD6bJBgg)SnvPyq#(`_KoMP_Qg2`aqpltZ~|=9fM*;1!_e>uzX;il45FNyv_V_&Yd%JZ!be<#^_75bV*Hy5?$M4 zt-W$(dq+%`k|-!F5v4>nH+`|(r3oZxh$Xsb#`jGhm^}~8_z|nrW78+5PtE>krq9_N zdcoGy8$K7k1@FKxBiq>Ao>avAi;gyNaQe-3oO8jJ{vRB&a_QrWFAA4 zKt3n{lNm7u(Nr)E6aojB&WIvVjI;#I05d@;CHTmqND6;Lj` zyhP(~E-^@2UDVK`{(!b-t=C7`vfC<>b6DeFLD;h2Dn%|;xrr7D3%P4}d^ZP+Dl3Vq z#6b3^^Ye(+Vh%0%x$Bp#CT&G++KR<#E0(0KSemw?E^WoKv=z(KR@Cz)^|zbGSCC8N zSt!L<5n1_{ckOjYV;%*q)ZY;Hg~l+!cp}z4hO#l2lR+S8Pch7qDLC$VRCK`=I`!mZ<7mLt#Zr*WU26u68(mG&-L{5#5!9#Vu@5E8=i=s zYF{S(75X|^(d3sELFxR{=gwq4nI3aj(Z~w+dt)tq@p$SLq~5kn2O0f1>GZAh1w4AT zZ#1LNCiC8*?wG-+?OKRnhMucaEc3_$FrKHxQgX!ehNIBeLHly2V|(Kj2>-3>!S&4`Jqm z;Y}x(-*jlOmgb5AK9N#W#4x?2+jN6Y(OwEs2hHLS&w* zk)B?2G%6J>cDeYahbGZy&PRGjj#Nq`YcpSwN_}51g+r3xXB8<7;Bx)&yd3rV!>-YH z1S6yGh^&u9BZkLFvDfhOBXG)n{vdYY+a{-_(PI9S+j${MsF;dqIytD2KO+tQU*7<@ CZT7wZ literal 0 HcmV?d00001