| \ stack. Use different names on both sides of the '--', if you change a |
\ stack. Use different names on both sides of the '--', if you change a |
| \ value (some stores to the stack are optimized away). |
\ value (some stores to the stack are optimized away). |
| \ |
\ |
| |
\ For superinstructions the syntax is: |
| |
\ |
| |
\ forth-name [/ c-name] = forth-name forth-name ... |
| \ |
\ |
| \ |
\ |
| \ The stack variables have the following types: |
\ The stack variables have the following types: |
| \ df_.* DFloat * |
\ df_.* DFloat * |
| \ sf_.* SFloat * |
\ sf_.* SFloat * |
| \ xt.* XT |
\ xt.* XT |
| \ wid.* WID |
|
| \ f83name.* F83Name * |
\ f83name.* F83Name * |
| |
|
| |
\E stack data-stack sp Cell |
| |
\E stack fp-stack fp Float |
| |
\E stack return-stack rp Cell |
| |
\E |
| \E get-current prefixes set-current |
\E get-current prefixes set-current |
| \E |
\E |
| \E s" Bool" single data-stack type-prefix f |
\E s" Bool" single data-stack type-prefix f |
| \E s" DFloat *" single data-stack type-prefix df_ |
\E s" DFloat *" single data-stack type-prefix df_ |
| \E s" SFloat *" single data-stack type-prefix sf_ |
\E s" SFloat *" single data-stack type-prefix sf_ |
| \E s" Xt" single data-stack type-prefix xt |
\E s" Xt" single data-stack type-prefix xt |
| \E s" WID" single data-stack type-prefix wid |
|
| \E s" struct F83Name *" single data-stack type-prefix f83name |
\E s" struct F83Name *" single data-stack type-prefix f83name |
| |
\E s" struct Longname *" single data-stack type-prefix longname |
| \E |
\E |
| \E return-stack stack-prefix R: |
\E return-stack stack-prefix R: |
| \E inst-stream stack-prefix # |
\E inst-stream stack-prefix # |
| \ these m4 macros would collide with identifiers |
\ these m4 macros would collide with identifiers |
| undefine(`index') |
undefine(`index') |
| undefine(`shift') |
undefine(`shift') |
| |
undefine(`symbols') |
| |
|
| |
\g control |
| |
|
| noop ( -- ) gforth |
noop ( -- ) gforth |
| : |
: |
| ""Perform the semantics represented by the execution token, @i{xt}."" |
""Perform the semantics represented by the execution token, @i{xt}."" |
| ip=IP; |
ip=IP; |
| IF_spTOS(spTOS = sp[0]); |
IF_spTOS(spTOS = sp[0]); |
| |
SUPER_END; |
| EXEC(xt); |
EXEC(xt); |
| |
|
| perform ( a_addr -- ) gforth |
perform ( a_addr -- ) gforth |
| /* and pfe */ |
/* and pfe */ |
| ip=IP; |
ip=IP; |
| IF_spTOS(spTOS = sp[0]); |
IF_spTOS(spTOS = sp[0]); |
| |
SUPER_END; |
| EXEC(*(Xt *)a_addr); |
EXEC(*(Xt *)a_addr); |
| : |
: |
| @ execute ; |
@ execute ; |
| $4 SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
$4 SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| $5 |
$5 |
| |
|
| \+glocals |
\+glocals |
| SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| |
|
| \+ |
\+ |
| ) |
) |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| |
|
| ?dup-0=-?branch ( #ndisp f -- ) new question_dupe_zero_equals_question_branch |
?dup-0=-?branch ( #ndisp f -- ) new question_dupe_zero_equals_question_branch |
| ""The run-time procedure compiled by @code{?DUP-0=-IF}."" |
""The run-time procedure compiled by @code{?DUP-0=-IF}."" |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| NEXT; |
NEXT; |
| } |
} |
| |
SUPER_CONTINUE; |
| |
|
| \+ |
\+ |
| \f[THEN] |
\f[THEN] |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| : |
: |
| 2dup = |
2dup = |
| IF r> swap rot >r >r |
IF r> swap rot >r >r |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| : |
: |
| swap 2dup |
swap 2dup |
| r> swap >r swap >r |
r> swap >r swap >r |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| : |
: |
| swap 2dup |
swap 2dup |
| r> swap >r swap >r |
r> swap >r swap >r |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| : |
: |
| swap 2dup |
swap 2dup |
| r> swap >r swap >r |
r> swap >r swap >r |
| SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); |
| TAIL; |
TAIL; |
| } |
} |
| |
SUPER_CONTINUE; |
| : |
: |
| swap 2dup |
swap 2dup |
| r> swap >r swap >r |
r> swap >r swap >r |
| |
|
| \ digit is high-level: 0/0% |
\ digit is high-level: 0/0% |
| |
|
| |
\g strings |
| |
|
| move ( c_from c_to ucount -- ) core |
move ( c_from c_to ucount -- ) core |
| ""Copy the contents of @i{ucount} aus at @i{c-from} to |
""Copy the contents of @i{ucount} aus at @i{c-from} to |
| @i{c-to}. @code{move} works correctly even if the two areas overlap."" |
@i{c-to}. @code{move} works correctly even if the two areas overlap."" |
| : |
: |
| tuck - >r + r> dup 0< IF - 0 THEN ; |
tuck - >r + r> dup 0< IF - 0 THEN ; |
| |
|
| |
\g arith |
| |
|
| + ( n1 n2 -- n ) core plus |
+ ( n1 n2 -- n ) core plus |
| n = n1+n2; |
n = n1+n2; |
| |
|
| : |
: |
| over - >r - r> u< ; |
over - >r - r> u< ; |
| |
|
| |
\g internal |
| |
|
| sp@ ( -- a_addr ) gforth sp_fetch |
sp@ ( -- a_addr ) gforth sp_fetch |
| a_addr = sp+1; |
a_addr = sp+1; |
| |
|
| ""The primitive compiled by @code{EXIT}."" |
""The primitive compiled by @code{EXIT}."" |
| SET_IP((Xt *)w); |
SET_IP((Xt *)w); |
| |
|
| |
\g stack |
| |
|
| >r ( w -- R:w ) core to_r |
>r ( w -- R:w ) core to_r |
| : |
: |
| (>r) ; |
(>r) ; |
| code-address! ( c_addr xt -- ) gforth code_address_store |
code-address! ( c_addr xt -- ) gforth code_address_store |
| ""Create a code field with code address @i{c-addr} at @i{xt}."" |
""Create a code field with code address @i{c-addr} at @i{xt}."" |
| MAKE_CF(xt, c_addr); |
MAKE_CF(xt, c_addr); |
| CACHE_FLUSH(xt,(size_t)PFA(0)); |
|
| : |
: |
| ! ; |
! ; |
| |
|
| ""Create a code field at @i{xt} for a child of a @code{DOES>}-word; |
""Create a code field at @i{xt} for a child of a @code{DOES>}-word; |
| @i{a-addr} is the start of the Forth code after @code{DOES>}."" |
@i{a-addr} is the start of the Forth code after @code{DOES>}."" |
| MAKE_DOES_CF(xt, a_addr); |
MAKE_DOES_CF(xt, a_addr); |
| CACHE_FLUSH(xt,(size_t)PFA(0)); |
|
| : |
: |
| dodoes: over ! cell+ ! ; |
dodoes: over ! cell+ ! ; |
| |
|
| ""Create a @code{DOES>}-handler at address @i{a-addr}. Normally, |
""Create a @code{DOES>}-handler at address @i{a-addr}. Normally, |
| @i{a-addr} points just behind a @code{DOES>}."" |
@i{a-addr} points just behind a @code{DOES>}."" |
| MAKE_DOES_HANDLER(a_addr); |
MAKE_DOES_HANDLER(a_addr); |
| CACHE_FLUSH((caddr_t)a_addr,DOES_HANDLER_SIZE); |
|
| : |
: |
| drop ; |
drop ; |
| |
|
| |
|
| \f[THEN] |
\f[THEN] |
| |
|
| |
\g hostos |
| |
|
| key-file ( wfileid -- n ) gforth paren_key_file |
key-file ( wfileid -- n ) gforth paren_key_file |
| #ifdef HAS_FILE |
#ifdef HAS_FILE |
| fflush(stdout); |
fflush(stdout); |
| FLUSH_ICACHE(c_addr,u); |
FLUSH_ICACHE(c_addr,u); |
| |
|
| (bye) ( n -- ) gforth paren_bye |
(bye) ( n -- ) gforth paren_bye |
| |
SUPER_END; |
| return (Label *)n; |
return (Label *)n; |
| |
|
| (system) ( c_addr u -- wretval wior ) gforth peren_system |
(system) ( c_addr u -- wretval wior ) gforth peren_system |
| u2 = (c_addr2 == NULL ? 0 : strlen(c_addr2)); |
u2 = (c_addr2 == NULL ? 0 : strlen(c_addr2)); |
| |
|
| open-pipe ( c_addr u wfam -- wfileid wior ) gforth open_pipe |
open-pipe ( c_addr u wfam -- wfileid wior ) gforth open_pipe |
| wfileid=(Cell)popen(cstr(c_addr,u,1),fileattr[wfam]); /* ~ expansion of 1st arg? */ |
wfileid=(Cell)popen(cstr(c_addr,u,1),pfileattr[wfam]); /* ~ expansion of 1st arg? */ |
| wior = IOR(wfileid==0); /* !! the man page says that errno is not set reliably */ |
wior = IOR(wfileid==0); /* !! the man page says that errno is not set reliably */ |
| |
|
| close-pipe ( wfileid -- wretval wior ) gforth close_pipe |
close-pipe ( wfileid -- wretval wior ) gforth close_pipe |
| clearerr((FILE *)wfileid); |
clearerr((FILE *)wfileid); |
| |
|
| read-line ( c_addr u1 wfileid -- u2 flag wior ) file read_line |
read-line ( c_addr u1 wfileid -- u2 flag wior ) file read_line |
| ""this is only for backward compatibility"" |
/* this may one day be replaced with : read-line (read-line) nip ; */ |
| Cell c; |
Cell c; |
| flag=-1; |
flag=-1; |
| for(u2=0; u2<u1; u2++) |
for(u2=0; u2<u1; u2++) |
| \+ |
\+ |
| \+floating |
\+floating |
| |
|
| |
\g floating |
| |
|
| comparisons(f, r1 r2, f_, r1, r2, gforth, gforth, float, gforth) |
comparisons(f, r1 r2, f_, r1, r2, gforth, gforth, float, gforth) |
| comparisons(f0, r, f_zero_, r, 0., float, gforth, float, gforth) |
comparisons(f0, r, f_zero_, r, 0., float, gforth, float, gforth) |
| |
|
| wcall ( u -- ) gforth |
wcall ( u -- ) gforth |
| IF_fpTOS(fp[0]=fpTOS); |
IF_fpTOS(fp[0]=fpTOS); |
| FP=fp; |
FP=fp; |
| sp=(SYSCALL(Cell(*)(Cell *, void *))u)(sp, &FP); |
sp=(Cell*)(SYSCALL(Cell(*)(Cell *, void *))u)(sp, &FP); |
| fp=FP; |
fp=FP; |
| IF_spTOS(spTOS=sp[0];) |
IF_spTOS(spTOS=sp[0];) |
| IF_fpTOS(fpTOS=fp[0]); |
IF_fpTOS(fpTOS=fp[0]); |
| \+file |
\+file |
| |
|
| open-dir ( c_addr u -- wdirid wior ) gforth open_dir |
open-dir ( c_addr u -- wdirid wior ) gforth open_dir |
| |
""Open the directory specified by @i{c-addr, u} |
| |
and return @i{dir-id} for futher access to it."" |
| wdirid = (Cell)opendir(tilde_cstr(c_addr, u, 1)); |
wdirid = (Cell)opendir(tilde_cstr(c_addr, u, 1)); |
| wior = IOR(wdirid == 0); |
wior = IOR(wdirid == 0); |
| |
|
| read-dir ( c_addr u1 wdirid -- u2 flag wior ) gforth read_dir |
read-dir ( c_addr u1 wdirid -- u2 flag wior ) gforth read_dir |
| |
""Attempt to read the next entry from the directory specified |
| |
by @i{dir-id} to the buffer of length @i{u1} at address @i{c-addr}. |
| |
If the attempt fails because there is no more entries, |
| |
@i{ior}=0, @i{flag}=0, @i{u2}=0, and the buffer is unmodified. |
| |
If the attempt to read the next entry fails because of any other reason, |
| |
return @i{ior}<>0. |
| |
If the attempt succeeds, store file name to the buffer at @i{c-addr} |
| |
and return @i{ior}=0, @i{flag}=true and @i{u2} equal to the size of the file name. |
| |
If the length of the file name is greater than @i{u1}, |
| |
store first @i{u1} characters from file name into the buffer and |
| |
indicate "name too long" with @i{ior}, @i{flag}=true, and @i{u2}=@i{u1}."" |
| struct dirent * dent; |
struct dirent * dent; |
| dent = readdir((DIR *)wdirid); |
dent = readdir((DIR *)wdirid); |
| wior = 0; |
wior = 0; |
| } |
} |
| |
|
| close-dir ( wdirid -- wior ) gforth close_dir |
close-dir ( wdirid -- wior ) gforth close_dir |
| |
""Close the directory specified by @i{dir-id}."" |
| wior = IOR(closedir((DIR *)wdirid)); |
wior = IOR(closedir((DIR *)wdirid)); |
| |
|
| filename-match ( c_addr1 u1 c_addr2 u2 -- flag ) gforth match_file |
filename-match ( c_addr1 u1 c_addr2 u2 -- flag ) gforth match_file |
| wior=FILEIO(ferror((FILE *)wfileid)); |
wior=FILEIO(ferror((FILE *)wfileid)); |
| |
|
| \+ |
\+ |
| |
|
| |
(listlfind) ( c_addr u longname1 -- longname2 ) new paren_listlfind |
| |
for (; longname1 != NULL; longname1 = (struct Longname *)(longname1->next)) |
| |
if ((UCell)LONGNAME_COUNT(longname1)==u && |
| |
memcasecmp(c_addr, longname1->name, u)== 0 /* or inline? */) |
| |
break; |
| |
longname2=longname1; |
| |
: |
| |
BEGIN dup WHILE (findl-samelen) dup WHILE |
| |
>r 2dup r@ cell+ cell+ capscomp 0= |
| |
IF 2drop r> EXIT THEN |
| |
r> @ |
| |
REPEAT THEN nip nip ; |
| |
: (findl-samelen) ( u longname1 -- u longname2/0 ) |
| |
BEGIN 2dup cell+ @ lcount-mask and <> WHILE @ dup 0= UNTIL THEN ; |
| |
|
| |
\+hash |
| |
|
| |
(hashlfind) ( c_addr u a_addr -- longname2 ) new paren_hashlfind |
| |
struct Longname *longname1; |
| |
longname2=NULL; |
| |
while(a_addr != NULL) |
| |
{ |
| |
longname1=(struct Longname *)(a_addr[1]); |
| |
a_addr=(Cell *)(a_addr[0]); |
| |
if ((UCell)LONGNAME_COUNT(longname1)==u && |
| |
memcasecmp(c_addr, longname1->name, u)== 0 /* or inline? */) |
| |
{ |
| |
longname2=longname1; |
| |
break; |
| |
} |
| |
} |
| |
: |
| |
BEGIN dup WHILE |
| |
2@ >r >r dup r@ cell+ @ lcount-mask and = |
| |
IF 2dup r@ cell+ cell+ capscomp 0= |
| |
IF 2drop r> rdrop EXIT THEN THEN |
| |
rdrop r> |
| |
REPEAT nip nip ; |
| |
|
| |
(tablelfind) ( c_addr u a_addr -- longname2 ) new paren_tablelfind |
| |
""A case-sensitive variant of @code{(hashfind)}"" |
| |
struct Longname *longname1; |
| |
longname2=NULL; |
| |
while(a_addr != NULL) |
| |
{ |
| |
longname1=(struct Longname *)(a_addr[1]); |
| |
a_addr=(Cell *)(a_addr[0]); |
| |
if ((UCell)LONGNAME_COUNT(longname1)==u && |
| |
memcmp(c_addr, longname1->name, u)== 0 /* or inline? */) |
| |
{ |
| |
longname2=longname1; |
| |
break; |
| |
} |
| |
} |
| |
: |
| |
BEGIN dup WHILE |
| |
2@ >r >r dup r@ cell+ @ lcount-mask and = |
| |
IF 2dup r@ cell+ cell+ -text 0= |
| |
IF 2drop r> rdrop EXIT THEN THEN |
| |
rdrop r> |
| |
REPEAT nip nip ; |
| |
|
| |
\+ |
| |
|
| |
\+peephole |
| |
|
| |
\g peephole |
| |
|
| |
primtable ( -- wprimtable ) new |
| |
""wprimtable is a table containing the xts of the primitives indexed |
| |
by sequence-number in prim (for use in prepare-peephole-table)."" |
| |
wprimtable = (Cell)primtable(symbols+DOESJUMP+1,MAX_SYMBOLS-DOESJUMP-1); |
| |
|
| |
prepare-peephole-table ( wprimtable -- wpeeptable ) new prepare_peephole_opt |
| |
""wpeeptable is a data structure used by @code{peephole-opt}; it is |
| |
constructed by combining a primitives table with a simple peephole |
| |
optimization table."" |
| |
wpeeptable = prepare_peephole_table((Xt *)wprimtable); |
| |
|
| |
peephole-opt ( xt1 xt2 wpeeptable -- xt ) new peephole_opt |
| |
""xt is the combination of xt1 and xt2 (according to wpeeptable); if |
| |
they cannot be combined, xt is 0."" |
| |
xt = peephole_opt(xt1, xt2, wpeeptable); |
| |
|
| |
call ( #a_callee -- R:a_retaddr ) new |
| |
""Call callee (a variant of docol with inline argument)."" |
| |
#ifdef DEBUG |
| |
{ |
| |
CFA_TO_NAME((((Cell *)a_callee)-2)); |
| |
fprintf(stderr,"%08lx: call %08lx %.*s\n",(Cell)ip,(Cell)a_callee, |
| |
len,name); |
| |
} |
| |
#endif |
| |
a_retaddr = (Cell *)IP; |
| |
SET_IP((Xt *)a_callee); |
| |
|
| |
useraddr ( #u -- a_addr ) new |
| |
a_addr = (Cell *)(up+u); |
| |
|
| |
compile-prim ( xt1 -- xt2 ) new compile_prim |
| |
xt2 = (Xt)compile_prim((Label)xt1); |
| |
|
| |
lit@ / lit_fetch = lit @ |
| |
|
| |
lit-perform ( #a_addr -- ) new lit_perform |
| |
ip=IP; |
| |
SUPER_END; |
| |
EXEC(*(Xt *)a_addr); |
| |
|
| |
lit+ / lit_plus = lit + |
| |
|
| |
does-exec ( #a_cfa -- R:nest a_pfa ) new does_exec |
| |
a_pfa = PFA(a_cfa); |
| |
nest = (Cell)ip; |
| |
IF_spTOS(spTOS = sp[0]); |
| |
#ifdef DEBUG |
| |
{ |
| |
CFA_TO_NAME(a_cfa); |
| |
fprintf(stderr,"%08lx: does %08lx %.*s\n", |
| |
(Cell)ip,(Cell)a_cfa,len,name); |
| |
} |
| |
#endif |
| |
SET_IP(DOES_CODE1(a_cfa)); |
| |
|
| |
include(peeprules.vmg) |
| |
|
| |
\+ |