--- gforth/prim 2000/07/14 08:55:15 1.47 +++ gforth/prim 2001/03/18 22:20:27 1.80 @@ -1,6 +1,6 @@ \ Gforth primitives -\ Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc. +\ Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc. \ This file is part of Gforth. @@ -16,7 +16,7 @@ \ You should have received a copy of the GNU General Public License \ along with this program; if not, write to the Free Software -\ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +\ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. \ WARNING: This file is processed by m4. Make sure your identifiers @@ -36,8 +36,9 @@ \ be separated by at least one empty line \ \ Both pronounciation and stack items (in the stack effect) must -\ conform to the C name syntax or the C compiler will complain. -\ +\ conform to the C identifier syntax or the C compiler will complain. +\ If you don't have a pronounciation field, the Forth name is used, +\ and has to conform to the C identifier syntax. \ \ These specifications are automatically translated into C-code for the \ interpreter and into some other files. I hope that your C compiler has @@ -71,8 +72,36 @@ \ df_.* DFloat * \ sf_.* SFloat * \ xt.* XT -\ wid.* WID \ 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 +\E s" Bool" single data-stack type-prefix f +\E s" Char" single data-stack type-prefix c +\E s" Cell" single data-stack type-prefix n +\E s" Cell" single data-stack type-prefix w +\E s" UCell" single data-stack type-prefix u +\E s" DCell" double data-stack type-prefix d +\E s" UDCell" double data-stack type-prefix ud +\E s" Float" single fp-stack type-prefix r +\E s" Cell *" single data-stack type-prefix a_ +\E s" Char *" single data-stack type-prefix c_ +\E s" Float *" single data-stack type-prefix f_ +\E s" DFloat *" single data-stack type-prefix df_ +\E s" SFloat *" single data-stack type-prefix sf_ +\E s" Xt" single data-stack type-prefix xt +\E s" struct F83Name *" single data-stack type-prefix f83name +\E s" struct Longname *" single data-stack type-prefix longname +\E +\E return-stack stack-prefix R: +\E inst-stream stack-prefix # +\E +\E set-current + \ \ \ @@ -101,29 +130,29 @@ \ these m4 macros would collide with identifiers undefine(`index') undefine(`shift') +undefine(`symbols') noop ( -- ) gforth -; : ; -lit ( -- w ) gforth -w = (Cell)NEXT_INST; -INC_IP(1); +lit ( #w -- w ) gforth : r> dup @ swap cell+ >r ; execute ( xt -- ) core ""Perform the semantics represented by the execution token, @i{xt}."" ip=IP; -IF_TOS(TOS = sp[0]); +IF_spTOS(spTOS = sp[0]); +SUPER_END; EXEC(xt); perform ( a_addr -- ) gforth -""Equivalent to @code{@ execute}."" +""@code{@@ execute}."" /* and pfe */ ip=IP; -IF_TOS(TOS = sp[0]); +IF_spTOS(spTOS = sp[0]); +SUPER_END; EXEC(*(Xt *)a_addr); : @ execute ; @@ -131,45 +160,40 @@ EXEC(*(Xt *)a_addr); \fhas? skipbranchprims 0= [IF] \+glocals -branch-lp+!# ( -- ) gforth branch_lp_plus_store_number +branch-lp+!# ( #ndisp #nlocals -- ) gforth branch_lp_plus_store_number /* this will probably not be used */ -branch_adjust_lp: -lp += (Cell)(IP[1]); -goto branch; +lp += nlocals; +SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); \+ -branch ( -- ) gforth -branch: -SET_IP((Xt *)(((Cell)IP)+(Cell)NEXT_INST)); +branch ( #ndisp -- ) gforth +SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); : r> dup @ + >r ; -\ condbranch(forthname,restline,code,forthcode) +\ condbranch(forthname,stackeffect,restline,code,forthcode) \ this is non-syntactical: code must open a brace that is closed by the macro define(condbranch, -$1 $2 -$3 SET_IP((Xt *)(((Cell)IP)+(Cell)NEXT_INST)); - NEXT; +$1 ( `#'ndisp $2 ) $3 +$4 SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +TAIL; } -else - INC_IP(1); -$4 +$5 \+glocals -$1-lp+!# $2_lp_plus_store_number -$3 goto branch_adjust_lp; +$1-lp+!`#' ( `#'ndisp `#'nlocals $2 ) $3_lp_plus_store_number +$4 lp += nlocals; +SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); +TAIL; } -else - INC_IP(2); \+ ) -condbranch(?branch,( f -- ) f83 question_branch, +condbranch(?branch,f --,f83 question_branch, if (f==0) { - IF_TOS(TOS = sp[0]); ,: 0= dup \ !f !f r> dup @ \ !f !f IP branchoffset @@ -182,18 +206,16 @@ if (f==0) { \+xconds -?dup-?branch ( f -- f ) new question_dupe_question_branch +?dup-?branch ( #ndisp f -- f ) new question_dupe_question_branch ""The run-time procedure compiled by @code{?DUP-IF}."" if (f==0) { sp++; - IF_TOS(TOS = sp[0]); - SET_IP((Xt *)(((Cell)IP)+(Cell)NEXT_INST)); - NEXT; + IF_spTOS(spTOS = sp[0]); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } -else - INC_IP(1); -?dup-0=-?branch ( 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 approach taken here of declaring the word as having the stack effect ( f -- ) and correcting for it in the branch-taken case costs a @@ -201,46 +223,37 @@ few cycles in that case, but is easy to invocation */ if (f!=0) { sp--; - SET_IP((Xt *)(((Cell)IP)+(Cell)NEXT_INST)); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); NEXT; } -else - INC_IP(1); \+ \f[THEN] \fhas? skiploopprims 0= [IF] -condbranch((next),( -- ) cmFORTH paren_next, -if ((*rp)--) { +condbranch((next),R:n1 -- R:n2,cmFORTH paren_next, +n2=n1-1; +if (n1) { ,: r> r> dup 1- >r IF dup @ + >r ELSE cell+ >r THEN ;) -condbranch((loop),( -- ) gforth paren_loop, -Cell index = *rp+1; -Cell limit = rp[1]; -if (index != limit) { - *rp = index; +condbranch((loop),R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_loop, +n2=n1+1; +if (n2 != nlimit) { ,: r> r> 1+ r> 2dup = IF >r 1- >r cell+ >r ELSE >r >r dup @ + >r THEN ;) -condbranch((+loop),( n -- ) gforth paren_plus_loop, +condbranch((+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_plus_loop, /* !! check this thoroughly */ -Cell index = *rp; /* sign bit manipulation and test: (x^y)<0 is equivalent to (x<0) != (y<0) */ /* dependent upon two's complement arithmetic */ -Cell olddiff = index-rp[1]; +Cell olddiff = n1-nlimit; +n2=n1+n; if ((olddiff^(olddiff+n))>=0 /* the limit is not crossed */ || (olddiff^n)>=0 /* it is a wrap-around effect */) { -#ifdef i386 - *rp += n; -#else - *rp = index + n; -#endif - IF_TOS(TOS = sp[0]); ,: r> swap r> r> 2dup - >r @@ -251,70 +264,48 @@ if ((olddiff^(olddiff+n))>=0 /* the li \+xconds -condbranch((-loop),( u -- ) gforth paren_minus_loop, -/* !! check this thoroughly */ -Cell index = *rp; -UCell olddiff = index-rp[1]; +condbranch((-loop),u R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_minus_loop, +UCell olddiff = n1-nlimit; +n2=n1-u; if (olddiff>u) { -#ifdef i386 - *rp -= u; -#else - *rp = index - u; -#endif - IF_TOS(TOS = sp[0]); ,) -condbranch((s+loop),( n -- ) gforth paren_symmetric_plus_loop, +condbranch((s+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_symmetric_plus_loop, ""The run-time procedure compiled by S+LOOP. It loops until the index crosses the boundary between limit and limit-sign(n). I.e. a symmetric version of (+LOOP)."" /* !! check this thoroughly */ -Cell index = *rp; -Cell diff = index-rp[1]; +Cell diff = n1-nlimit; Cell newdiff = diff+n; if (n<0) { diff = -diff; newdiff = -newdiff; } +n2=n1+n; if (diff>=0 || newdiff<0) { -#ifdef i386 - *rp += n; -#else - *rp = index + n; -#endif - IF_TOS(TOS = sp[0]); ,) \+ -unloop ( -- ) core -rp += 2; +unloop ( R:w1 R:w2 -- ) core +/* !! alias for 2rdrop */ : r> rdrop rdrop >r ; -(for) ( ncount -- ) cmFORTH paren_for +(for) ( ncount -- R:nlimit R:ncount ) cmFORTH paren_for /* or (for) = >r -- collides with unloop! */ -*--rp = 0; -*--rp = ncount; +nlimit=0; : r> swap 0 >r >r >r ; -(do) ( nlimit nstart -- ) gforth paren_do -/* or do it in high-level? 0.09/0.23% */ -*--rp = nlimit; -*--rp = nstart; +(do) ( nlimit nstart -- R:nlimit R:nstart ) gforth paren_do : r> swap rot >r >r >r ; -(?do) ( nlimit nstart -- ) gforth paren_question_do -*--rp = nlimit; -*--rp = nstart; +(?do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_question_do if (nstart == nlimit) { - IF_TOS(TOS = sp[0]); - goto branch; - } -else { - INC_IP(1); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } : 2dup = @@ -326,15 +317,10 @@ else { \+xconds -(+do) ( nlimit nstart -- ) gforth paren_plus_do -*--rp = nlimit; -*--rp = nstart; +(+do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_plus_do if (nstart >= nlimit) { - IF_TOS(TOS = sp[0]); - goto branch; - } -else { - INC_IP(1); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } : swap 2dup @@ -346,15 +332,10 @@ else { cell+ THEN >r ; -(u+do) ( ulimit ustart -- ) gforth paren_u_plus_do -*--rp = ulimit; -*--rp = ustart; +(u+do) ( #ndisp ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_plus_do if (ustart >= ulimit) { - IF_TOS(TOS = sp[0]); - goto branch; - } -else { - INC_IP(1); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } : swap 2dup @@ -366,15 +347,10 @@ else { cell+ THEN >r ; -(-do) ( nlimit nstart -- ) gforth paren_minus_do -*--rp = nlimit; -*--rp = nstart; +(-do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_minus_do if (nstart <= nlimit) { - IF_TOS(TOS = sp[0]); - goto branch; - } -else { - INC_IP(1); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } : swap 2dup @@ -386,15 +362,10 @@ else { cell+ THEN >r ; -(u-do) ( ulimit ustart -- ) gforth paren_u_minus_do -*--rp = ulimit; -*--rp = ustart; +(u-do) ( #ndisp ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_minus_do if (ustart <= ulimit) { - IF_TOS(TOS = sp[0]); - goto branch; - } -else { - INC_IP(1); + SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); + TAIL; } : swap 2dup @@ -411,29 +382,24 @@ else { \ don't make any assumptions where the return stack is!! \ implement this in machine code if it should run quickly! -i ( -- n ) core -n = *rp; +i ( R:n -- R:n n ) core : \ rp@ cell+ @ ; r> r> tuck >r >r ; -i' ( -- w ) gforth i_tick -""loop end value"" -w = rp[1]; +i' ( R:w R:w2 -- R:w R:w2 w ) gforth i_tick : \ rp@ cell+ cell+ @ ; r> r> r> dup itmp ! >r >r >r itmp @ ; variable itmp -j ( -- n ) core -n = rp[2]; +j ( R:n R:d1 -- n R:n R:d1 ) core : \ rp@ cell+ cell+ cell+ @ ; r> r> r> r> dup itmp ! >r >r >r >r itmp @ ; [IFUNDEF] itmp variable itmp [THEN] -k ( -- n ) gforth -n = rp[4]; +k ( R:n R:d1 R:d2 -- n R:n R:d1 R:d2 ) gforth : \ rp@ [ 5 cells ] Literal + @ ; r> r> r> r> r> r> dup itmp ! >r >r >r >r >r >r itmp @ ; @@ -444,8 +410,9 @@ n = rp[4]; \ digit is high-level: 0/0% move ( c_from c_to ucount -- ) core -""Copy the contents of @i{ucount} address units 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."" +/* !! note that the standard specifies addr, not c-addr */ memmove(c_to,c_from,ucount); /* make an Ifdef for bsd and others? */ : @@ -474,8 +441,7 @@ while (u-- > 0) DO 1- dup c@ I c! -1 +LOOP drop ; fill ( c_addr u c -- ) core -"" If @i{u}>0, store character @i{c} in each of @i{u} consecutive -@code{char} addresses in memory, starting at address @i{c-addr}."" +""Store @i{c} in @i{u} chars starting at @i{c-addr}."" memset(c_addr,c,u); : -rot bounds @@ -510,7 +476,7 @@ else if (n>0) : swap bounds ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 - ELSE c@ I c@ - unloop THEN -text-flag ; + ELSE c@ I c@ - unloop THEN sgn ; : sgn ( n -- -1/0/1 ) dup 0= IF EXIT THEN 0< 2* 1+ ; @@ -532,7 +498,7 @@ else if (n>0) ?DO dup c@ I c@ <> IF dup c@ toupper I c@ toupper = ELSE true THEN WHILE 1+ LOOP drop 0 - ELSE c@ toupper I c@ toupper - unloop THEN -text-flag ; + ELSE c@ toupper I c@ toupper - unloop THEN sgn ; -trailing ( c_addr u1 -- c_addr u2 ) string dash_trailing ""Adjust the string specified by @i{c-addr, u1} to remove all trailing @@ -599,11 +565,11 @@ else : 2dup > IF swap THEN drop ; -abs ( n1 -- n2 ) core -if (n1<0) - n2 = -n1; +abs ( n -- u ) core +if (n<0) + u = -n; else - n2 = n1; + u = n; : dup 0< IF negate THEN ; @@ -629,12 +595,14 @@ n3 = n1%n2; /* !! is this correct? look >r s>d r> fm/mod ; 2* ( n1 -- n2 ) core two_star +""Shift left by 1; also works on unsigned numbers"" n2 = 2*n1; : dup + ; 2/ ( n1 -- n2 ) core two_slash -/* !! is this still correct? */ +""Arithmetic shift right by 1. For signed numbers this is a floored +division by 2 (note that @code{/} not necessarily floors)."" n2 = n1>>1; : dup MINI and IF 1 ELSE 0 THEN @@ -776,6 +744,7 @@ d2 = -d1; invert swap negate tuck 0= - ; d2* ( d1 -- d2 ) double d_two_star +""Shift left by 1; also works on unsigned numbers"" #ifdef BUGGY_LONG_LONG d2.lo = d1.lo<<1; d2.hi = (d1.hi<<1) | (d1.lo>>(CELL_BITS-1)); @@ -786,6 +755,8 @@ d2 = 2*d1; 2dup d+ ; d2/ ( d1 -- d2 ) double d_two_slash +""Arithmetic shift right by 1. For signed numbers this is a floored +division by 2."" #ifdef BUGGY_LONG_LONG d2.hi = d1.hi>>1; d2.lo= (d1.lo>>1) | (d1.hi<<(CELL_BITS-1)); @@ -813,6 +784,7 @@ w2 = ~w1; MAXU xor ; rshift ( u1 n -- u2 ) core r_shift +""Logical shift right by @i{n} bits."" u2 = u1>>n; : 0 ?DO 2/ MAXI and LOOP ; @@ -938,7 +910,7 @@ about this word is to consider the numbe around from @code{max-u} to 0 for unsigned, and from @code{max-n} to min-n for signed numbers); now consider the range from u2 towards increasing numbers up to and excluding u3 (giving an empty range if -u2=u3; if u1 is in this range, @code{within} returns true."" +u2=u3); if u1 is in this range, @code{within} returns true."" f = FLAG(u1-u2 < u3-u2); : over - >r - r> u< ; @@ -948,7 +920,7 @@ a_addr = sp+1; sp! ( a_addr -- ) gforth sp_store sp = a_addr; -/* works with and without TOS caching */ +/* works with and without spTOS caching */ rp@ ( -- a_addr ) gforth rp_fetch a_addr = rp; @@ -966,47 +938,37 @@ fp = f_addr; \+ -;s ( -- ) gforth semis +;s ( R:w -- ) gforth semis ""The primitive compiled by @code{EXIT}."" -SET_IP((Xt *)(*rp++)); +SET_IP((Xt *)w); ->r ( w -- ) core to_r -*--rp = w; +>r ( w -- R:w ) core to_r : (>r) ; : (>r) rp@ cell+ @ rp@ ! rp@ cell+ ! ; -r> ( -- w ) core r_from -w = *rp++; +r> ( R:w -- w ) core r_from : rp@ cell+ @ rp@ @ rp@ cell+ ! (rdrop) rp@ ! ; Create (rdrop) ' ;s A, -rdrop ( -- ) gforth -rp++; +rdrop ( R:w -- ) gforth : r> r> drop >r ; -2>r ( w1 w2 -- ) core-ext two_to_r -*--rp = w1; -*--rp = w2; +2>r ( w1 w2 -- R:w1 R:w2 ) core-ext two_to_r : swap r> swap >r swap >r >r ; -2r> ( -- w1 w2 ) core-ext two_r_from -w2 = *rp++; -w1 = *rp++; +2r> ( R:w1 R:w2 -- w1 w2 ) core-ext two_r_from : r> r> swap r> swap >r swap ; -2r@ ( -- w1 w2 ) core-ext two_r_fetch -w2 = rp[0]; -w1 = rp[1]; +2r@ ( R:w1 R:w2 -- R:w1 R:w2 w1 w2 ) core-ext two_r_fetch : i' j ; -2rdrop ( -- ) gforth two_r_drop -rp+=2; +2rdrop ( R:w1 R:w2 -- ) gforth two_r_drop : r> r> drop r> drop >r ; @@ -1049,8 +1011,10 @@ tuck ( w1 w2 -- w2 w1 w2 ) core-ext swap over ; ?dup ( w -- w ) core question_dupe +""Actually the stack effect is: @code{( w -- 0 | w w )}. It performs a +@code{dup} if w is nonzero."" if (w!=0) { - IF_TOS(*sp-- = w;) + IF_spTOS(*sp-- = w;) #ifndef USE_TOS *--sp = w; #endif @@ -1059,6 +1023,7 @@ if (w!=0) { dup IF dup THEN ; pick ( u -- w ) core-ext +""Actually the stack effect is @code{ x0 ... xu u -- x0 ... xu x0 }."" w = sp[u+1]; : 1+ cells sp@ + @ ; @@ -1094,21 +1059,21 @@ w = sp[u+1]; \ toggle is high-level: 0.11/0.42% @ ( a_addr -- w ) core fetch -"" Read from the cell at address @i{a-addr}, and return its contents, @i{w}."" +""@i{w} is the cell stored at @i{a_addr}."" w = *a_addr; ! ( w a_addr -- ) core store -"" Write the value @i{w} to the cell at address @i{a-addr}."" +""Store @i{w} into the cell at @i{a-addr}."" *a_addr = w; +! ( n a_addr -- ) core plus_store -"" Add @i{n} to the value stored in the cell at address @i{a-addr}."" +""Add @i{n} to the cell at @i{a-addr}."" *a_addr += n; : tuck @ + swap ! ; c@ ( c_addr -- c ) core c_fetch -"" Read from the char at address @i{c-addr}, and return its contents, @i{c}."" +""@i{c} is the char stored at @i{c_addr}."" c = *c_addr; : [ bigendian [IF] ] @@ -1134,7 +1099,7 @@ c = *c_addr; : 8>> 2/ 2/ 2/ 2/ 2/ 2/ 2/ 2/ ; c! ( c c_addr -- ) core c_store -"" Write the value @i{c} to the char at address @i{c-addr}."" +""Store @i{c} into the char at @i{c-addr}."" *c_addr = c; : [ bigendian [IF] ] @@ -1164,28 +1129,28 @@ c! ( c c_addr -- ) core c_store : 8<< 2* 2* 2* 2* 2* 2* 2* 2* ; 2! ( w1 w2 a_addr -- ) core two_store -"" Write the value @i{w1, w2} to the double at address @i{a-addr}."" +""Store @i{w2} into the cell at @i{c-addr} and @i{w1} into the next cell."" a_addr[0] = w2; a_addr[1] = w1; : tuck ! cell+ ! ; 2@ ( a_addr -- w1 w2 ) core two_fetch -"" Read from the double at address @i{a-addr}, and return its contents, @i{w1, w2}."" +""@i{w2} is the content of the cell stored at @i{a-addr}, @i{w1} is +the content of the next cell."" w2 = a_addr[0]; w1 = a_addr[1]; : dup cell+ @ swap @ ; cell+ ( a_addr1 -- a_addr2 ) core cell_plus -"" Increment @i{a-addr1} by the number of address units corresponding to the size of -one cell, to give @i{a-addr2}."" +""@code{1 cells +}"" a_addr2 = a_addr1+1; : cell + ; cells ( n1 -- n2 ) core -"" @i{n2} is the number of address units corresponding to @i{n1} cells."" +"" @i{n2} is the number of address units of @i{n1} cells."" n2 = n1 * sizeof(Cell); : [ cell @@ -1196,8 +1161,7 @@ n2 = n1 * sizeof(Cell); drop ] ; char+ ( c_addr1 -- c_addr2 ) core char_plus -"" Increment @i{c-addr1} by the number of address units corresponding to the size of -one char, to give @i{c-addr2}."" +""@code{1 chars +}."" c_addr2 = c_addr1 + 1; : 1+ ; @@ -1208,8 +1172,8 @@ n2 = n1 * sizeof(Char); ; count ( c_addr1 -- c_addr2 u ) core -"" If @i{c-add1} is the address of a counted string return the length of -the string, @i{u}, and the address of its first character, @i{c-addr2}."" +""@i{c-addr2} is the first character and @i{u} the length of the +counted string at @i{c-addr1}."" u = *c_addr1; c_addr2 = c_addr1+1; : @@ -1228,7 +1192,7 @@ f83name2=f83name1; r> @ REPEAT THEN nip nip ; : (find-samelen) ( u f83name1 -- u f83name2/0 ) - BEGIN 2dup cell+ c@ $1F and <> WHILE @ dup 0= UNTIL THEN ; + BEGIN 2dup cell+ c@ $1F and <> WHILE @ dup 0= UNTIL THEN ; \+hash @@ -1363,7 +1327,7 @@ c_addr = (Address)CODE_ADDRESS(xt); @ ; >does-code ( xt -- a_addr ) gforth to_does_code -""If @i{xt} is the execution token of a defining-word-defined word, +""If @i{xt} is the execution token of a child of a @code{DOES>} word, @i{a-addr} is the start of the Forth code after the @code{DOES>}; Otherwise @i{a-addr} is 0."" a_addr = (Cell *)DOES_CODE(xt); @@ -1378,16 +1342,16 @@ CACHE_FLUSH(xt,(size_t)PFA(0)); ! ; does-code! ( a_addr xt -- ) gforth does_code_store -""Create a code field at @i{xt} for a defining-word-defined word; @i{a-addr} -is the start of the Forth code after @code{DOES>}."" +""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>}."" MAKE_DOES_CF(xt, a_addr); CACHE_FLUSH(xt,(size_t)PFA(0)); : dodoes: over ! cell+ ! ; does-handler! ( a_addr -- ) gforth does_handler_store -""Create a @code{DOES>}-handler at address @i{a-addr}. Usually, @i{a-addr} points -just behind a @code{DOES>}."" +""Create a @code{DOES>}-handler at address @i{a-addr}. Normally, +@i{a-addr} points just behind a @code{DOES>}."" MAKE_DOES_HANDLER(a_addr); CACHE_FLUSH((caddr_t)a_addr,DOES_HANDLER_SIZE); : @@ -1465,6 +1429,7 @@ cache."" FLUSH_ICACHE(c_addr,u); (bye) ( n -- ) gforth paren_bye +SUPER_END; return (Label *)n; (system) ( c_addr u -- wretval wior ) gforth peren_system @@ -1488,8 +1453,8 @@ in length."" c_addr2 = getenv(cstr(c_addr1,u1,1)); u2 = (c_addr2 == NULL ? 0 : strlen(c_addr2)); -open-pipe ( c_addr u ntype -- wfileid wior ) gforth open_pipe -wfileid=(Cell)popen(cstr(c_addr,u,1),fileattr[ntype]); /* ~ expansion of 1st arg? */ +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? */ wior = IOR(wfileid==0); /* !! the man page says that errno is not set reliably */ close-pipe ( wfileid -- wretval wior ) gforth close_pipe @@ -1503,6 +1468,8 @@ struct timeval time1; struct timezone zone1; struct tm *ltime; gettimeofday(&time1,&zone1); +/* !! Single Unix specification: + If tzp is not a null pointer, the behaviour is unspecified. */ ltime=localtime((time_t *)&time1.tv_sec); nyear =ltime->tm_year+1900; nmonth=ltime->tm_mon+1; @@ -1523,16 +1490,15 @@ allocate ( u -- a_addr wior ) memory contents of the data space is undefined. If the allocation is successful, @i{a-addr} is the start address of the allocated region and @i{wior} is 0. If the allocation fails, @i{a-addr} is undefined and @i{wior} -is an implementation-defined I/O result code."" +is a non-zero I/O result code."" a_addr = (Cell *)malloc(u?u:1); wior = IOR(a_addr==NULL); free ( a_addr -- wior ) memory ""Return the region of data space starting at @i{a-addr} to the system. -The regon must originally have been obtained using @code{allocate} or +The region must originally have been obtained using @code{allocate} or @code{resize}. If the operational is successful, @i{wior} is 0. -If the operation fails, @i{wior} is an implementation-defined -I/O result code."" +If the operation fails, @i{wior} is a non-zero I/O result code."" free(a_addr); wior = 0; @@ -1540,8 +1506,8 @@ resize ( a_addr1 u -- a_addr2 wior ) mem ""Change the size of the allocated area at @i{a-addr1} to @i{u} address units, possibly moving the contents to a different area. @i{a-addr2} is the address of the resulting area. -If the operational is successful, @i{wior} is 0. -If the operation fails, @i{wior} is an implementation-defined +If the operation is successful, @i{wior} is 0. +If the operation fails, @i{wior} is a non-zero I/O result code. If @i{a-addr1} is 0, Gforth's (but not the Standard) @code{resize} @code{allocate}s @i{u} address units."" /* the following check is not necessary on most OSs, but it is needed @@ -1567,14 +1533,14 @@ access the stack itself. The stack point variables @code{SP} and @code{FP}."" /* This is a first attempt at support for calls to C. This may change in the future */ -IF_FTOS(fp[0]=FTOS); +IF_fpTOS(fp[0]=fpTOS); FP=fp; SP=sp; ((void (*)())w)(); sp=SP; fp=FP; -IF_TOS(TOS=sp[0]); -IF_FTOS(FTOS=fp[0]); +IF_spTOS(spTOS=sp[0]); +IF_fpTOS(fpTOS=fp[0]); \+ \+file @@ -1582,23 +1548,15 @@ IF_FTOS(FTOS=fp[0]); close-file ( wfileid -- wior ) file close_file wior = IOR(fclose((FILE *)wfileid)==EOF); -open-file ( c_addr u ntype -- wfileid wior ) file open_file -wfileid = (Cell)fopen(tilde_cstr(c_addr, u, 1), fileattr[ntype]); -#if defined(GO32) && defined(MSDOS) -if(wfileid && !(ntype & 1)) - setbuf((FILE*)wfileid, NULL); -#endif +open-file ( c_addr u wfam -- wfileid wior ) file open_file +wfileid = (Cell)fopen(tilde_cstr(c_addr, u, 1), fileattr[wfam]); wior = IOR(wfileid == 0); -create-file ( c_addr u ntype -- wfileid wior ) file create_file +create-file ( c_addr u wfam -- wfileid wior ) file create_file Cell fd; -fd = open(tilde_cstr(c_addr, u, 1), O_CREAT|O_TRUNC|ufileattr[ntype], 0666); +fd = open(tilde_cstr(c_addr, u, 1), O_CREAT|O_TRUNC|ufileattr[wfam], 0666); if (fd != -1) { - wfileid = (Cell)fdopen(fd, fileattr[ntype]); -#if defined(GO32) && defined(MSDOS) - if(wfileid && !(ntype & 1)) - setbuf((FILE*)wfileid, NULL); -#endif + wfileid = (Cell)fdopen(fd, fileattr[wfam]); wior = IOR(wfileid == 0); } else { wfileid = 0; @@ -1638,7 +1596,7 @@ if (wior) clearerr((FILE *)wfileid); read-line ( c_addr u1 wfileid -- u2 flag wior ) file read_line -#if 1 +""this is only for backward compatibility"" Cell c; flag=-1; for(u2=0; u20) && (c_addr[u2-1]==NEWLINE)); -} -else { - wior=0; - u2=0; -} -#endif \+ @@ -1701,26 +1645,26 @@ PUTC(c); flush-file ( wfileid -- wior ) file-ext flush_file wior = IOR(fflush((FILE *) wfileid)==EOF); -file-status ( c_addr u -- ntype wior ) file-ext file_status +file-status ( c_addr u -- wfam wior ) file-ext file_status char *filename=tilde_cstr(c_addr, u, 1); if (access (filename, F_OK) != 0) { - ntype=0; + wfam=0; wior=IOR(1); } else if (access (filename, R_OK | W_OK) == 0) { - ntype=2; /* r/w */ + wfam=2; /* r/w */ wior=0; } else if (access (filename, R_OK) == 0) { - ntype=0; /* r/o */ + wfam=0; /* r/o */ wior=0; } else if (access (filename, W_OK) == 0) { - ntype=4; /* w/o */ + wfam=4; /* w/o */ wior=0; } else { - ntype=1; /* well, we cannot access the file, but better deliver a legal + wfam=1; /* well, we cannot access the file, but better deliver a legal access mode (r/o bin), so we get a decent error later upon open. */ wior=0; } @@ -1748,15 +1692,15 @@ d = r; #endif f! ( r f_addr -- ) float f_store -"" Store the floating-point value @i{r} to address @i{f-addr}."" +""Store @i{r} into the float at address @i{f-addr}."" *f_addr = r; f@ ( f_addr -- r ) float f_fetch -"" Fetch floating-point value @i{r} from address @i{f-addr}."" +""@i{r} is the float at address @i{f-addr}."" r = *f_addr; df@ ( df_addr -- r ) float-ext d_f_fetch -"" Fetch the double-precision IEEE floating-point value @i{r} from the address @i{df-addr}."" +""Fetch the double-precision IEEE floating-point value @i{r} from the address @i{df-addr}."" #ifdef IEEE_FP r = *df_addr; #else @@ -1764,7 +1708,8 @@ r = *df_addr; #endif df! ( r df_addr -- ) float-ext d_f_store -"" Store the double-precision IEEE floating-point value @i{r} to the address @i{df-addr}."" +""Store @i{r} as double-precision IEEE floating-point value to the +address @i{df-addr}."" #ifdef IEEE_FP *df_addr = r; #else @@ -1772,7 +1717,7 @@ df! ( r df_addr -- ) float-ext d_f_store #endif sf@ ( sf_addr -- r ) float-ext s_f_fetch -"" Fetch the single-precision IEEE floating-point value @i{r} from the address @i{sf-addr}."" +""Fetch the single-precision IEEE floating-point value @i{r} from the address @i{sf-addr}."" #ifdef IEEE_FP r = *sf_addr; #else @@ -1780,7 +1725,8 @@ r = *sf_addr; #endif sf! ( r sf_addr -- ) float-ext s_f_store -"" Store the single-precision IEEE floating-point value @i{r} to the address @i{sf-addr}."" +""Store @i{r} as single-precision IEEE floating-point value to the +address @i{sf-addr}."" #ifdef IEEE_FP *sf_addr = r; #else @@ -1821,12 +1767,11 @@ fnip ( r1 r2 -- r2 ) gforth f_nip ftuck ( r1 r2 -- r2 r1 r2 ) gforth f_tuck float+ ( f_addr1 -- f_addr2 ) float float_plus -"" Increment @i{f-addr1} by the number of address units corresponding to the size of -one floating-point number, to give @i{f-addr2}."" +""@code{1 floats +}."" f_addr2 = f_addr1+1; floats ( n1 -- n2 ) float -""@i{n2} is the number of address units corresponding to @i{n1} floating-point numbers."" +""@i{n2} is the number of address units of @i{n1} floats."" n2 = n1*sizeof(Float); floor ( r1 -- r2 ) float @@ -1867,12 +1812,12 @@ f2=FLAG(isdigit((unsigned)(sig[0]))!=0); memmove(c_addr,sig,u); >float ( c_addr u -- flag ) float to_float -""Attempt to convert the character string @i{c-addr u} to -internal floating-point representation. If the string -represents a valid floating-point number @i{r} is placed -on the floating-point stack and @i{flag} is true. Otherwise, -@i{flag} is false. A string of blanks is a special case -and represents the floating-point number 0."" +""Actual stack effect: ( c_addr u -- r t | f ). Attempt to convert the +character string @i{c-addr u} to internal floating-point +representation. If the string represents a valid floating-point number +@i{r} is placed on the floating-point stack and @i{flag} is +true. Otherwise, @i{flag} is false. A string of blanks is a special +case and represents the floating-point number 0."" /* real signature: c_addr u -- r t / f */ Float r; char *number=cstr(c_addr, u, 1); @@ -1896,9 +1841,9 @@ number[u]='\0'; r=strtod(number,&endconv); if((flag=FLAG(!(Cell)*endconv))) { - IF_FTOS(fp[0] = FTOS); + IF_fpTOS(fp[0] = fpTOS); fp += -1; - FTOS = sign ? -r : r; + fpTOS = sign ? -r : r; } else if(*endconv=='d' || *endconv=='D') { @@ -1906,9 +1851,9 @@ else if(*endconv=='d' || *endconv=='D') r=strtod(number,&endconv); if((flag=FLAG(!(Cell)*endconv))) { - IF_FTOS(fp[0] = FTOS); + IF_fpTOS(fp[0] = fpTOS); fp += -1; - FTOS = sign ? -r : r; + fpTOS = sign ? -r : r; } } @@ -2021,24 +1966,24 @@ r2 = atanh(r1); r> IF fnegate THEN ; sfloats ( n1 -- n2 ) float-ext s_floats -""@i{n2} is the number of address units corresponding to @i{n1} +""@i{n2} is the number of address units of @i{n1} single-precision IEEE floating-point numbers."" n2 = n1*sizeof(SFloat); dfloats ( n1 -- n2 ) float-ext d_floats -""@i{n2} is the number of address units corresponding to @i{n1} +""@i{n2} is the number of address units of @i{n1} double-precision IEEE floating-point numbers."" n2 = n1*sizeof(DFloat); sfaligned ( c_addr -- sf_addr ) float-ext s_f_aligned -"" @i{sf-addr} is the first single-float-aligned address greater +""@i{sf-addr} is the first single-float-aligned address greater than or equal to @i{c-addr}."" sf_addr = (SFloat *)((((Cell)c_addr)+(sizeof(SFloat)-1))&(-sizeof(SFloat))); : [ 1 sfloats 1- ] Literal + [ -1 sfloats ] Literal and ; dfaligned ( c_addr -- df_addr ) float-ext d_f_aligned -"" @i{df-addr} is the first double-float-aligned address greater +""@i{df-addr} is the first double-float-aligned address greater than or equal to @i{c-addr}."" df_addr = (DFloat *)((((Cell)c_addr)+(sizeof(DFloat)-1))&(-sizeof(DFloat))); : @@ -2053,9 +1998,8 @@ df_addr = (DFloat *)((((Cell)c_addr)+(si \+ \+glocals -@local# ( -- w ) gforth fetch_local_number -w = *(Cell *)(lp+(Cell)NEXT_INST); -INC_IP(1); +@local# ( #noffset -- w ) gforth fetch_local_number +w = *(Cell *)(lp+noffset); @local0 ( -- w ) new fetch_local_zero w = *(Cell *)(lp+0*sizeof(Cell)); @@ -2071,9 +2015,8 @@ w = *(Cell *)(lp+3*sizeof(Cell)); \+floating -f@local# ( -- r ) gforth f_fetch_local_number -r = *(Float *)(lp+(Cell)NEXT_INST); -INC_IP(1); +f@local# ( #noffset -- r ) gforth f_fetch_local_number +r = *(Float *)(lp+noffset); f@local0 ( -- r ) new f_fetch_local_zero r = *(Float *)(lp+0*sizeof(Float)); @@ -2083,17 +2026,15 @@ r = *(Float *)(lp+1*sizeof(Float)); \+ -laddr# ( -- c_addr ) gforth laddr_number +laddr# ( #noffset -- c_addr ) gforth laddr_number /* this can also be used to implement lp@ */ -c_addr = (Char *)(lp+(Cell)NEXT_INST); -INC_IP(1); +c_addr = (Char *)(lp+noffset); -lp+!# ( -- ) gforth lp_plus_store_number +lp+!# ( #noffset -- ) gforth lp_plus_store_number ""used with negative immediate values it allocates memory on the local stack, a positive immediate argument drops memory from the local stack"" -lp += (Cell)NEXT_INST; -INC_IP(1); +lp += noffset; lp- ( -- ) new minus_four_lp_plus_store lp += -sizeof(Cell); @@ -2118,6 +2059,7 @@ lp -= sizeof(Float); *(Float *)lp = r; fpick ( u -- r ) gforth +""Actually the stack effect is @code{ r0 ... ru u -- r0 ... ru r0 }."" r = fp[u+1]; /* +1, because update of fp happens before this fragment */ : floats fp@ + f@ ; @@ -2199,12 +2141,12 @@ UP=up=(char *)a_addr; Variable UP wcall ( u -- ) gforth -IF_FTOS(fp[0]=FTOS); +IF_fpTOS(fp[0]=fpTOS); FP=fp; sp=(SYSCALL(Cell(*)(Cell *, void *))u)(sp, &FP); fp=FP; -IF_TOS(TOS=sp[0];) -IF_FTOS(FTOS=fp[0]); +IF_spTOS(spTOS=sp[0];) +IF_fpTOS(fpTOS=fp[0]); \+file @@ -2222,8 +2164,10 @@ if(dent == NULL) { flag = 0; } else { u2 = strlen(dent->d_name); - if(u2 > u1) + if(u2 > u1) { u2 = u1; + wior = -512-ENAMETOOLONG; + } memmove(c_addr, dent->d_name, u2); } @@ -2240,7 +2184,8 @@ flag = FLAG(!fnmatch(pattern, string, 0) newline ( -- c_addr u ) gforth ""String containing the newline sequence of the host OS"" char newline[] = { -#ifdef unix +#if defined(unix) || defined(__MACH__) +/* Darwin/MacOS X sets __MACH__, but not unix. */ '\n' #else '\r','\n' @@ -2248,3 +2193,190 @@ char newline[] = { }; c_addr=newline; u=sizeof(newline); +: + "newline count ; +Create "newline e? crlf [IF] 2 c, $0D c, [ELSE] 1 c, [THEN] $0A c, + +\+os + +utime ( -- dtime ) gforth +""Report the current time in microseconds since some epoch."" +struct timeval time1; +gettimeofday(&time1,NULL); +dtime = timeval2us(&time1); + +cputime ( -- duser dsystem ) gforth +""duser and dsystem are the respective user- and system-level CPU +times used since the start of the Forth system (excluding child +processes), in microseconds (the granularity may be much larger, +however). On platforms without the getrusage call, it reports elapsed +time (since some epoch) for duser and 0 for dsystem."" +#ifdef HAVE_GETRUSAGE +struct rusage usage; +getrusage(RUSAGE_SELF, &usage); +duser = timeval2us(&usage.ru_utime); +dsystem = timeval2us(&usage.ru_stime); +#else +struct timeval time1; +gettimeofday(&time1,NULL); +duser = timeval2us(&time1); +#ifndef BUGGY_LONG_LONG +dsystem = (DCell)0; +#else +dsystem=(DCell){0,0}; +#endif +#endif + +\+ + +\+floating + +v* ( f_addr1 nstride1 f_addr2 nstride2 ucount -- r ) gforth v_star +""dot-product: r=v1*v2. The first element of v1 is at f_addr1, the +next at f_addr1+nstride1 and so on (similar for v2). Both vectors have +ucount elements."" +for (r=0.; ucount>0; ucount--) { + r += *f_addr1 * *f_addr2; + f_addr1 = (Float *)(((Address)f_addr1)+nstride1); + f_addr2 = (Float *)(((Address)f_addr2)+nstride2); +} +: + >r swap 2swap swap 0e r> 0 ?DO + dup f@ over + 2swap dup f@ f* f+ over + 2swap + LOOP 2drop 2drop ; + +faxpy ( ra f_x nstridex f_y nstridey ucount -- ) gforth +""vy=ra*vx+vy"" +for (; ucount>0; ucount--) { + *f_y += ra * *f_x; + f_x = (Float *)(((Address)f_x)+nstridex); + f_y = (Float *)(((Address)f_y)+nstridey); +} +: + >r swap 2swap swap r> 0 ?DO + fdup dup f@ f* over + 2swap dup f@ f+ dup f! over + 2swap + LOOP 2drop 2drop fdrop ; + +\+ + +\+file + +(read-line) ( c_addr u1 wfileid -- u2 flag u3 wior ) file paren_read_line +Cell c; +flag=-1; +u3=0; +for(u2=0; u2next)) + 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 + +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); + +lit_plus = lit + + +call ( #a_callee -- R:a_retaddr ) +""Call callee (a variant of docol with inline argument)."" +a_retaddr = (Cell *)IP; +SET_IP((Xt *)a_callee); + +useraddr ( #u -- a_addr ) +a_addr = (Cell *)(up+u); + +\+