--- gforth/prim 2002/12/28 17:18:27 1.110 +++ gforth/prim 2003/08/20 09:23:45 1.139 @@ -1,6 +1,6 @@ \ Gforth primitives -\ Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc. +\ Copyright (C) 1995,1996,1997,1998,2000,2003 Free Software Foundation, Inc. \ This file is part of Gforth. @@ -106,6 +106,10 @@ \E set-current \E store-optimization on \E ' noop tail-nextp2 ! \ now INST_TAIL just stores, but does not jump +\E +\E include-skipped-insts on \ static superinsts include cells for components +\E \ useful for dynamic programming and +\E \ superinsts across entry points \ \ @@ -137,15 +141,67 @@ undefine(`index') undefine(`shift') undefine(`symbols') +\ run-time routines for non-primitives. They are defined as +\ primitives, because that simplifies things. + +(docol) ( -- R:a_retaddr ) gforth-internal paren_docol +""run-time routine for colon definitions"" +a_retaddr = (Cell *)ip; +SET_IP((Xt *)PFA(CFA)); + +(docon) ( -- w ) gforth-internal paren_docon +""run-time routine for constants"" +w = *(Cell *)PFA(CFA); + +(dovar) ( -- a_body ) gforth-internal paren_dovar +""run-time routine for variables and CREATEd words"" +a_body = PFA(CFA); + +(douser) ( -- a_user ) gforth-internal paren_douser +""run-time routine for constants"" +a_user = (Cell *)(up+*(Cell *)PFA(CFA)); + +(dodefer) ( -- ) gforth-internal paren_dodefer +""run-time routine for deferred words"" +SUPER_END; +EXEC(*(Xt *)PFA(CFA)); + +(dofield) ( n1 -- n2 ) gforth-internal paren_field +""run-time routine for fields"" +n2 = n1 + *(Cell *)PFA(CFA); + +(dodoes) ( -- a_body R:a_retaddr ) gforth-internal paren_dodoes +""run-time routine for @code{does>}-defined words"" +a_retaddr = (Cell *)ip; +a_body = PFA(CFA); +SET_IP(DOES_CODE1(CFA)); + +(does-handler) ( -- ) gforth-internal paren_does_handler +""just a slot to have an encoding for the DOESJUMP, +which is no longer used anyway (!! eliminate this)"" + \g control noop ( -- ) gforth : ; -lit ( #w -- w ) gforth -: - r> dup @ swap cell+ >r ; +call ( #a_callee -- R:a_retaddr ) new +""Call callee (a variant of docol with inline argument)."" +#ifdef NO_IP +INST_TAIL; +JUMP(a_callee); +#else +#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); +#endif execute ( xt -- ) core ""Perform the semantics represented by the execution token, @i{xt}."" @@ -168,37 +224,99 @@ EXEC(*(Xt *)a_addr); : @ execute ; -\fhas? skipbranchprims 0= [IF] +;s ( R:w -- ) gforth semis +""The primitive compiled by @code{EXIT}."" +#ifdef NO_IP +INST_TAIL; +goto *(void *)w; +#else +SET_IP((Xt *)w); +#endif + +unloop ( R:w1 R:w2 -- ) core +/* !! alias for 2rdrop */ +: + r> rdrop rdrop >r ; + +lit-perform ( #a_addr -- ) new lit_perform +#ifndef NO_IP +ip=IP; +#endif +SUPER_END; +EXEC(*(Xt *)a_addr); + +does-exec ( #a_cfa -- R:nest a_pfa ) new does_exec +#ifdef NO_IP +/* compiled to LIT CALL by compile_prim */ +assert(0); +#else +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)); +#endif + \+glocals -branch-lp+!# ( #ndisp #nlocals -- ) gforth branch_lp_plus_store_number +branch-lp+!# ( #a_target #nlocals -- ) gforth branch_lp_plus_store_number /* this will probably not be used */ lp += nlocals; -SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); +#ifdef NO_IP +INST_TAIL; +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +#endif \+ -branch ( #ndisp -- ) gforth -SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +branch ( #a_target -- ) gforth +#ifdef NO_IP +INST_TAIL; +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +#endif : - r> dup @ + >r ; + r> @ >r ; -\ condbranch(forthname,stackeffect,restline,code,forthcode) +\ condbranch(forthname,stackeffect,restline,code1,code2,forthcode) \ this is non-syntactical: code must open a brace that is closed by the macro define(condbranch, -$1 ( `#'ndisp $2 ) $3 -$4 SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +$1 ( `#'a_target $2 ) $3 +$4 #ifdef NO_IP INST_TAIL; +#endif +$5 #ifdef NO_IP +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; -$5 +$6 \+glocals -$1-lp+!`#' ( `#'ndisp `#'nlocals $2 ) $3_lp_plus_store_number -$4 lp += nlocals; -SET_IP((Xt *)(((Cell)(IP-2))+ndisp)); +$1-lp+!`#' ( `#'a_target `#'nlocals $2 ) $3_lp_plus_store_number +$4 #ifdef NO_IP INST_TAIL; +#endif +$5 lp += nlocals; +#ifdef NO_IP +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; @@ -206,12 +324,11 @@ SUPER_CONTINUE; ) condbranch(?branch,f --,f83 question_branch, -if (f==0) { +,if (f==0) { ,: - 0= dup \ !f !f - r> dup @ \ !f !f IP branchoffset - rot and + \ !f IP|IP+branchoffset - swap 0= cell and + \ IP'' + 0= dup 0= \ !f f + r> tuck cell+ \ !f branchoffset f IP+ + and -rot @ and or \ f&IP+|!f&branch >r ;) \ we don't need an lp_plus_store version of the ?dup-stuff, because it @@ -219,17 +336,22 @@ if (f==0) { \+xconds -?dup-?branch ( #ndisp f -- f ) new question_dupe_question_branch +?dup-?branch ( #a_target f -- f ) new question_dupe_question_branch ""The run-time procedure compiled by @code{?DUP-IF}."" if (f==0) { sp++; IF_spTOS(spTOS = sp[0]); - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); - INST_TAIL; +#ifdef NO_IP +INST_TAIL; +JUMP(a_target); +#else +SET_IP((Xt *)a_target); + INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; -?dup-0=-?branch ( #ndisp f -- ) new question_dupe_zero_equals_question_branch +?dup-0=-?branch ( #a_target 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 @@ -237,29 +359,32 @@ few cycles in that case, but is easy to invocation */ if (f!=0) { sp--; - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +#ifdef NO_IP + JUMP(a_target); +#else + SET_IP((Xt *)a_target); NEXT; +#endif } SUPER_CONTINUE; \+ -\f[THEN] \fhas? skiploopprims 0= [IF] condbranch((next),R:n1 -- R:n2,cmFORTH paren_next, n2=n1-1; -if (n1) { +,if (n1) { ,: r> r> dup 1- >r - IF dup @ + >r ELSE cell+ >r THEN ;) + IF @ >r ELSE cell+ >r THEN ;) condbranch((loop),R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_loop, n2=n1+1; -if (n2 != nlimit) { +,if (n2 != nlimit) { ,: r> r> 1+ r> 2dup = IF >r 1- >r cell+ >r - ELSE >r >r dup @ + >r THEN ;) + ELSE >r >r @ >r THEN ;) condbranch((+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_plus_loop, /* !! check this thoroughly */ @@ -267,14 +392,14 @@ condbranch((+loop),n R:nlimit R:n1 -- R: /* dependent upon two's complement arithmetic */ Cell olddiff = n1-nlimit; n2=n1+n; -if ((olddiff^(olddiff+n))>=0 /* the limit is not crossed */ +,if ((olddiff^(olddiff+n))>=0 /* the limit is not crossed */ || (olddiff^n)>=0 /* it is a wrap-around effect */) { ,: r> swap r> r> 2dup - >r 2 pick r@ + r@ xor 0< 0= 3 pick r> xor 0< 0= or - IF >r + >r dup @ + >r + IF >r + >r @ >r ELSE >r >r drop cell+ >r THEN ;) \+xconds @@ -282,7 +407,7 @@ if ((olddiff^(olddiff+n))>=0 /* the li 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) { +,if (olddiff>u) { ,) condbranch((s+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth paren_symmetric_plus_loop, @@ -297,46 +422,55 @@ if (n<0) { newdiff = -newdiff; } n2=n1+n; -if (diff>=0 || newdiff<0) { +,if (diff>=0 || newdiff<0) { ,) \+ -unloop ( R:w1 R:w2 -- ) core -/* !! alias for 2rdrop */ -: - r> rdrop rdrop >r ; - -(for) ( ncount -- R:nlimit R:ncount ) cmFORTH paren_for +(for) ( ncount -- R:nlimit R:ncount ) cmFORTH paren_for /* or (for) = >r -- collides with unloop! */ nlimit=0; : r> swap 0 >r >r >r ; -(do) ( nlimit nstart -- R:nlimit R:nstart ) gforth paren_do +(do) ( nlimit nstart -- R:nlimit R:nstart ) gforth paren_do : r> swap rot >r >r >r ; -(?do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_question_do -if (nstart == nlimit) { - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +(?do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth paren_question_do +#ifdef NO_IP INST_TAIL; +#endif +if (nstart == nlimit) { +#ifdef NO_IP + JUMP(a_target); +#else + SET_IP((Xt *)a_target); + INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; : 2dup = IF r> swap rot >r >r - dup @ + >r + @ >r ELSE r> swap rot >r >r cell+ >r THEN ; \ --> CORE-EXT \+xconds -(+do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_plus_do -if (nstart >= nlimit) { - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +(+do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth paren_plus_do +#ifdef NO_IP INST_TAIL; +#endif +if (nstart >= nlimit) { +#ifdef NO_IP + JUMP(a_target); +#else + SET_IP((Xt *)a_target); + INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; : @@ -344,15 +478,22 @@ SUPER_CONTINUE; r> swap >r swap >r >= IF - dup @ + + @ ELSE cell+ THEN >r ; -(u+do) ( #ndisp ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_plus_do -if (ustart >= ulimit) { - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +(u+do) ( #a_target ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_plus_do +#ifdef NO_IP INST_TAIL; +#endif +if (ustart >= ulimit) { +#ifdef NO_IP +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; : @@ -360,15 +501,22 @@ SUPER_CONTINUE; r> swap >r swap >r u>= IF - dup @ + + @ ELSE cell+ THEN >r ; -(-do) ( #ndisp nlimit nstart -- R:nlimit R:nstart ) gforth paren_minus_do -if (nstart <= nlimit) { - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +(-do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth paren_minus_do +#ifdef NO_IP INST_TAIL; +#endif +if (nstart <= nlimit) { +#ifdef NO_IP +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; : @@ -376,15 +524,22 @@ SUPER_CONTINUE; r> swap >r swap >r <= IF - dup @ + + @ ELSE cell+ THEN >r ; -(u-do) ( #ndisp ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_minus_do -if (ustart <= ulimit) { - SET_IP((Xt *)(((Cell)(IP-1))+ndisp)); +(u-do) ( #a_target ulimit ustart -- R:ulimit R:ustart ) gforth paren_u_minus_do +#ifdef NO_IP INST_TAIL; +#endif +if (ustart <= ulimit) { +#ifdef NO_IP +JUMP(a_target); +#else +SET_IP((Xt *)a_target); +INST_TAIL; NEXT_P2; +#endif } SUPER_CONTINUE; : @@ -392,7 +547,7 @@ SUPER_CONTINUE; r> swap >r swap >r u<= IF - dup @ + + @ ELSE cell+ THEN >r ; @@ -445,8 +600,7 @@ cmove ( c_from c_to u -- ) string c_move @i{c-from} to @i{c-to}. The copy proceeds @code{char}-by-@code{char} from low address to high address; i.e., for overlapping areas it is safe if @i{c-to}=<@i{c-from}."" -while (u-- > 0) - *c_to++ = *c_from++; +cmove(c_from,c_to,u); : bounds ?DO dup c@ I c! 1+ LOOP drop ; @@ -455,8 +609,7 @@ cmove> ( c_from c_to u -- ) string c_mov @i{c-from} to @i{c-to}. The copy proceeds @code{char}-by-@code{char} from high address to low address; i.e., for overlapping areas it is safe if @i{c-to}>=@i{c-from}."" -while (u-- > 0) - c_to[u] = c_from[u]; +cmove_up(c_from,c_to,u); : dup 0= IF drop 2drop exit THEN rot over + -rot bounds swap 1- @@ -476,31 +629,26 @@ is 1. Currently this is based on the mac comparison. In the future, this may change to consider the current locale and its collation order."" /* close ' to keep fontify happy */ -n = memcmp(c_addr1, c_addr2, u10) - n = 1; +n = compare(c_addr1, u1, c_addr2, u2); : rot 2dup swap - >r min swap -text dup IF rdrop ELSE drop r> sgn THEN ; : sgn ( n -- -1/0/1 ) dup 0= IF EXIT THEN 0< 2* 1+ ; --text ( c_addr1 u c_addr2 -- n ) new dash_text -n = memcmp(c_addr1, c_addr2, u); -if (n<0) - n = -1; -else if (n>0) - n = 1; -: - swap bounds - ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 - ELSE c@ I c@ - unloop THEN sgn ; -: sgn ( n -- -1/0/1 ) - dup 0= IF EXIT THEN 0< 2* 1+ ; +\ -text is only used by replaced primitives now; move it elsewhere +\ -text ( c_addr1 u c_addr2 -- n ) new dash_text +\ n = memcmp(c_addr1, c_addr2, u); +\ if (n<0) +\ n = -1; +\ else if (n>0) +\ n = 1; +\ : +\ swap bounds +\ ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 +\ ELSE c@ I c@ - unloop THEN sgn ; +\ : sgn ( n -- -1/0/1 ) +\ dup 0= IF EXIT THEN 0< 2* 1+ ; toupper ( c1 -- c2 ) gforth ""If @i{c1} is a lower-case character (in the current locale), @i{c2} @@ -509,29 +657,6 @@ c2 = toupper(c1); : dup [char] a - [ char z char a - 1 + ] Literal u< bl and - ; -capscomp ( c_addr1 u c_addr2 -- n ) new -n = memcasecmp(c_addr1, c_addr2, u); /* !! use something that works in all locales */ -if (n<0) - n = -1; -else if (n>0) - n = 1; -: - swap bounds - ?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 sgn ; - --trailing ( c_addr u1 -- c_addr u2 ) string dash_trailing -""Adjust the string specified by @i{c-addr, u1} to remove all trailing -spaces. @i{u2} is the length of the modified string."" -u2 = u1; -while (u2>0 && c_addr[u2-1] == ' ') - u2--; -: - BEGIN 1- 2dup + c@ bl = WHILE - dup 0= UNTIL ELSE 1+ THEN ; - /string ( c_addr1 u1 n -- c_addr2 u2 ) string slash_string ""Adjust the string specified by @i{c-addr1, u1} to remove @i{n} characters from the start of the string."" @@ -542,9 +667,18 @@ u2 = u1-n; \g arith +lit ( #w -- w ) gforth +: + r> dup @ swap cell+ >r ; + + ( n1 n2 -- n ) core plus n = n1+n2; +\ lit+ / lit_plus = lit + + +lit+ ( n1 #n2 -- n ) new lit_plus +n=n1+n2; + \ PFE-0.9.14 has it differently, but the next release will have it as follows under+ ( n1 n2 n3 -- n n2 ) gforth under_plus ""add @i{n3} to @i{n1} (giving @i{n})"" @@ -698,11 +832,10 @@ ud = ummul(u1,u2); ud = (UDCell)u1 * (UDCell)u2; #endif : - >r >r 0 0 r> r> [ 8 cells ] literal 0 + 0 -rot dup [ 8 cells ] literal - DO - over >r dup >r 0< and d2*+ drop - r> 2* r> swap - LOOP 2drop ; + dup 0< I' and d2*+ drop + LOOP ; : d2*+ ( ud n -- ud+n c ) over MINI and >r >r 2dup d+ swap r> + swap r> ; @@ -941,6 +1074,17 @@ f = FLAG(u1-u2 < u3-u2); : over - >r - r> u< ; +\g stack + +useraddr ( #u -- a_addr ) new +a_addr = (Cell *)(up+u); + +up! ( a_addr -- ) gforth up_store +UP=up=(char *)a_addr; +: + up ! ; +Variable UP + sp@ ( -- a_addr ) gforth sp_fetch a_addr = sp+1; @@ -964,17 +1108,6 @@ fp = f_addr; \+ -;s ( R:w -- ) gforth semis -""The primitive compiled by @code{EXIT}."" -#ifdef NO_IP -INST_TAIL; -goto *(void *)w; -#else -SET_IP((Xt *)w); -#endif - -\g stack - >r ( w -- R:w ) core to_r : (>r) ; @@ -989,19 +1122,19 @@ rdrop ( R:w -- ) gforth : r> r> drop >r ; -2>r ( w1 w2 -- R:w1 R:w2 ) core-ext two_to_r +2>r ( d -- R:d ) core-ext two_to_r : swap r> swap >r swap >r >r ; -2r> ( R:w1 R:w2 -- w1 w2 ) core-ext two_r_from +2r> ( R:d -- d ) core-ext two_r_from : r> r> swap r> swap >r swap ; -2r@ ( R:w1 R:w2 -- R:w1 R:w2 w1 w2 ) core-ext two_r_fetch +2r@ ( R:d -- R:d d ) core-ext two_r_fetch : i' j ; -2rdrop ( R:w1 R:w2 -- ) gforth two_r_drop +2rdrop ( R:d -- ) gforth two_r_drop : r> r> drop r> drop >r ; @@ -1097,6 +1230,11 @@ w = sp[u+1]; ""@i{w} is the cell stored at @i{a_addr}."" w = *a_addr; +\ lit@ / lit_fetch = lit @ + +lit@ ( #a_addr -- w ) new lit_fetch +w = *a_addr; + ! ( w a_addr -- ) core store ""Store @i{w} into the cell at @i{a-addr}."" *a_addr = w; @@ -1216,6 +1354,8 @@ c_addr2 = c_addr1+1; \g compiler +\+f83headerstring + (f83find) ( c_addr u f83name1 -- f83name2 ) new paren_f83find for (; f83name1 != NULL; f83name1 = (struct F83Name *)(f83name1->next)) if ((UCell)F83NAME_COUNT(f83name1)==u && @@ -1229,77 +1369,61 @@ 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 ; +: capscomp ( c_addr1 u c_addr2 -- n ) + swap bounds + ?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 sgn ; +: sgn ( n -- -1/0/1 ) + dup 0= IF EXIT THEN 0< 2* 1+ ; + +\- + +(listlfind) ( c_addr u longname1 -- longname2 ) new paren_listlfind +longname2=listlfind(c_addr, u, 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 -(hashfind) ( c_addr u a_addr -- f83name2 ) new paren_hashfind -struct F83Name *f83name1; -f83name2=NULL; -while(a_addr != NULL) -{ - f83name1=(struct F83Name *)(a_addr[1]); - a_addr=(Cell *)(a_addr[0]); - if ((UCell)F83NAME_COUNT(f83name1)==u && - memcasecmp(c_addr, f83name1->name, u)== 0 /* or inline? */) - { - f83name2=f83name1; - break; - } -} +(hashlfind) ( c_addr u a_addr -- longname2 ) new paren_hashlfind +longname2 = hashlfind(c_addr, u, a_addr); : BEGIN dup WHILE - 2@ >r >r dup r@ cell+ c@ $1F and = - IF 2dup r@ cell+ char+ capscomp 0= + 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 ; -(tablefind) ( c_addr u a_addr -- f83name2 ) new paren_tablefind +(tablelfind) ( c_addr u a_addr -- longname2 ) new paren_tablelfind ""A case-sensitive variant of @code{(hashfind)}"" -struct F83Name *f83name1; -f83name2=NULL; -while(a_addr != NULL) -{ - f83name1=(struct F83Name *)(a_addr[1]); - a_addr=(Cell *)(a_addr[0]); - if ((UCell)F83NAME_COUNT(f83name1)==u && - memcmp(c_addr, f83name1->name, u)== 0 /* or inline? */) - { - f83name2=f83name1; - break; - } -} +longname2 = tablelfind(c_addr, u, a_addr); : BEGIN dup WHILE - 2@ >r >r dup r@ cell+ c@ $1F and = - IF 2dup r@ cell+ char+ -text 0= + 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 ; - -(hashkey) ( c_addr u1 -- u2 ) gforth paren_hashkey -u2=0; -while(u1--) - u2+=(Cell)toupper(*c_addr++); -: - 0 -rot bounds ?DO I c@ toupper + LOOP ; +: -text ( c_addr1 u c_addr2 -- n ) + swap bounds + ?DO dup c@ I c@ = WHILE 1+ LOOP drop 0 + ELSE c@ I c@ - unloop THEN sgn ; +: sgn ( n -- -1/0/1 ) + dup 0= IF EXIT THEN 0< 2* 1+ ; (hashkey1) ( c_addr u ubits -- ukey ) gforth paren_hashkey1 ""ukey is the hash key for the string c_addr u fitting in ubits bits"" -/* this hash function rotates the key at every step by rot bits within - ubits bits and xors it with the character. This function does ok in - the chi-sqare-test. Rot should be <=7 (preferably <=5) for - ASCII strings (larger if ubits is large), and should share no - divisors with ubits. -*/ -static char rot_values[] = {5,0,1,2,3,4,5,5,5,5,3,5,5,5,5,7,5,5,5,5,7,5,5,5,5,6,5,5,5,5,7,5,5}; -unsigned rot = rot_values[ubits]; -Char *cp = c_addr; -for (ukey=0; cp>(ubits-rot))) - ^ toupper(*cp)) - & ((1<r tuck - 2swap r> 0 2swap bounds @@ -1315,20 +1439,12 @@ Create rot-values \+ +\+ + (parse-white) ( c_addr1 u1 -- c_addr2 u2 ) gforth paren_parse_white -/* use !isgraph instead of isspace? */ -Char *endp = c_addr1+u1; -while (c_addr1body ( xt -- a_addr ) core to_body -"" Get the address of the body of the word represented by @i{xt} (the address -of the word's data field)."" -a_addr = PFA(xt); -: - 2 cells + ; - \ threading stuff is currently only interesting if we have a compiler \fhas? standardthreading has? compiler and [IF] - ->code-address ( xt -- c_addr ) gforth to_code_address -""@i{c-addr} is the code address of the word @i{xt}."" -/* !! This behaves installation-dependently for DOES-words */ -c_addr = (Address)CODE_ADDRESS(xt); -: - @ ; - ->does-code ( xt -- a_addr ) gforth to_does_code -""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); -: - cell+ @ ; - -code-address! ( c_addr xt -- ) gforth code_address_store -""Create a code field with code address @i{c-addr} at @i{xt}."" -MAKE_CF(xt, c_addr); -: - ! ; - -does-code! ( a_addr xt -- ) gforth does_code_store -""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); -: - dodoes: over ! cell+ ! ; - -does-handler! ( a_addr -- ) gforth does_handler_store -""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); -: - drop ; - -/does-handler ( -- n ) gforth slash_does_handler -""The size of a @code{DOES>}-handler (includes possible padding)."" -/* !! a constant or environmental query might be better */ -n = DOES_HANDLER_SIZE; -: - 2 cells ; - threading-method ( -- n ) gforth threading_method ""0 if the engine is direct threaded. Note that this may change during the lifetime of an image."" @@ -1469,7 +1535,7 @@ FLUSH_ICACHE(c_addr,u); SUPER_END; return (Label *)n; -(system) ( c_addr u -- wretval wior ) gforth peren_system +(system) ( c_addr u -- wretval wior ) gforth paren_system #ifndef MSDOS int old_tp=terminal_prepped; deprep_terminal(); @@ -1501,6 +1567,12 @@ wior = IOR(wretval==-1); time&date ( -- nsec nmin nhour nday nmonth nyear ) facility-ext time_and_date ""Report the current time of day. Seconds, minutes and hours are numbered from 0. Months are numbered from 1."" +#if 1 +time_t now; +struct tm *ltime; +time(&now); +ltime=localtime(&now); +#else struct timeval time1; struct timezone zone1; struct tm *ltime; @@ -1508,6 +1580,7 @@ gettimeofday(&time1,&zone1); /* !! Single Unix specification: If tzp is not a null pointer, the behaviour is unspecified. */ ltime=localtime((time_t *)&time1.tv_sec); +#endif nyear =ltime->tm_year+1900; nmonth=ltime->tm_mon+1; nday =ltime->tm_mday; @@ -1561,7 +1634,7 @@ c_addr = strerror(n); u = strlen(c_addr); strsignal ( n -- c_addr u ) gforth -c_addr = strsignal(n); +c_addr = (Address)strsignal(n); u = strlen(c_addr); call-c ( w -- ) gforth call_c @@ -1605,8 +1678,7 @@ wior = IOR(unlink(tilde_cstr(c_addr, u, rename-file ( c_addr1 u1 c_addr2 u2 -- wior ) file-ext rename_file ""Rename file @i{c_addr1 u1} to new name @i{c_addr2 u2}"" -char *s1=tilde_cstr(c_addr2, u2, 1); -wior = IOR(rename(tilde_cstr(c_addr1, u1, 0), s1)==-1); +wior = rename_file(c_addr1, u1, c_addr2, u2); file-position ( wfileid -- ud wior ) file file_position /* !! use tell and lseek? */ @@ -1632,26 +1704,12 @@ wior = FILEIO(u20. +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; +dent = readdir((DIR *)wdirid); +wior = 0; +flag = -1; +if(dent == NULL) { + u2 = 0; + flag = 0; +} else { + u2 = strlen(dent->d_name); + if(u2 > u1) { + u2 = u1; + wior = -512-ENAMETOOLONG; + } + memmove(c_addr, dent->d_name, u2); } +close-dir ( wdirid -- wior ) gforth close_dir +""Close the directory specified by @i{dir-id}."" +wior = IOR(closedir((DIR *)wdirid)); + +filename-match ( c_addr1 u1 c_addr2 u2 -- flag ) gforth match_file +char * string = cstr(c_addr1, u1, 1); +char * pattern = cstr(c_addr2, u2, 0); +flag = FLAG(!fnmatch(pattern, string, 0)); + +\+ + +newline ( -- c_addr u ) gforth +""String containing the newline sequence of the host OS"" +char newline[] = { +#if DIRSEP=='/' +/* Unix */ +'\n' +#else +/* DOS, Win, OS/2 */ +'\r','\n' +#endif +}; +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 \g floating @@ -1717,7 +1852,11 @@ comparisons(f0, r, f_zero_, r, 0., float d>f ( d -- r ) float d_to_f #ifdef BUGGY_LONG_LONG extern double ldexp(double x, int exp); -r = ldexp((Float)d.hi,CELL_BITS) + (Float)d.lo; +if (d.hi<0) { + DCell d2=dnegate(d); + r = -(ldexp((Float)d2.hi,CELL_BITS) + (Float)d2.lo); +} else + r = ldexp((Float)d.hi,CELL_BITS) + (Float)d.lo; #else r = d; #endif @@ -1832,13 +1971,18 @@ else represent ( r c_addr u -- n f1 f2 ) float char *sig; +size_t siglen; int flag; int decpt; sig=ecvt(r, u, &decpt, &flag); -n=(r==0 ? 1 : decpt); +n=(r==0. ? 1 : decpt); f1=FLAG(flag!=0); f2=FLAG(isdigit((unsigned)(sig[0]))!=0); -memmove(c_addr,sig,u); +siglen=strlen(sig); +if (siglen>u) /* happens in glibc-2.1.3 if 999.. is rounded up */ + siglen=u; +memcpy(c_addr,sig,siglen); +memset(c_addr+siglen,f2?'0':' ',u-siglen); >float ( c_addr u -- flag ) float to_float ""Actual stack effect: ( c_addr u -- r t | f ). Attempt to convert the @@ -1847,43 +1991,12 @@ representation. If the string represents @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); -char *endconv; -int sign = 0; -if(number[0]=='-') { - sign = 1; - number++; - u--; -} -while(isspace((unsigned)(number[--u])) && u>0); -switch(number[u]) -{ - case 'd': - case 'D': - case 'e': - case 'E': break; - default : u++; break; -} -number[u]='\0'; -r=strtod(number,&endconv); -if((flag=FLAG(!(Cell)*endconv))) -{ - IF_fpTOS(fp[0] = fpTOS); - fp += -1; - fpTOS = sign ? -r : r; -} -else if(*endconv=='d' || *endconv=='D') -{ - *endconv='E'; - r=strtod(number,&endconv); - if((flag=FLAG(!(Cell)*endconv))) - { - IF_fpTOS(fp[0] = fpTOS); - fp += -1; - fpTOS = sign ? -r : r; - } +flag = to_float(c_addr, u, &r); +if (flag) { + IF_fpTOS(fp[0] = fpTOS); + fp += -1; + fpTOS = r; } fabs ( r1 -- r2 ) float-ext f_abs @@ -2018,13 +2131,33 @@ df_addr = (DFloat *)((((Cell)c_addr)+(si : [ 1 dfloats 1- ] Literal + [ -1 dfloats ] Literal and ; +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."" +r = v_star(f_addr1, nstride1, f_addr2, nstride2, ucount); +: + >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"" +faxpy(ra, f_x, nstridex, f_y, nstridey, ucount); +: + >r swap 2swap swap r> 0 ?DO + fdup dup f@ f* over + 2swap dup f@ f+ dup f! over + 2swap + LOOP 2drop 2drop fdrop ; + +\+ + \ The following words access machine/OS/installation-dependent \ Gforth internals \ !! how about environmental queries DIRECT-THREADED, \ INDIRECT-THREADED, TOS-CACHED, FTOS-CACHED, CODEFIELD-DOES */ \ local variable implementation primitives -\+ + \+glocals \g locals @@ -2033,16 +2166,16 @@ df_addr = (DFloat *)((((Cell)c_addr)+(si w = *(Cell *)(lp+noffset); @local0 ( -- w ) new fetch_local_zero -w = *(Cell *)(lp+0*sizeof(Cell)); +w = ((Cell *)lp)[0]; @local1 ( -- w ) new fetch_local_four -w = *(Cell *)(lp+1*sizeof(Cell)); +w = ((Cell *)lp)[1]; @local2 ( -- w ) new fetch_local_eight -w = *(Cell *)(lp+2*sizeof(Cell)); +w = ((Cell *)lp)[2]; @local3 ( -- w ) new fetch_local_twelve -w = *(Cell *)(lp+3*sizeof(Cell)); +w = ((Cell *)lp)[3]; \+floating @@ -2050,10 +2183,10 @@ f@local# ( #noffset -- r ) gforth f_fetc r = *(Float *)(lp+noffset); f@local0 ( -- r ) new f_fetch_local_zero -r = *(Float *)(lp+0*sizeof(Float)); +r = ((Float *)lp)[0]; f@local1 ( -- r ) new f_fetch_local_eight -r = *(Float *)(lp+1*sizeof(Float)); +r = ((Float *)lp)[1]; \+ @@ -2102,37 +2235,6 @@ r = fp[u+1]; /* +1, because update of fp \g syslib -define(`uploop', - `pushdef(`$1', `$2')_uploop(`$1', `$2', `$3', `$4', `$5')`'popdef(`$1')') -define(`_uploop', - `ifelse($1, `$3', `$5', - `$4`'define(`$1', incr($1))_uploop(`$1', `$2', `$3', `$4', `$5')')') -\ argflist(argnum): Forth argument list -define(argflist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `format(`u%d ', _i)', `format(`u%d ', _i)')')') -\ argdlist(argnum): declare C's arguments -define(argdlist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `Cell, ', `Cell')')') -\ argclist(argnum): pass C's arguments -define(argclist, - `ifelse($1, 0, `', - `uploop(`_i', 1, $1, `format(`u%d, ', _i)', `format(`u%d', _i)')')') -\ icall(argnum) -define(icall, -`icall$1 ( argflist($1)u -- uret ) gforth -uret = (SYSCALL(Cell(*)(argdlist($1)))u)(argclist($1)); - -') -define(fcall, -`fcall$1 ( argflist($1)u -- rret ) gforth -rret = (SYSCALL(Float(*)(argdlist($1)))u)(argclist($1)); - -') - -\ close ' to keep fontify happy - open-lib ( c_addr1 u1 -- u2 ) gforth open_lib #if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) #ifndef RTLD_GLOBAL @@ -2160,598 +2262,224 @@ u3 = 0; # endif #endif -uploop(i, 0, 7, `icall(i)') -icall(20) -uploop(i, 0, 7, `fcall(i)') -fcall(20) +\+FFCALL -\+ +av-start-void ( c_addr -- ) gforth av_start_void +av_start_void(alist, c_addr); -up! ( a_addr -- ) gforth up_store -UP=up=(char *)a_addr; -: - up ! ; -Variable UP +av-start-int ( c_addr -- ) gforth av_start_int +av_start_int(alist, c_addr, &irv); -wcall ( u -- ) gforth -IF_fpTOS(fp[0]=fpTOS); -FP=fp; -sp=(Cell*)(SYSCALL(Cell*(*)(Cell *, void *))u)(sp, &FP); -fp=FP; -IF_spTOS(spTOS=sp[0];) -IF_fpTOS(fpTOS=fp[0]); +av-start-float ( c_addr -- ) gforth av_start_float +av_start_float(alist, c_addr, &frv); -\+file +av-start-double ( c_addr -- ) gforth av_start_double +av_start_double(alist, c_addr, &drv); -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)); -wior = IOR(wdirid == 0); +av-start-longlong ( c_addr -- ) gforth av_start_longlong +av_start_longlong(alist, c_addr, &llrv); -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; -dent = readdir((DIR *)wdirid); -wior = 0; -flag = -1; -if(dent == NULL) { - u2 = 0; - flag = 0; -} else { - u2 = strlen(dent->d_name); - if(u2 > u1) { - u2 = u1; - wior = -512-ENAMETOOLONG; - } - memmove(c_addr, dent->d_name, u2); -} +av-start-ptr ( c_addr -- ) gforth av_start_ptr +av_start_ptr(alist, c_addr, void*, &prv); -close-dir ( wdirid -- wior ) gforth close_dir -""Close the directory specified by @i{dir-id}."" -wior = IOR(closedir((DIR *)wdirid)); +av-int ( w -- ) gforth av_int +av_int(alist, w); -filename-match ( c_addr1 u1 c_addr2 u2 -- flag ) gforth match_file -char * string = cstr(c_addr1, u1, 1); -char * pattern = cstr(c_addr2, u2, 0); -flag = FLAG(!fnmatch(pattern, string, 0)); +av-float ( r -- ) gforth av_float +av_float(alist, r); -\+ +av-double ( r -- ) gforth av_double +av_double(alist, r); -newline ( -- c_addr u ) gforth -""String containing the newline sequence of the host OS"" -char newline[] = { -#if defined(unix) || defined(__MACH__) -/* Darwin/MacOS X sets __MACH__, but not unix. */ -'\n' -#else -'\r','\n' -#endif -}; -c_addr=newline; -u=sizeof(newline); -: - "newline count ; -Create "newline e? crlf [IF] 2 c, $0D c, [ELSE] 1 c, [THEN] $0A c, +av-longlong ( d -- ) gforth av_longlong +av_longlong(alist, d); -\+os +av-ptr ( c_addr -- ) gforth av_ptr +av_ptr(alist, void*, c_addr); -utime ( -- dtime ) gforth -""Report the current time in microseconds since some epoch."" -struct timeval time1; -gettimeofday(&time1,NULL); -dtime = timeval2us(&time1); +av-int-r ( R:w -- ) gforth av_int_r +av_int(alist, w); -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 +av-float-r ( -- ) gforth av_float_r +float r = *(Float*)lp; +lp += sizeof(Float); +av_float(alist, r); -\+ +av-double-r ( -- ) gforth av_double_r +double r = *(Float*)lp; +lp += sizeof(Float); +av_double(alist, r); -\+floating +av-longlong-r ( R:d -- ) gforth av_longlong_r +av_longlong(alist, d); -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 ; +av-ptr-r ( R:c_addr -- ) gforth av_ptr_r +av_ptr(alist, void*, c_addr); -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 ; +av-call-void ( -- ) gforth av_call_void +SAVE_REGS +av_call(alist); +REST_REGS -\+ +av-call-int ( -- w ) gforth av_call_int +SAVE_REGS +av_call(alist); +REST_REGS +w = irv; -\+file +av-call-float ( -- r ) gforth av_call_float +SAVE_REGS +av_call(alist); +REST_REGS +r = frv; -(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 ; +av-call-ptr ( -- c_addr ) gforth av_call_ptr +SAVE_REGS +av_call(alist); +REST_REGS +c_addr = prv; -\+hash +alloc-callback ( a_ip -- c_addr ) gforth alloc_callback +c_addr = (char *)alloc_callback(engine_callback, (Xt *)a_ip); -(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 ; +va-start-void ( -- ) gforth va_start_void +va_start_void(clist); -(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 ; +va-start-int ( -- ) gforth va_start_int +va_start_int(clist); -\+ +va-start-longlong ( -- ) gforth va_start_longlong +va_start_longlong(clist); -\+peephole +va-start-ptr ( -- ) gforth va_start_ptr +va_start_ptr(clist, (char *)); -\g peephole +va-start-float ( -- ) gforth va_start_float +va_start_float(clist); -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); +va-start-double ( -- ) gforth va_start_double +va_start_double(clist); -call ( #a_callee -- R:a_retaddr ) new -""Call callee (a variant of docol with inline argument)."" -#ifdef NO_IP -INST_TAIL; -JUMP(a_callee); -#else -#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); -#endif +va-arg-int ( -- w ) gforth va_arg_int +w = va_arg_int(clist); -useraddr ( #u -- a_addr ) new -a_addr = (Cell *)(up+u); +va-arg-longlong ( -- d ) gforth va_arg_longlong +d = va_arg_longlong(clist); -compile-prim ( xt1 -- xt2 ) obsolete compile_prim -xt2 = (Xt)compile_prim((Label)xt1); +va-arg-ptr ( -- c_addr ) gforth va_arg_ptr +c_addr = (char *)va_arg_ptr(clist,char*); -\ lit@ / lit_fetch = lit @ +va-arg-float ( -- r ) gforth va_arg_float +r = va_arg_float(clist); -lit@ ( #a_addr -- w ) new lit_fetch -w = *a_addr; +va-arg-double ( -- r ) gforth va_arg_double +r = va_arg_double(clist); -lit-perform ( #a_addr -- ) new lit_perform -#ifndef NO_IP -ip=IP; -#endif -SUPER_END; -EXEC(*(Xt *)a_addr); - -\ lit+ / lit_plus = lit + - -lit+ ( n1 #n2 -- n ) new lit_plus -n=n1+n2; - -does-exec ( #a_cfa -- R:nest a_pfa ) new does_exec -#ifdef NO_IP -/* compiled to LIT CALL by compile_prim */ -assert(0); -#else -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)); -#endif - -abranch-lp+!# ( #a_target #nlocals -- ) gforth abranch_lp_plus_store_number -/* this will probably not be used */ -lp += nlocals; -#ifdef NO_IP -INST_TAIL; -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -#endif +va-return-void ( -- ) gforth va_return_void +va_return_void(clist); +return 0; -\+ +va-return-int ( w -- ) gforth va_return_int +va_return_int(clist, w); +return 0; -abranch ( #a_target -- ) gforth -#ifdef NO_IP -INST_TAIL; -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -#endif -: - r> @ >r ; +va-return-ptr ( c_addr -- ) gforth va_return_ptr +va_return_ptr(clist, void *, c_addr); +return 0; -\ acondbranch(forthname,stackeffect,restline,code1,code2,forthcode) -\ this is non-syntactical: code must open a brace that is closed by the macro -define(acondbranch, -$1 ( `#'a_target $2 ) $3 -$4 #ifdef NO_IP -INST_TAIL; -#endif -$5 #ifdef NO_IP -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -$6 +va-return-longlong ( d -- ) gforth va_return_longlong +va_return_longlong(clist, d); +return 0; -\+glocals +va-return-float ( r -- ) gforth va_return_float +va_return_float(clist, r); +return 0; -$1-lp+!`#' ( `#'a_target `#'nlocals $2 ) $3_lp_plus_store_number -$4 #ifdef NO_IP -INST_TAIL; -#endif -$5 lp += nlocals; -#ifdef NO_IP -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; +va-return-double ( r -- ) gforth va_return_double +va_return_double(clist, r); +return 0; -\+ -) +\- -acondbranch(a?branch,f --,f83 aquestion_branch, -,if (f==0) { -,: - 0= dup \ !f !f \ !! still uses relative addresses - r> dup @ \ !f !f IP branchoffset - rot and + \ !f IP|IP+branchoffset - swap 0= cell and + \ IP'' - >r ;) +define(`uploop', + `pushdef(`$1', `$2')_uploop(`$1', `$2', `$3', `$4', `$5')`'popdef(`$1')') +define(`_uploop', + `ifelse($1, `$3', `$5', + `$4`'define(`$1', incr($1))_uploop(`$1', `$2', `$3', `$4', `$5')')') +\ argflist(argnum): Forth argument list +define(argflist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, `format(`u%d ', _i)', `format(`u%d ', _i)')')') +\ argdlist(argnum): declare C's arguments +define(argdlist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, `Cell, ', `Cell')')') +\ argclist(argnum): pass C's arguments +define(argclist, + `ifelse($1, 0, `', + `uploop(`_i', 1, $1, `format(`u%d, ', _i)', `format(`u%d', _i)')')') +\ icall(argnum) +define(icall, +`icall$1 ( argflist($1)u -- uret ) gforth +uret = (SYSCALL(Cell(*)(argdlist($1)))u)(argclist($1)); -\ we don't need an lp_plus_store version of the ?dup-stuff, because it -\ is only used in if's (yet) +') +define(fcall, +`fcall$1 ( argflist($1)u -- rret ) gforth +rret = (SYSCALL(Float(*)(argdlist($1)))u)(argclist($1)); -\+xconds +') -a?dup-?branch ( #a_target f -- f ) new aquestion_dupe_question_branch -""The run-time procedure compiled by @code{?DUP-IF}."" -if (f==0) { - sp++; - IF_spTOS(spTOS = sp[0]); -#ifdef NO_IP -INST_TAIL; -JUMP(a_target); -#else -SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; +\ close ' to keep fontify happy -a?dup-0=-?branch ( #a_target f -- ) new aquestion_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 -few cycles in that case, but is easy to convert to a CONDBRANCH -invocation */ -if (f!=0) { - sp--; -#ifdef NO_IP - JUMP(a_target); -#else - SET_IP((Xt *)a_target); - NEXT; -#endif -} -SUPER_CONTINUE; +uploop(i, 0, 7, `icall(i)') +icall(20) +uploop(i, 0, 7, `fcall(i)') +fcall(20) \+ -\f[THEN] -\fhas? skiploopprims 0= [IF] - -acondbranch(a(next),R:n1 -- R:n2,cmFORTH aparen_next, -n2=n1-1; -,if (n1) { -,: - r> r> dup 1- >r - IF @ >r ELSE cell+ >r THEN ;) - -acondbranch(a(loop),R:nlimit R:n1 -- R:nlimit R:n2,gforth aparen_loop, -n2=n1+1; -,if (n2 != nlimit) { -,: - r> r> 1+ r> 2dup = - IF >r 1- >r cell+ >r - ELSE >r >r @ >r THEN ;) - -acondbranch(a(+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth aparen_plus_loop, -/* !! check this thoroughly */ -/* sign bit manipulation and test: (x^y)<0 is equivalent to (x<0) != (y<0) */ -/* dependent upon two's complement arithmetic */ -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 */) { -,: - r> swap - r> r> 2dup - >r - 2 pick r@ + r@ xor 0< 0= - 3 pick r> xor 0< 0= or - IF >r + >r @ >r - ELSE >r >r drop cell+ >r THEN ;) - -\+xconds - -acondbranch(a(-loop),u R:nlimit R:n1 -- R:nlimit R:n2,gforth aparen_minus_loop, -UCell olddiff = n1-nlimit; -n2=n1-u; -,if (olddiff>u) { -,) +\+ -acondbranch(a(s+loop),n R:nlimit R:n1 -- R:nlimit R:n2,gforth aparen_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 diff = n1-nlimit; -Cell newdiff = diff+n; -if (n<0) { - diff = -diff; - newdiff = -newdiff; -} -n2=n1+n; -,if (diff>=0 || newdiff<0) { -,) +wcall ( u -- ) gforth +IF_fpTOS(fp[0]=fpTOS); +FP=fp; +sp=(Cell*)(SYSCALL(Cell*(*)(Cell *, void *))u)(sp, &FP); +fp=FP; +IF_spTOS(spTOS=sp[0];) +IF_fpTOS(fpTOS=fp[0]); -a(?do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth aparen_question_do -#ifdef NO_IP - INST_TAIL; -#endif -if (nstart == nlimit) { -#ifdef NO_IP - JUMP(a_target); -#else - SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -: - 2dup = - IF r> swap rot >r >r - @ >r - ELSE r> swap rot >r >r - cell+ >r - THEN ; \ --> CORE-EXT +\+peephole -\+xconds +\g peephole -a(+do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth aparen_plus_do -#ifdef NO_IP - INST_TAIL; -#endif -if (nstart >= nlimit) { -#ifdef NO_IP - JUMP(a_target); -#else - SET_IP((Xt *)a_target); - INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -: - swap 2dup - r> swap >r swap >r - >= - IF - @ - ELSE - cell+ - THEN >r ; +compile-prim1 ( a_prim -- ) gforth compile_prim1 +""compile prim (incl. immargs) at @var{a_prim}"" +compile_prim1(a_prim); -a(u+do) ( #a_target ulimit ustart -- R:ulimit R:ustart ) gforth aparen_u_plus_do -#ifdef NO_IP - INST_TAIL; -#endif -if (ustart >= ulimit) { -#ifdef NO_IP -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -: - swap 2dup - r> swap >r swap >r - u>= - IF - @ - ELSE - cell+ - THEN >r ; +finish-code ( -- ) gforth finish_code +""Perform delayed steps in code generation (branch resolution, I-cache +flushing)."" +finish_code(); -a(-do) ( #a_target nlimit nstart -- R:nlimit R:nstart ) gforth aparen_minus_do -#ifdef NO_IP - INST_TAIL; -#endif -if (nstart <= nlimit) { -#ifdef NO_IP -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -: - swap 2dup - r> swap >r swap >r - <= - IF - @ - ELSE - cell+ - THEN >r ; +forget-dyncode ( c_code -- f ) gforth-internal forget_dyncode +f = forget_dyncode(c_code); -a(u-do) ( #a_target ulimit ustart -- R:ulimit R:ustart ) gforth aparen_u_minus_do -#ifdef NO_IP - INST_TAIL; -#endif -if (ustart <= ulimit) { -#ifdef NO_IP -JUMP(a_target); -#else -SET_IP((Xt *)a_target); -INST_TAIL; NEXT_P2; -#endif -} -SUPER_CONTINUE; -: - swap 2dup - r> swap >r swap >r - u<= - IF - @ - ELSE - cell+ - THEN >r ; +decompile-prim ( a_code -- a_prim ) gforth-internal decompile_prim +""a_prim is the code address of the primitive that has been +compile_prim1ed to a_code"" +a_prim = (Cell *)decompile_code((Label)a_code); \ set-next-code and call2 do not appear in images and can be \ renumbered arbitrarily @@ -2770,27 +2498,18 @@ JUMP(a_callee); assert(0); #endif -compile-prim1 ( a_prim -- ) gforth compile_prim1 -""compile prim (incl. immargs) at @var{a_prim}"" -compile_prim1(a_prim); - -finish-code ( -- ) gforth finish_code -""Perform delayed steps in code generation (branch resolution, I-cache -flushing)."" -finish_code(); +tag-offsets ( -- a_addr ) gforth tag_offsets +extern Cell groups[32]; +a_addr = groups; -forget-dyncode ( c_code -- f ) gforth-internal forget_dyncode -f = forget_dyncode(c_code); +\+ -decompile-prim ( a_code -- a_prim ) gforth-internal decompile_prim -""a_prim is the code address of the primitive that has been -compile_prim1ed to a_code"" -a_prim = decompile_code(a_code); +\g static_super -\+ +\C #if !defined(GFORTH_DEBUGGING) && !defined(INDIRECT_THREADED) && !defined(DOUBLY_INDIRECT) && !defined(VM_PROFILING) include(peeprules.vmg) -\g end +\C #endif -\+ +\g end