File:  [gforth] / gforth / Attic / primitives
Revision 1.26: download - view: text, annotated - select for diffs
Mon Dec 12 17:10:49 1994 UTC (29 years, 4 months ago) by anton
Branches: MAIN
CVS tags: HEAD
Reorganized configuration: configure is now created by autoconf from
configure.in; I still left it in the CVS repository because not
everyone has autoconf. decstation.h renamed to mips.h and apollo68k to
m68k. Added general 32bit.h description, which the other machine
descriptions use. Created/copied replacement files install-sh memcmp.c
memmove.c select.c (carved out from ecvt.c) strtol.c
strtoul.c. Bytesex is now handled by configure.

Deciding the threading method is now done in machine.h, this should
also be done for USE_TOS and USE_FTOS.

    1: \ Copyright 1992 by the ANSI figForth Development Group
    2: \ 
    3: \ WARNING: This file is processed by m4. Make sure your identifiers
    4: \ don't collide with m4's (e.g. by undefining them).
    5: \ 
    6: \ 
    7: \ 
    8: \ This file contains instructions in the following format:
    9: \ 
   10: \ forth name	stack effect	category	[pronunciation]
   11: \ [""glossary entry""]
   12: \ C code
   13: \ [:
   14: \ Forth code]
   15: \ 
   16: \ The pronunciation is also used for forming C names.
   17: \ 
   18: \ 
   19: \ 
   20: \ These informations are automatically translated into C-code for the
   21: \ interpreter and into some other files. I hope that your C compiler has
   22: \ decent optimization, otherwise the automatically generated code will
   23: \ be somewhat slow. The Forth version of the code is included for manual
   24: \ compilers, so they will need to compile only the important words.
   25: \ 
   26: \ Note that stack pointer adjustment is performed according to stack
   27: \ effect by automatically generated code and NEXT is automatically
   28: \ appended to the C code. Also, you can use the names in the stack
   29: \ effect in the C code. Stack access is automatic. One exception: if
   30: \ your code does not fall through, the results are not stored into the
   31: \ stack. Use different names on both sides of the '--', if you change a
   32: \ value (some stores to the stack are optimized away).
   33: \ 
   34: \ 
   35: \ 
   36: \ The stack variables have the following types:
   37: \ 
   38: \ name matches	type
   39: \ f.*		Bool
   40: \ c.*		Char
   41: \ [nw].*		Cell
   42: \ u.*		UCell
   43: \ d.*		DCell
   44: \ ud.*		UDCell
   45: \ r.*		Float
   46: \ a_.*		Cell *
   47: \ c_.*		Char *
   48: \ f_.*		Float *
   49: \ df_.*		DFloat *
   50: \ sf_.*		SFloat *
   51: \ xt.*		XT
   52: \ wid.*		WID
   53: \ f83name.*	F83Name *
   54: \ 
   55: \ 
   56: \ 
   57: \ In addition the following names can be used:
   58: \ ip	the instruction pointer
   59: \ sp	the data stack pointer
   60: \ rp	the parameter stack pointer
   61: \ lp	the locals stack pointer
   62: \ NEXT	executes NEXT
   63: \ cfa	
   64: \ NEXT1	executes NEXT1
   65: \ FLAG(x)	makes a Forth flag from a C flag
   66: \ 
   67: \ 
   68: \ 
   69: \ Percentages in comments are from Koopmans book: average/maximum use
   70: \ (taken from four, not very representative benchmarks)
   71: \ 
   72: \ 
   73: \ 
   74: \ To do:
   75: \ 
   76: \ throw execute, cfa and NEXT1 out?
   77: \ macroize *ip, ip++, *ip++ (pipelining)?
   78: 
   79: \ these m4 macros would collide with identifiers
   80: undefine(`index')
   81: undefine(`shift')
   82: 
   83: noop	--		fig
   84: ;
   85: :
   86:  ;
   87: 
   88: lit	-- w		fig
   89: w = (Cell)*ip++;
   90: 
   91: execute		xt --		core,fig
   92: cfa = xt;
   93: IF_TOS(TOS = sp[0]);
   94: NEXT1;
   95: 
   96: branch-lp+!#	--	new	branch_lp_plus_store_number
   97: /* this will probably not be used */
   98: branch_adjust_lp:
   99: lp += (int)(ip[1]);
  100: goto branch;
  101: 
  102: branch	--		fig
  103: branch:
  104: ip = (Xt *)(((int)ip)+(int)*ip);
  105: :
  106:  r> dup @ + >r ;
  107: 
  108: \ condbranch(forthname,restline,code)
  109: \ this is non-syntactical: code must open a brace that is close by the macro
  110: define(condbranch,
  111: $1	$2
  112: $3    goto branch;
  113: }
  114: else
  115:     ip++;
  116: 
  117: $1-lp+!#	$2_lp_plus_store_number
  118: $3    goto branch_adjust_lp;
  119: }
  120: else
  121:     ip+=2;
  122: 
  123: )
  124: 
  125: condbranch(?branch,f --		f83	question_branch,
  126: if (f==0) {
  127:     IF_TOS(TOS = sp[0]);
  128: )
  129: 
  130: condbranch((next),--		cmFORTH	paren_next,
  131: if ((*rp)--) {
  132: )
  133: 
  134: condbranch((loop),--		fig	paren_loop,
  135: int index = *rp+1;
  136: int limit = rp[1];
  137: if (index != limit) {
  138:     *rp = index;
  139: )
  140: 
  141: condbranch((+loop),n --		fig	paren_plus_loop,
  142: /* !! check this thoroughly */
  143: int index = *rp;
  144: /* sign bit manipulation and test: (x^y)<0 is equivalent to (x<0) != (y<0) */
  145: /* dependent upon two's complement arithmetic */
  146: int olddiff = index-rp[1];
  147: #ifdef undefined
  148: if ((olddiff^(olddiff+n))>=0   /* the limit is not crossed */
  149:     || (olddiff^n)>=0          /* it is a wrap-around effect */) {
  150: #else
  151: #ifndef MAXINT
  152: #define MAXINT ((1<<(8*sizeof(Cell)-1))-1)
  153: #endif
  154: if(((olddiff^MAXINT) >= n) ^ ((olddiff+n) < 0)) {
  155: #endif
  156: #ifdef i386
  157:     *rp += n;
  158: #else
  159:     *rp = index + n;
  160: #endif
  161:     IF_TOS(TOS = sp[0]);
  162: )
  163: 
  164: condbranch((s+loop),n --		new	paren_symmetric_plus_loop,
  165: ""The run-time procedure compiled by S+LOOP. It loops until the index
  166: crosses the boundary between limit and limit-sign(n). I.e. a symmetric
  167: version of (+LOOP).""
  168: /* !! check this thoroughly */
  169: int index = *rp;
  170: int diff = index-rp[1];
  171: int newdiff = diff+n;
  172: if (n<0) {
  173:     diff = -diff;
  174:     newdiff = -newdiff;
  175: }
  176: if (diff>=0 || newdiff<0) {
  177: #ifdef i386
  178:     *rp += n;
  179: #else
  180:     *rp = index + n;
  181: #endif
  182:     IF_TOS(TOS = sp[0]);
  183: )
  184: 
  185: unloop		--	core
  186: rp += 2;
  187: :
  188:  r> rdrop rdrop >r ;
  189: 
  190: (for)	ncount --		cmFORTH		paren_for
  191: /* or (for) = >r -- collides with unloop! */
  192: *--rp = 0;
  193: *--rp = ncount;
  194: :
  195:  r> swap 0 >r >r >r ;
  196: 
  197: (do)	nlimit nstart --		fig		paren_do
  198: /* or do it in high-level? 0.09/0.23% */
  199: *--rp = nlimit;
  200: *--rp = nstart;
  201: :
  202:  r> -rot swap >r >r >r ;
  203: 
  204: (?do)	nlimit nstart --	core-ext	paren_question_do
  205: *--rp = nlimit;
  206: *--rp = nstart;
  207: if (nstart == nlimit) {
  208:     IF_TOS(TOS = sp[0]);
  209:     goto branch;
  210:     }
  211: else {
  212:     ip++;
  213: }
  214: 
  215: i	-- n		core,fig
  216: n = *rp;
  217: 
  218: j	-- n		core
  219: n = rp[2];
  220: 
  221: \ digit is high-level: 0/0%
  222: 
  223: (emit)	c --		fig	paren_emit
  224: putchar(c);
  225: emitcounter++;
  226: 
  227: (type)	c_addr n --	fig	paren_type
  228: fwrite(c_addr,sizeof(Char),n,stdout);
  229: emitcounter += n;
  230: 
  231: (key)	-- n		fig	paren_key
  232: fflush(stdout);
  233: /* !! noecho */
  234: n = key();
  235: 
  236: key?	-- n		fig	key_q
  237: fflush(stdout);
  238: n = key_query;
  239: 
  240: cr	--		fig
  241: puts("");
  242: :
  243:  $0A emit ;
  244: 
  245: move	c_from c_to ucount --		core
  246: memmove(c_to,c_from,ucount);
  247: /* make an Ifdef for bsd and others? */
  248: :
  249:  >r 2dup u< IF r> cmove> ELSE r> cmove THEN ;
  250: 
  251: cmove	c_from c_to u --	string
  252: while (u-- > 0)
  253:   *c_to++ = *c_from++;
  254: :
  255:  bounds ?DO  dup c@ I c! 1+  LOOP  drop ;
  256: 
  257: cmove>	c_from c_to u --	string	c_move_up
  258: while (u-- > 0)
  259:   c_to[u] = c_from[u];
  260: :
  261:  dup 0= IF  drop 2drop exit  THEN
  262:  rot over + -rot bounds swap 1-
  263:  DO  1- dup c@ I c!  -1 +LOOP  drop ;
  264: 
  265: fill	c_addr u c --	core
  266: memset(c_addr,c,u);
  267: :
  268:  -rot bounds
  269:  ?DO  dup I c!  LOOP  drop ;
  270: 
  271: compare		c_addr1 u1 c_addr2 u2 -- n	string
  272: ""Compare the strings lexicographically. If they are equal, n is 0; if
  273: the first string is smaller, n is -1; if the first string is larger, n
  274: is 1. Currently this is based on the machine's character
  275: comparison. In the future, this may change to considering the current
  276: locale and its collation order.""
  277: n = memcmp(c_addr1, c_addr2, u1<u2 ? u1 : u2);
  278: if (n==0)
  279:   n = u1-u2;
  280: if (n<0)
  281:   n = -1;
  282: else if (n>0)
  283:   n = 1;
  284: :
  285:  rot 2dup - >r min swap -text dup
  286:  IF    rdrop
  287:  ELSE  drop r@ 0>
  288:        IF    rdrop -1
  289:        ELSE  r> 1 and
  290:        THEN
  291:  THEN ;
  292: 
  293: -text		c_addr1 u c_addr2 -- n	new	dash_text
  294: n = memcmp(c_addr1, c_addr2, u);
  295: if (n<0)
  296:   n = -1;
  297: else if (n>0)
  298:   n = 1;
  299: :
  300:  swap bounds
  301:  ?DO  dup c@ I c@ = WHILE  1+  LOOP  drop 0
  302:  ELSE  c@ I c@ - unloop  THEN  -text-flag ;
  303: : -text-flag ( n -- -1/0/1 )
  304:  dup 0< IF  drop -1  ELSE  0>  IF  1  ELSE  0  THEN  THEN  ;
  305: 
  306: capscomp	c_addr1 u c_addr2 -- n	new
  307: Char c1, c2;
  308: for (;; u--, c_addr1++, c_addr2++) {
  309:   if (u == 0) {
  310:     n = 0;
  311:     break;
  312:   }
  313:   c1 = toupper(*c_addr1);
  314:   c2 = toupper(*c_addr2);
  315:   if (c1 != c2) {
  316:     if (c1 < c2)
  317:       n = -1;
  318:     else
  319:       n = 1;
  320:     break;
  321:   }
  322: }
  323: :
  324:  swap bounds
  325:  ?DO  dup c@ toupper I c@ toupper = WHILE  1+  LOOP  drop 0
  326:  ELSE  c@ toupper I c@ toupper - unloop  THEN  -text-flag ;
  327: 
  328: -trailing	c_addr u1 -- c_addr u2		string	dash_trailing
  329: u2 = u1;
  330: while (c_addr[u2-1] == ' ')
  331:   u2--;
  332: :
  333:  BEGIN  1- 2dup + c@ bl =  WHILE
  334:         dup  0= UNTIL  ELSE  1+  THEN ;
  335: 
  336: /string		c_addr1 u1 n -- c_addr2 u2	string	slash_string
  337: c_addr2 = c_addr1+n;
  338: u2 = u1-n;
  339: :
  340:  tuck - >r + r> dup 0< IF  - 0  THEN ;
  341: 
  342: +	n1 n2 -- n		core,fig	plus
  343: n = n1+n2;
  344: 
  345: -	n1 n2 -- n		core,fig	minus
  346: n = n1-n2;
  347: :
  348:  negate + ;
  349: 
  350: negate	n1 -- n2		core,fig
  351: /* use minus as alias */
  352: n2 = -n1;
  353: :
  354:  invert 1+ ;
  355: 
  356: 1+	n1 -- n2		core		one_plus
  357: n2 = n1+1;
  358: :
  359:  1 + ;
  360: 
  361: 1-	n1 -- n2		core		one_minus
  362: n2 = n1-1;
  363: :
  364:  1 - ;
  365: 
  366: max	n1 n2 -- n	core
  367: if (n1<n2)
  368:   n = n2;
  369: else
  370:   n = n1;
  371: :
  372:  2dup < IF swap THEN drop ;
  373: 
  374: min	n1 n2 -- n	core
  375: if (n1<n2)
  376:   n = n1;
  377: else
  378:   n = n2;
  379: :
  380:  2dup > IF swap THEN drop ;
  381: 
  382: abs	n1 -- n2	core
  383: if (n1<0)
  384:   n2 = -n1;
  385: else
  386:   n2 = n1;
  387: :
  388:  dup 0< IF negate THEN ;
  389: 
  390: *	n1 n2 -- n		core,fig	star
  391: n = n1*n2;
  392: :
  393:  um* drop ;
  394: 
  395: /	n1 n2 -- n		core,fig	slash
  396: n = n1/n2;
  397: :
  398:  /mod nip ;
  399: 
  400: mod	n1 n2 -- n		core
  401: n = n1%n2;
  402: :
  403:  /mod drop ;
  404: 
  405: /mod	n1 n2 -- n3 n4		core		slash_mod
  406: n4 = n1/n2;
  407: n3 = n1%n2; /* !! is this correct? look into C standard! */
  408: :
  409:  >r s>d r> fm/mod ;
  410: 
  411: 2*	n1 -- n2		core		two_star
  412: n2 = 2*n1;
  413: :
  414:  dup + ;
  415: 
  416: 2/	n1 -- n2		core		two_slash
  417: /* !! is this still correct? */
  418: n2 = n1>>1;
  419: 
  420: fm/mod	d1 n1 -- n2 n3		core		f_m_slash_mod
  421: ""floored division: d1 = n3*n1+n2, n1>n2>=0 or 0>=n2>n1""
  422: /* assumes that the processor uses either floored or symmetric division */
  423: n3 = d1/n1;
  424: n2 = d1%n1;
  425: /* note that this 1%-3>0 is optimized by the compiler */
  426: if (1%-3>0 && (d1<0) != (n1<0) && n2!=0) {
  427:   n3--;
  428:   n2+=n1;
  429: }
  430: 
  431: sm/rem	d1 n1 -- n2 n3		core		s_m_slash_rem
  432: ""symmetric division: d1 = n3*n1+n2, sign(n2)=sign(d1) or 0""
  433: /* assumes that the processor uses either floored or symmetric division */
  434: n3 = d1/n1;
  435: n2 = d1%n1;
  436: /* note that this 1%-3<0 is optimized by the compiler */
  437: if (1%-3<0 && (d1<0) != (n1<0) && n2!=0) {
  438:   n3++;
  439:   n2-=n1;
  440: }
  441: :
  442:  over >r dup >r abs -rot
  443:  dabs rot um/mod
  444:  r> 0< IF       negate       THEN
  445:  r> 0< IF  swap negate swap  THEN ;
  446: 
  447: m*	n1 n2 -- d		core	m_star
  448: d = (DCell)n1 * (DCell)n2;
  449: :
  450:  2dup      0< and >r
  451:  2dup swap 0< and >r
  452:  um* r> - r> - ;
  453: 
  454: um*	u1 u2 -- ud		core	u_m_star
  455: /* use u* as alias */
  456: ud = (UDCell)u1 * (UDCell)u2;
  457: 
  458: um/mod	ud u1 -- u2 u3		core	u_m_slash_mod
  459: u3 = ud/u1;
  460: u2 = ud%u1;
  461: :
  462:   dup IF  0 (um/mod)  THEN  nip ; 
  463: : (um/mod)  ( ud ud--ud u)
  464:   2dup >r >r  dup 0< 
  465:   IF    2drop 0 
  466:   ELSE  2dup d+  (um/mod)  2*  THEN 
  467:   -rot  r> r> 2over 2over  du<
  468:   IF    2drop rot 
  469:   ELSE  dnegate  d+  rot 1+  THEN ; 
  470: 
  471: m+	d1 n -- d2		double		m_plus
  472: d2 = d1+n;
  473: :
  474:  s>d d+ ;
  475: 
  476: d+	d1 d2 -- d		double,fig	d_plus
  477: d = d1+d2;
  478: :
  479:  >r swap >r over 2/ over 2/ + >r over 1 and over 1 and + 2/
  480:  r> + >r + r> 0< r> r> + swap - ;
  481: 
  482: d-	d1 d2 -- d		double		d_minus
  483: d = d1-d2;
  484: :
  485:  dnegate d+ ;
  486: 
  487: dnegate	d1 -- d2		double
  488: /* use dminus as alias */
  489: d2 = -d1;
  490: :
  491:  invert swap negate tuck 0= - ;
  492: 
  493: dmax	d1 d2 -- d	double
  494: if (d1<d2)
  495:   d = d2;
  496: else
  497:   d = d1;
  498: :
  499:  2over 2over d> IF  2swap  THEN 2drop ;
  500: 
  501: dmin	d1 d2 -- d	double
  502: if (d1<d2)
  503:   d = d1;
  504: else
  505:   d = d2;
  506: :
  507:  2over 2over d< IF  2swap  THEN 2drop ;
  508: 
  509: dabs	d1 -- d2	double
  510: if (d1<0)
  511:   d2 = -d1;
  512: else
  513:   d2 = d1;
  514: :
  515:  dup 0< IF dnegate THEN ;
  516: 
  517: d2*	d1 -- d2		double		d_two_star
  518: d2 = 2*d1;
  519: :
  520:  2dup d+ ;
  521: 
  522: d2/	d1 -- d2		double		d_two_slash
  523: /* !! is this still correct? */
  524: d2 = d1>>1;
  525: :
  526:  dup 1 and >r 2/ swap 2/ [ 1 8 cells 1- lshift 1- ] Literal and
  527:  r> IF  [ 1 8 cells 1- lshift ] Literal + THEN  swap ;
  528: 
  529: d>s	d -- n			double		d_to_s
  530: /* make this an alias for drop? */
  531: n = d;
  532: :
  533:  drop ;
  534: 
  535: and	w1 w2 -- w		core,fig
  536: w = w1&w2;
  537: 
  538: or	w1 w2 -- w		core,fig
  539: w = w1|w2;
  540: 
  541: xor	w1 w2 -- w		core,fig
  542: w = w1^w2;
  543: 
  544: invert	w1 -- w2		core
  545: w2 = ~w1;
  546: :
  547:  -1 xor ;
  548: 
  549: rshift	u1 n -- u2		core
  550:   u2 = u1>>n;
  551: 
  552: lshift	u1 n -- u2		core
  553:   u2 = u1<<n;
  554: 
  555: \ comparisons(prefix, args, prefix, arg1, arg2, wordsets...)
  556: define(comparisons,
  557: $1=	$2 -- f		$6	$3equals
  558: f = FLAG($4==$5);
  559: 
  560: $1<>	$2 -- f		$7	$3different
  561: /* use != as alias ? */
  562: f = FLAG($4!=$5);
  563: 
  564: $1<	$2 -- f		$8	$3less
  565: f = FLAG($4<$5);
  566: 
  567: $1>	$2 -- f		$9	$3greater
  568: f = FLAG($4>$5);
  569: 
  570: $1<=	$2 -- f		new	$3less_or_equal
  571: f = FLAG($4<=$5);
  572: 
  573: $1>=	$2 -- f		new	$3greater_or_equal
  574: f = FLAG($4>=$5);
  575: 
  576: )
  577: 
  578: comparisons(0, n, zero_, n, 0, core, core-ext, core, core-ext)
  579: comparisons(, n1 n2, , n1, n2, core, core-ext, core, core)
  580: comparisons(u, u1 u2, u_, u1, u2, new, new, core, core-ext)
  581: comparisons(d, d1 d2, d_, d1, d2, double, new, double, new)
  582: comparisons(d0, d, d_zero_, d, 0, double, new, double, new)
  583: comparisons(du, ud1 ud2, d_u_, ud1, ud2, new, new, double-ext, new)
  584: 
  585: within	u1 u2 u3 -- f		core-ext
  586: f = FLAG(u1-u2 < u3-u2);
  587: :
  588:  over - >r - r> u< ;
  589: 
  590: sp@	-- a_addr		fig		spat
  591: a_addr = sp+1;
  592: 
  593: sp!	a_addr --		fig		spstore
  594: sp = a_addr;
  595: /* works with and without TOS caching */
  596: 
  597: rp@	-- a_addr		fig		rpat
  598: a_addr = rp;
  599: 
  600: rp!	a_addr --		fig		rpstore
  601: rp = a_addr;
  602: 
  603: fp@	-- f_addr	new	fp_fetch
  604: f_addr = fp;
  605: 
  606: fp!	f_addr --	new	fp_store
  607: fp = f_addr;
  608: 
  609: ;s	--		fig	semis
  610: ip = (Xt *)(*rp++);
  611: 
  612: >r	w --		core,fig	to_r
  613: *--rp = w;
  614: 
  615: r>	-- w		core,fig	r_from
  616: w = *rp++;
  617: 
  618: r@	-- w		core,fig	r_fetch
  619: /* use r as alias */
  620: /* make r@ an alias for i */
  621: w = *rp;
  622: 
  623: rdrop	--		fig
  624: rp++;
  625: 
  626: i'	-- w		fig		i_tick
  627: w=rp[1];
  628: 
  629: 2>r	w1 w2 --	core-ext	two_to_r
  630: *--rp = w1;
  631: *--rp = w2;
  632: 
  633: 2r>	-- w1 w2	core-ext	two_r_from
  634: w2 = *rp++;
  635: w1 = *rp++;
  636: 
  637: 2r@	-- w1 w2	core-ext	two_r_fetch
  638: w2 = rp[0];
  639: w1 = rp[1];
  640: 
  641: 2rdrop	--		new	two_r_drop
  642: rp+=2;
  643: 
  644: over	w1 w2 -- w1 w2 w1		core,fig
  645: 
  646: drop	w --		core,fig
  647: 
  648: swap	w1 w2 -- w2 w1		core,fig
  649: 
  650: dup	w -- w w		core,fig
  651: 
  652: rot	w1 w2 w3 -- w2 w3 w1	core	rote
  653: 
  654: -rot	w1 w2 w3 -- w3 w1 w2	fig	not_rote
  655: :
  656:  rot rot ;
  657: 
  658: nip	w1 w2 -- w2		core-ext
  659: :
  660:  swap drop ;
  661: 
  662: tuck	w1 w2 -- w2 w1 w2	core-ext
  663: :
  664:  swap over ;
  665: 
  666: ?dup	w -- w			core	question_dupe
  667: if (w!=0) {
  668:   IF_TOS(*sp-- = w;)
  669: #ifndef USE_TOS
  670:   *--sp = w;
  671: #endif
  672: }
  673: :
  674:  dup IF dup THEN ;
  675: 
  676: pick	u -- w			core-ext
  677: w = sp[u+1];
  678: :
  679:  1+ cells sp@ + @ ;
  680: 
  681: 2drop	w1 w2 --		core	two_drop
  682: :
  683:  drop drop ;
  684: 
  685: 2dup	w1 w2 -- w1 w2 w1 w2	core	two_dupe
  686: :
  687:  over over ;
  688: 
  689: 2over	w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2	core	two_over
  690: :
  691:  3 pick 3 pick ;
  692: 
  693: 2swap	w1 w2 w3 w4 -- w3 w4 w1 w2	core	two_swap
  694: :
  695:  >r -rot r> -rot ;
  696: 
  697: 2rot	w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2	double	two_rote
  698: :
  699:  >r >r 2swap r> r> 2swap ;
  700: 
  701: \ toggle is high-level: 0.11/0.42%
  702: 
  703: @	a_addr -- w		fig	fetch
  704: w = *a_addr;
  705: 
  706: !	w a_addr --		core,fig	store
  707: *a_addr = w;
  708: 
  709: +!	n a_addr --		core,fig	plus_store
  710: *a_addr += n;
  711: 
  712: c@	c_addr -- c		fig	cfetch
  713: c = *c_addr;
  714: 
  715: c!	c c_addr --		fig	cstore
  716: *c_addr = c;
  717: 
  718: 2!	w1 w2 a_addr --		core	two_store
  719: a_addr[0] = w2;
  720: a_addr[1] = w1;
  721: :
  722:  tuck ! cell+ ! ;
  723: 
  724: 2@	a_addr -- w1 w2		core	two_fetch
  725: w2 = a_addr[0];
  726: w1 = a_addr[1];
  727: :
  728:  dup cell+ @ swap @ ;
  729: 
  730: d!	d a_addr --		double	d_store
  731: /* !! alignment problems on some machines */
  732: *(DCell *)a_addr = d;
  733: 
  734: d@	a_addr -- d		double	d_fetch
  735: d = *(DCell *)a_addr;
  736: 
  737: cell+	a_addr1 -- a_addr2	core	cell_plus
  738: a_addr2 = a_addr1+1;
  739: :
  740:  [ cell ] Literal + ;
  741: 
  742: cells	n1 -- n2		core
  743: n2 = n1 * sizeof(Cell);
  744: :
  745:  [ cell ]
  746:  [ 2/ dup ] [IF] 2* [THEN]
  747:  [ 2/ dup ] [IF] 2* [THEN]
  748:  [ 2/ dup ] [IF] 2* [THEN]
  749:  [ 2/ dup ] [IF] 2* [THEN]
  750:  [ drop ] ;
  751: 
  752: char+	c_addr1 -- c_addr2	core	care_plus
  753: c_addr2 = c_addr1 + 1;
  754: :
  755:  1+ ;
  756: 
  757: (chars)		n1 -- n2	gforth	paren_cares
  758: n2 = n1 * sizeof(Char);
  759: :
  760:  ;
  761: 
  762: count	c_addr1 -- c_addr2 u	core
  763: u = *c_addr1;
  764: c_addr2 = c_addr1+1;
  765: :
  766:  dup 1+ swap c@ ;
  767: 
  768: (bye)	n --	toolkit-ext	paren_bye
  769: return (Label *)n;
  770: 
  771: system	c_addr u -- n	own
  772: n=system(cstr(c_addr,u,1));
  773: 
  774: getenv	c_addr1 u1 -- c_addr2 u2	new
  775: c_addr2 = getenv(cstr(c_addr1,u1,1));
  776: u2=strlen(c_addr2);
  777: 
  778: popen	c_addr u n -- wfileid	own
  779: static char* mode[2]={"r","w"};
  780: wfileid=(Cell)popen(cstr(c_addr,u,1),mode[n]);
  781: 
  782: pclose	wfileid -- wior	own
  783: wior=pclose((FILE *)wfileid);
  784: 
  785: time&date	-- nsec nmin nhour nday nmonth nyear	facility-ext	time_and_date
  786: struct timeval time1;
  787: struct timezone zone1;
  788: struct tm *ltime;
  789: gettimeofday(&time1,&zone1);
  790: ltime=localtime(&time1.tv_sec);
  791: nyear =ltime->tm_year+1900;
  792: nmonth=ltime->tm_mon+1;
  793: nday  =ltime->tm_mday;
  794: nhour =ltime->tm_hour;
  795: nmin  =ltime->tm_min;
  796: nsec  =ltime->tm_sec;
  797: 
  798: ms	n --	facility-ext
  799: struct timeval timeout;
  800: timeout.tv_sec=n/1000;
  801: timeout.tv_usec=1000*(n%1000);
  802: (void)select(0,0,0,0,&timeout);
  803: 
  804: allocate	u -- a_addr wior	memory
  805: a_addr = (Cell *)malloc(u);
  806: wior = a_addr==NULL;	/* !! Define a return code */
  807: 
  808: free		a_addr -- wior		memory
  809: free(a_addr);
  810: wior = 0;
  811: 
  812: resize		a_addr1 u -- a_addr2 wior	memory
  813: a_addr2 = realloc(a_addr1, u);
  814: wior = a_addr2==NULL;	/* !! Define a return code */
  815: 
  816: (f83find)	c_addr u f83name1 -- f83name2	new	paren_f83find
  817: for (; f83name1 != NULL; f83name1 = f83name1->next)
  818:   if (F83NAME_COUNT(f83name1)==u &&
  819:       strncasecmp(c_addr, f83name1->name, u)== 0 /* or inline? */)
  820:     break;
  821: f83name2=f83name1;
  822: :
  823:  BEGIN  dup  WHILE
  824:         >r dup r@ cell+ c@ $1F and =
  825: 	IF  2dup r@ cell+ char+ capscomp  0=
  826: 	    IF  2drop r>  EXIT  THEN  THEN
  827: 	r> @
  828:  REPEAT  nip nip ;
  829: 
  830: (hashfind)	c_addr u a_addr -- f83name2	new	paren_hashfind
  831: F83Name *f83name1;
  832: f83name2=NULL;
  833: while(a_addr != NULL)
  834: {
  835:    f83name1=(F83Name *)(a_addr[1]);
  836:    a_addr=(Cell *)(a_addr[0]);
  837:    if (F83NAME_COUNT(f83name1)==u &&
  838:        strncasecmp(c_addr, f83name1->name, u)== 0 /* or inline? */)
  839:      {
  840: 	f83name2=f83name1;
  841: 	break;
  842:      }
  843: }
  844: :
  845:  BEGIN  dup  WHILE
  846:         2@ >r >r dup r@ cell+ c@ $1F and =
  847:         IF  2dup r@ cell+ char+ capscomp 0=
  848: 	    IF  2drop r> rdrop  EXIT  THEN  THEN
  849: 	rdrop r>
  850:  REPEAT nip nip ;
  851: 
  852: (hashkey)	c_addr u1 -- u2		new	paren_hashkey
  853: u2=0;
  854: while(u1--)
  855:    u2+=(int)toupper(*c_addr++);
  856: :
  857:  0 -rot bounds ?DO  I c@ toupper +  LOOP ;
  858: 
  859: (hashkey1)	c_addr u ubits -- ukey		new	paren_hashkey1
  860: ""ukey is the hash key for the string c_addr u fitting in ubits bits""
  861: /* this hash function rotates the key at every step by rot bits within
  862:    ubits bits and xors it with the character. This function does ok in
  863:    the chi-sqare-test.  Rot should be <=7 (preferably <=5) for
  864:    ASCII strings (larger if ubits is large), and should share no
  865:    divisors with ubits.
  866: */
  867: unsigned rot = ((char []){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})[ubits];
  868: Char *cp = c_addr;
  869: for (ukey=0; cp<c_addr+u; cp++)
  870:     ukey = ((((ukey<<rot) | (ukey>>(ubits-rot))) 
  871: 	     ^ toupper(*cp))
  872: 	    & ((1<<ubits)-1));
  873: :
  874:  dup rot-values + c@ over 1 swap lshift 1- >r
  875:  tuck - 2swap r> 0 2swap bounds
  876:  ?DO  dup 4 pick lshift swap 3 pick rshift or
  877:       I c@ toupper xor
  878:       over and  LOOP
  879:  nip nip nip ;
  880: Create rot-values
  881:   5 c, 0 c, 1 c, 2 c, 3 c,  4 c, 5 c, 5 c, 5 c, 5 c,
  882:   3 c, 5 c, 5 c, 5 c, 5 c,  7 c, 5 c, 5 c, 5 c, 5 c,
  883:   7 c, 5 c, 5 c, 5 c, 5 c,  6 c, 5 c, 5 c, 5 c, 5 c,
  884:   7 c, 5 c, 5 c,
  885: 
  886: (parse-white)	c_addr1 u1 -- c_addr2 u2	new	paren_parse_white
  887: /* use !isgraph instead of isspace? */
  888: Char *endp = c_addr1+u1;
  889: while (c_addr1<endp && isspace(*c_addr1))
  890:   c_addr1++;
  891: if (c_addr1<endp) {
  892:   for (c_addr2 = c_addr1; c_addr1<endp && !isspace(*c_addr1); c_addr1++)
  893:     ;
  894:   u2 = c_addr1-c_addr2;
  895: }
  896: else {
  897:   c_addr2 = c_addr1;
  898:   u2 = 0;
  899: }
  900: :
  901:  BEGIN  dup  WHILE  over c@ bl <=  WHILE  1 /string
  902:  REPEAT  THEN  2dup
  903:  BEGIN  dup  WHILE  over c@ bl >   WHILE  1 /string
  904:  REPEAT  THEN  nip - ;
  905: 
  906: close-file	wfileid -- wior	file	close_file
  907: wior = FILEIO(fclose((FILE *)wfileid)==EOF);
  908: 
  909: open-file	c_addr u ntype -- w2 wior	file	open_file
  910: w2 = (Cell)fopen(cstr(c_addr, u, 1), fileattr[ntype]);
  911: wior =  FILEEXIST(w2 == NULL);
  912: 
  913: create-file	c_addr u ntype -- w2 wior	file	create_file
  914: int	fd;
  915: fd = creat(cstr(c_addr, u, 1), 0644);
  916: if (fd > -1) {
  917:   w2 = (Cell)fdopen(fd, fileattr[ntype]);
  918:   assert(w2 != NULL);
  919:   wior = 0;
  920: } else {
  921:   assert(fd == -1);
  922:   wior = FILEIO(fd);
  923:   w2 = 0;
  924: }
  925: 
  926: delete-file	c_addr u -- wior		file	delete_file
  927: wior = FILEEXIST(unlink(cstr(c_addr, u, 1)));
  928: 
  929: rename-file	c_addr1 u1 c_addr2 u2 -- wior	file-ext	rename_file
  930: char *s1=cstr(c_addr2, u2, 1);
  931: wior = FILEEXIST(rename(cstr(c_addr1, u1, 0), s1));
  932: 
  933: file-position	wfileid -- ud wior	file	file_position
  934: /* !! use tell and lseek? */
  935: ud = ftell((FILE *)wfileid);
  936: wior = 0; /* !! or wior = FLAG(ud<0) */
  937: 
  938: reposition-file	ud wfileid -- wior	file	reposition_file
  939: wior = FILEIO(fseek((FILE *)wfileid, (long)ud, SEEK_SET));
  940: 
  941: file-size	wfileid -- ud wior	file	file_size
  942: struct stat buf;
  943: wior = FILEEXIST(fstat(fileno((FILE *)wfileid), &buf));
  944: ud = buf.st_size;
  945: 
  946: resize-file	ud wfileid -- wior	file	resize_file
  947: wior = FILEIO(ftruncate(fileno((FILE *)wfileid), (int)ud));
  948: 
  949: read-file	c_addr u1 wfileid -- u2 wior	file	read_file
  950: /* !! fread does not guarantee enough */
  951: u2 = fread(c_addr, sizeof(Char), u1, (FILE *)wfileid);
  952: wior = FILEIO(u2<u1 && ferror((FILE *)wfileid));
  953: /* !! who performs clearerr((FILE *)wfileid); ? */
  954: 
  955: read-line	c_addr u1 wfileid -- u2 flag wior	file	read_line
  956: /*
  957: Cell c;
  958: flag=-1;
  959: for(u2=0; u2<u1; u2++)
  960: {
  961:    *c_addr++ = (Char)(c = getc((FILE *)wfileid));
  962:    if(c=='\n') break;
  963:    if(c==EOF)
  964:      {
  965: 	flag=FLAG(u2!=0);
  966: 	break;
  967:      }
  968: }
  969: wior=FILEIO(ferror((FILE *)wfileid));
  970: */
  971: if ((flag=FLAG(!feof((FILE *)wfileid) &&
  972: 	       fgets(c_addr,u1+1,(FILE *)wfileid) != NULL))) {
  973:   wior=FILEIO(ferror((FILE *)wfileid));
  974:   u2 = strlen(c_addr);
  975:   u2-=((u2>0) && (c_addr[u2-1]==NEWLINE));
  976: }
  977: else {
  978:   wior=0;
  979:   u2=0;
  980: }
  981: 
  982: write-file	c_addr u1 wfileid -- wior	file	write_file
  983: /* !! fwrite does not guarantee enough */
  984: {
  985:   int u2 = fwrite(c_addr, sizeof(Char), u1, (FILE *)wfileid);
  986:   wior = FILEIO(u2<u1 && ferror((FILE *)wfileid));
  987: }
  988: 
  989: flush-file	wfileid -- wior		file-ext	flush_file
  990: wior = FILEIO(fflush((FILE *) wfileid));
  991: 
  992: comparisons(f, r1 r2, f_, r1, r2, new, new, float, new)
  993: comparisons(f0, r, f_zero_, r, 0., float, new, float, new)
  994: 
  995: d>f		d -- r		float	d_to_f
  996: r = d;
  997: 
  998: f>d		r -- d		float	f_to_d
  999: /* !! basis 15 is not very specific */
 1000: d = r;
 1001: 
 1002: f!		r f_addr --	float	f_store
 1003: *f_addr = r;
 1004: 
 1005: f@		f_addr -- r	float	f_fetch
 1006: r = *f_addr;
 1007: 
 1008: df@		df_addr -- r	float-ext	d_f_fetch
 1009: #ifdef IEEE_FP
 1010: r = *df_addr;
 1011: #else
 1012: !! df@
 1013: #endif
 1014: 
 1015: df!		r df_addr --	float-ext	d_f_store
 1016: #ifdef IEEE_FP
 1017: *df_addr = r;
 1018: #else
 1019: !! df!
 1020: #endif
 1021: 
 1022: sf@		sf_addr -- r	float-ext	s_f_fetch
 1023: #ifdef IEEE_FP
 1024: r = *sf_addr;
 1025: #else
 1026: !! sf@
 1027: #endif
 1028: 
 1029: sf!		r sf_addr --	float-ext	s_f_store
 1030: #ifdef IEEE_FP
 1031: *sf_addr = r;
 1032: #else
 1033: !! sf!
 1034: #endif
 1035: 
 1036: f+		r1 r2 -- r3	float	f_plus
 1037: r3 = r1+r2;
 1038: 
 1039: f-		r1 r2 -- r3	float	f_minus
 1040: r3 = r1-r2;
 1041: 
 1042: f*		r1 r2 -- r3	float	f_star
 1043: r3 = r1*r2;
 1044: 
 1045: f/		r1 r2 -- r3	float	f_slash
 1046: r3 = r1/r2;
 1047: 
 1048: f**		r1 r2 -- r3	float-ext	f_star_star
 1049: r3 = pow(r1,r2);
 1050: 
 1051: fnegate		r1 -- r2	float
 1052: r2 = - r1;
 1053: 
 1054: fdrop		r --		float
 1055: 
 1056: fdup		r -- r r	float
 1057: 
 1058: fswap		r1 r2 -- r2 r1	float
 1059: 
 1060: fover		r1 r2 -- r1 r2 r1	float
 1061: 
 1062: frot		r1 r2 r3 -- r2 r3 r1	float
 1063: 
 1064: float+		f_addr1 -- f_addr2	float	float_plus
 1065: f_addr2 = f_addr1+1;
 1066: 
 1067: floats		n1 -- n2	float
 1068: n2 = n1*sizeof(Float);
 1069: 
 1070: floor		r1 -- r2	float
 1071: /* !! unclear wording */
 1072: r2 = floor(r1);
 1073: 
 1074: fround		r1 -- r2	float
 1075: /* !! unclear wording */
 1076: #ifdef HAVE_RINT
 1077: r2 = rint(r1);
 1078: #else
 1079: r2 = floor(r1+0.5);
 1080: /* !! This is not quite true to the rounding rules given in the standard */
 1081: #endif
 1082: 
 1083: fmax		r1 r2 -- r3	float
 1084: if (r1<r2)
 1085:   r3 = r2;
 1086: else
 1087:   r3 = r1;
 1088: 
 1089: fmin		r1 r2 -- r3	float
 1090: if (r1<r2)
 1091:   r3 = r1;
 1092: else
 1093:   r3 = r2;
 1094: 
 1095: represent		r c_addr u -- n f1 f2	float
 1096: char *sig;
 1097: int flag;
 1098: int decpt;
 1099: sig=ecvt(r, u, &decpt, &flag);
 1100: n=decpt;
 1101: f1=FLAG(flag!=0);
 1102: f2=FLAG(isdigit(sig[0])!=0);
 1103: memmove(c_addr,sig,u);
 1104: 
 1105: >float	c_addr u -- flag	float	to_float
 1106: /* real signature: c_addr u -- r t / f */
 1107: Float r;
 1108: char *number=cstr(c_addr, u, 1);
 1109: char *endconv;
 1110: while(isspace(number[u-1])) u--;
 1111: switch(number[u-1])
 1112: {
 1113: 	case 'd':
 1114: 	case 'D':
 1115: 	case 'e':
 1116: 	case 'E': u--; break;
 1117: 	default: break;
 1118: }
 1119: number[u]='\0';
 1120: r=strtod(number,&endconv);
 1121: if((flag=FLAG(!(int)*endconv)))
 1122: {
 1123: 	IF_FTOS(fp[0] = FTOS);
 1124: 	fp += -1;
 1125: 	FTOS = r;
 1126: }
 1127: else if(*endconv=='d' || *endconv=='D')
 1128: {
 1129: 	*endconv='E';
 1130: 	r=strtod(number,&endconv);
 1131: 	if((flag=FLAG(!(int)*endconv)))
 1132: 	{
 1133: 		IF_FTOS(fp[0] = FTOS);
 1134: 		fp += -1;
 1135: 		FTOS = r;
 1136: 	}
 1137: }
 1138: 
 1139: fabs		r1 -- r2	float-ext
 1140: r2 = fabs(r1);
 1141: 
 1142: facos		r1 -- r2	float-ext
 1143: r2 = acos(r1);
 1144: 
 1145: fasin		r1 -- r2	float-ext
 1146: r2 = asin(r1);
 1147: 
 1148: fatan		r1 -- r2	float-ext
 1149: r2 = atan(r1);
 1150: 
 1151: fatan2		r1 r2 -- r3	float-ext
 1152: r3 = atan2(r1,r2);
 1153: 
 1154: fcos		r1 -- r2	float-ext
 1155: r2 = cos(r1);
 1156: 
 1157: fexp		r1 -- r2	float-ext
 1158: r2 = exp(r1);
 1159: 
 1160: fexpm1		r1 -- r2	float-ext
 1161: r2 =
 1162: #ifdef HAS_EXPM1
 1163: 	expm1(r1);
 1164: #else
 1165: 	exp(r1)-1;
 1166: #endif
 1167: 
 1168: fln		r1 -- r2	float-ext
 1169: r2 = log(r1);
 1170: 
 1171: flnp1		r1 -- r2	float-ext
 1172: r2 =
 1173: #ifdef HAS_LOG1P
 1174: 	log1p(r1);
 1175: #else
 1176: log(r1+1);
 1177: #endif
 1178: 
 1179: flog		r1 -- r2	float-ext
 1180: r2 = log10(r1);
 1181: 
 1182: fsin		r1 -- r2	float-ext
 1183: r2 = sin(r1);
 1184: 
 1185: fsincos		r1 -- r2 r3	float-ext
 1186: r2 = sin(r1);
 1187: r3 = cos(r1);
 1188: 
 1189: fsqrt		r1 -- r2	float-ext
 1190: r2 = sqrt(r1);
 1191: 
 1192: ftan		r1 -- r2	float-ext
 1193: r2 = tan(r1);
 1194: 
 1195: \ The following words access machine/OS/installation-dependent ANSI
 1196: \   figForth internals
 1197: \ !! how about environmental queries DIRECT-THREADED,
 1198: \   INDIRECT-THREADED, TOS-CACHED, FTOS-CACHED, CODEFIELD-DOES */
 1199: 
 1200: >body		xt -- a_addr	core	to_body
 1201: a_addr = PFA(xt);
 1202: 
 1203: >code-address		xt -- c_addr		new	to_code_address
 1204: ""c_addr is the code address of the word xt""
 1205: /* !! This behaves installation-dependently for DOES-words */
 1206: c_addr = CODE_ADDRESS(xt);
 1207: 
 1208: >does-code	xt -- a_addr		new	to_does_code
 1209: ""If xt ist the execution token of a defining-word-defined word,
 1210: a_addr is the start of the Forth code after the DOES>; Otherwise the
 1211: behaviour is uundefined""
 1212: /* !! there is currently no way to determine whether a word is
 1213: defining-word-defined */
 1214: a_addr = (Cell *)DOES_CODE(xt);
 1215: 
 1216: code-address!		n xt --	new	code_address_store
 1217: ""Creates a code field with code address c_addr at xt""
 1218: MAKE_CF(xt, symbols[CF(n)]);
 1219: CACHE_FLUSH(xt,PFA(0));
 1220: 
 1221: does-code!	a_addr xt --		new	does_code_store
 1222: ""creates a code field at xt for a defining-word-defined word; a_addr
 1223: is the start of the Forth code after DOES>""
 1224: MAKE_DOES_CF(xt, a_addr);
 1225: CACHE_FLUSH(xt,PFA(0));
 1226: 
 1227: does-handler!	a_addr --	new	does_jump_store
 1228: ""creates a DOES>-handler at address a_addr. a_addr usually points
 1229: just behind a DOES>.""
 1230: MAKE_DOES_HANDLER(a_addr);
 1231: CACHE_FLUSH(a_addr,DOES_HANDLER_SIZE);
 1232: 
 1233: /does-handler	-- n	new	slash_does_handler
 1234: ""the size of a does-handler (includes possible padding)""
 1235: /* !! a constant or environmental query might be better */
 1236: n = DOES_HANDLER_SIZE;
 1237: 
 1238: toupper	c1 -- c2	new
 1239: c2 = toupper(c1);
 1240: 
 1241: \ local variable implementation primitives
 1242: @local#		-- w	new	fetch_local_number
 1243: w = *(Cell *)(lp+(int)(*ip++));
 1244: 
 1245: @local0	-- w	new	fetch_local_zero
 1246: w = *(Cell *)(lp+0*sizeof(Cell));
 1247: 
 1248: @local1	-- w	new	fetch_local_four
 1249: w = *(Cell *)(lp+1*sizeof(Cell));
 1250: 
 1251: @local2	-- w	new	fetch_local_eight
 1252: w = *(Cell *)(lp+2*sizeof(Cell));
 1253: 
 1254: @local3	-- w	new	fetch_local_twelve
 1255: w = *(Cell *)(lp+3*sizeof(Cell));
 1256: 
 1257: f@local#	-- r	new	f_fetch_local_number
 1258: r = *(Float *)(lp+(int)(*ip++));
 1259: 
 1260: f@local0	-- r	new	f_fetch_local_zero
 1261: r = *(Float *)(lp+0*sizeof(Float));
 1262: 
 1263: f@local1	-- r	new	f_fetch_local_eight
 1264: r = *(Float *)(lp+1*sizeof(Float));
 1265: 
 1266: laddr#		-- c_addr	new	laddr_number
 1267: /* this can also be used to implement lp@ */
 1268: c_addr = (Char *)(lp+(int)(*ip++));
 1269: 
 1270: lp+!#	--	new	lp_plus_store_number
 1271: ""used with negative immediate values it allocates memory on the
 1272: local stack, a positive immediate argument drops memory from the local
 1273: stack""
 1274: lp += (int)(*ip++);
 1275: 
 1276: lp-	--	new	minus_four_lp_plus_store
 1277: lp += -sizeof(Cell);
 1278: 
 1279: lp+	--	new	eight_lp_plus_store
 1280: lp += sizeof(Float);
 1281: 
 1282: lp+2	--	new	sixteen_lp_plus_store
 1283: lp += 2*sizeof(Float);
 1284: 
 1285: lp!	c_addr --	new	lp_store
 1286: lp = (Address)c_addr;
 1287: 
 1288: >l	w --	new	to_l
 1289: lp -= sizeof(Cell);
 1290: *(Cell *)lp = w;
 1291: 
 1292: f>l	r --	new	f_to_l
 1293: lp -= sizeof(Float);
 1294: *(Float *)lp = r;
 1295: 
 1296: up!	a_addr --	new	up_store
 1297: up0=up=(char *)a_addr;

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>