File:  [gforth] / gforth / Attic / primitives
Revision 1.34: download - view: text, annotated - select for diffs
Thu Feb 9 17:49:58 1995 UTC (29 years, 2 months ago) by anton
Branches: MAIN
CVS tags: HEAD
fixed blocks.fb creation bug by making result of create-file readable.

    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 += (Cell)(ip[1]);
  100: goto branch;
  101: 
  102: branch	--		fig
  103: branch:
  104: ip = (Xt *)(((Cell)ip)+(Cell)*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	ip = (Xt *)(((Cell)ip)+(Cell)*ip); NEXT;
  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: Cell index = *rp+1;
  136: Cell 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: Cell 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: Cell olddiff = index-rp[1];
  147: #ifndef 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 ((((Cell)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: Cell index = *rp;
  170: Cell diff = index-rp[1];
  171: Cell 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+=(Cell)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: Cell	fd;
  915: fd = open(cstr(c_addr, u, 1), O_CREAT|O_RDWR|O_TRUNC, 0666);
  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), (Cell)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:   Cell 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: ""@i{r3} is @i{r1} raised to the @i{r2}th power""
 1050: r3 = pow(r1,r2);
 1051: 
 1052: fnegate		r1 -- r2	float
 1053: r2 = - r1;
 1054: 
 1055: fdrop		r --		float
 1056: 
 1057: fdup		r -- r r	float
 1058: 
 1059: fswap		r1 r2 -- r2 r1	float
 1060: 
 1061: fover		r1 r2 -- r1 r2 r1	float
 1062: 
 1063: frot		r1 r2 r3 -- r2 r3 r1	float
 1064: 
 1065: float+		f_addr1 -- f_addr2	float	float_plus
 1066: f_addr2 = f_addr1+1;
 1067: 
 1068: floats		n1 -- n2	float
 1069: n2 = n1*sizeof(Float);
 1070: 
 1071: floor		r1 -- r2	float
 1072: ""round towards the next smaller integral value, i.e., round toward negative infinity""
 1073: /* !! unclear wording */
 1074: r2 = floor(r1);
 1075: 
 1076: fround		r1 -- r2	float
 1077: ""round to the nearest integral value""
 1078: /* !! unclear wording */
 1079: #ifdef HAVE_RINT
 1080: r2 = rint(r1);
 1081: #else
 1082: r2 = floor(r1+0.5);
 1083: /* !! This is not quite true to the rounding rules given in the standard */
 1084: #endif
 1085: 
 1086: fmax		r1 r2 -- r3	float
 1087: if (r1<r2)
 1088:   r3 = r2;
 1089: else
 1090:   r3 = r1;
 1091: 
 1092: fmin		r1 r2 -- r3	float
 1093: if (r1<r2)
 1094:   r3 = r1;
 1095: else
 1096:   r3 = r2;
 1097: 
 1098: represent		r c_addr u -- n f1 f2	float
 1099: char *sig;
 1100: Cell flag;
 1101: Cell decpt;
 1102: sig=ecvt(r, u, &decpt, &flag);
 1103: n=(r==0 ? 1 : decpt);
 1104: f1=FLAG(flag!=0);
 1105: f2=FLAG(isdigit(sig[0])!=0);
 1106: memmove(c_addr,sig,u);
 1107: 
 1108: >float	c_addr u -- flag	float	to_float
 1109: /* real signature: c_addr u -- r t / f */
 1110: Float r;
 1111: char *number=cstr(c_addr, u, 1);
 1112: char *endconv;
 1113: while(isspace(number[--u]) && u>0);
 1114: switch(number[u])
 1115: {
 1116:    case 'd':
 1117:    case 'D':
 1118:    case 'e':
 1119:    case 'E':  break;
 1120:    default :  u++; break;
 1121: }
 1122: number[u]='\0';
 1123: r=strtod(number,&endconv);
 1124: if((flag=FLAG(!(Cell)*endconv)))
 1125: {
 1126:    IF_FTOS(fp[0] = FTOS);
 1127:    fp += -1;
 1128:    FTOS = r;
 1129: }
 1130: else if(*endconv=='d' || *endconv=='D')
 1131: {
 1132:    *endconv='E';
 1133:    r=strtod(number,&endconv);
 1134:    if((flag=FLAG(!(Cell)*endconv)))
 1135:      {
 1136: 	IF_FTOS(fp[0] = FTOS);
 1137: 	fp += -1;
 1138: 	FTOS = r;
 1139:      }
 1140: }
 1141: 
 1142: fabs		r1 -- r2	float-ext
 1143: r2 = fabs(r1);
 1144: 
 1145: facos		r1 -- r2	float-ext
 1146: r2 = acos(r1);
 1147: 
 1148: fasin		r1 -- r2	float-ext
 1149: r2 = asin(r1);
 1150: 
 1151: fatan		r1 -- r2	float-ext
 1152: r2 = atan(r1);
 1153: 
 1154: fatan2		r1 r2 -- r3	float-ext
 1155: ""@i{r1/r2}=tan@i{r3}. The standard does not require, but probably
 1156: intends this to be the inverse of @code{fsincos}. In gforth it is.""
 1157: r3 = atan2(r1,r2);
 1158: 
 1159: fcos		r1 -- r2	float-ext
 1160: r2 = cos(r1);
 1161: 
 1162: fexp		r1 -- r2	float-ext
 1163: r2 = exp(r1);
 1164: 
 1165: fexpm1		r1 -- r2	float-ext
 1166: ""@i{r2}=@i{e}**@i{r1}@minus{}1""
 1167: #ifdef HAVE_EXPM1
 1168: extern double expm1(double);
 1169: r2 = expm1(r1);
 1170: #else
 1171: r2 = exp(r1)-1.;
 1172: #endif
 1173: 
 1174: fln		r1 -- r2	float-ext
 1175: r2 = log(r1);
 1176: 
 1177: flnp1		r1 -- r2	float-ext
 1178: ""@i{r2}=ln(@i{r1}+1)""
 1179: #ifdef HAVE_LOG1P
 1180: extern double log1p(double);
 1181: r2 = log1p(r1);
 1182: #else
 1183: r2 = log(r1+1.);
 1184: #endif
 1185: 
 1186: flog		r1 -- r2	float-ext
 1187: ""the decimal logarithm""
 1188: r2 = log10(r1);
 1189: 
 1190: falog		r1 -- r2	float-ext
 1191: ""@i{r2}=10**@i{r1}""
 1192: #ifdef HAVE_POW10
 1193: extern double pow10(double);
 1194: r2 = pow10(r1);
 1195: #else
 1196: #ifndef M_LN10
 1197: #define M_LN10      2.30258509299404568402
 1198: #endif
 1199: r2 = exp(r1*M_LN10);
 1200: #endif
 1201: 
 1202: fsin		r1 -- r2	float-ext
 1203: r2 = sin(r1);
 1204: 
 1205: fsincos		r1 -- r2 r3	float-ext
 1206: ""@i{r2}=sin(@i{r1}), @i{r3}=cos(@i{r1})""
 1207: r2 = sin(r1);
 1208: r3 = cos(r1);
 1209: 
 1210: fsqrt		r1 -- r2	float-ext
 1211: r2 = sqrt(r1);
 1212: 
 1213: ftan		r1 -- r2	float-ext
 1214: r2 = tan(r1);
 1215: :
 1216:  fsincos f/ ;
 1217: 
 1218: fsinh		r1 -- r2	float-ext
 1219: r2 = sinh(r1);
 1220: :
 1221:  fexpm1 fdup fdup 1. d>f f+ f/ f+ f2/ ;
 1222: 
 1223: fcosh		r1 -- r2	float-ext
 1224: r2 = cosh(r1);
 1225: :
 1226:  fexp fdup 1/f f+ f2/ ;
 1227: 
 1228: ftanh		r1 -- r2	float-ext
 1229: r2 = tanh(r1);
 1230: :
 1231:  f2* fexpm1 fdup 2. d>f f+ f/ ;
 1232: 
 1233: fasinh		r1 -- r2	float-ext
 1234: r2 = asinh(r1);
 1235: :
 1236:  fdup fdup f* 1. d>f f+ fsqrt f/ fatanh ;
 1237: 
 1238: facosh		r1 -- r2	float-ext
 1239: r2 = acosh(r1);
 1240: :
 1241:  fdup fdup f* 1. d>f f- fsqrt f+ fln ;
 1242: 
 1243: fatanh		r1 -- r2	float-ext
 1244: r2 = atanh(r1);
 1245: :
 1246:  fdup f0< >r fabs 1. d>f fover f- f/  f2* flnp1 f2/
 1247:  r> IF  fnegate  THEN ;
 1248: 
 1249: \ The following words access machine/OS/installation-dependent ANSI
 1250: \   figForth internals
 1251: \ !! how about environmental queries DIRECT-THREADED,
 1252: \   INDIRECT-THREADED, TOS-CACHED, FTOS-CACHED, CODEFIELD-DOES */
 1253: 
 1254: >body		xt -- a_addr	core	to_body
 1255: a_addr = PFA(xt);
 1256: 
 1257: >code-address		xt -- c_addr		new	to_code_address
 1258: ""c_addr is the code address of the word xt""
 1259: /* !! This behaves installation-dependently for DOES-words */
 1260: c_addr = CODE_ADDRESS(xt);
 1261: 
 1262: >does-code	xt -- a_addr		new	to_does_code
 1263: ""If xt ist the execution token of a defining-word-defined word,
 1264: a_addr is the start of the Forth code after the DOES>; Otherwise the
 1265: behaviour is undefined""
 1266: /* !! there is currently no way to determine whether a word is
 1267: defining-word-defined */
 1268: a_addr = (Cell *)DOES_CODE(xt);
 1269: 
 1270: code-address!		n xt --	new	code_address_store
 1271: ""Creates a code field with code address c_addr at xt""
 1272: MAKE_CF(xt, symbols[CF(n)]);
 1273: CACHE_FLUSH(xt,PFA(0));
 1274: 
 1275: does-code!	a_addr xt --		new	does_code_store
 1276: ""creates a code field at xt for a defining-word-defined word; a_addr
 1277: is the start of the Forth code after DOES>""
 1278: MAKE_DOES_CF(xt, a_addr);
 1279: CACHE_FLUSH(xt,PFA(0));
 1280: 
 1281: does-handler!	a_addr --	new	does_jump_store
 1282: ""creates a DOES>-handler at address a_addr. a_addr usually points
 1283: just behind a DOES>.""
 1284: MAKE_DOES_HANDLER(a_addr);
 1285: CACHE_FLUSH(a_addr,DOES_HANDLER_SIZE);
 1286: 
 1287: /does-handler	-- n	new	slash_does_handler
 1288: ""the size of a does-handler (includes possible padding)""
 1289: /* !! a constant or environmental query might be better */
 1290: n = DOES_HANDLER_SIZE;
 1291: 
 1292: toupper	c1 -- c2	new
 1293: c2 = toupper(c1);
 1294: 
 1295: \ local variable implementation primitives
 1296: @local#		-- w	new	fetch_local_number
 1297: w = *(Cell *)(lp+(Cell)(*ip++));
 1298: 
 1299: @local0	-- w	new	fetch_local_zero
 1300: w = *(Cell *)(lp+0*sizeof(Cell));
 1301: 
 1302: @local1	-- w	new	fetch_local_four
 1303: w = *(Cell *)(lp+1*sizeof(Cell));
 1304: 
 1305: @local2	-- w	new	fetch_local_eight
 1306: w = *(Cell *)(lp+2*sizeof(Cell));
 1307: 
 1308: @local3	-- w	new	fetch_local_twelve
 1309: w = *(Cell *)(lp+3*sizeof(Cell));
 1310: 
 1311: f@local#	-- r	new	f_fetch_local_number
 1312: r = *(Float *)(lp+(Cell)(*ip++));
 1313: 
 1314: f@local0	-- r	new	f_fetch_local_zero
 1315: r = *(Float *)(lp+0*sizeof(Float));
 1316: 
 1317: f@local1	-- r	new	f_fetch_local_eight
 1318: r = *(Float *)(lp+1*sizeof(Float));
 1319: 
 1320: laddr#		-- c_addr	new	laddr_number
 1321: /* this can also be used to implement lp@ */
 1322: c_addr = (Char *)(lp+(Cell)(*ip++));
 1323: 
 1324: lp+!#	--	new	lp_plus_store_number
 1325: ""used with negative immediate values it allocates memory on the
 1326: local stack, a positive immediate argument drops memory from the local
 1327: stack""
 1328: lp += (Cell)(*ip++);
 1329: 
 1330: lp-	--	new	minus_four_lp_plus_store
 1331: lp += -sizeof(Cell);
 1332: 
 1333: lp+	--	new	eight_lp_plus_store
 1334: lp += sizeof(Float);
 1335: 
 1336: lp+2	--	new	sixteen_lp_plus_store
 1337: lp += 2*sizeof(Float);
 1338: 
 1339: lp!	c_addr --	new	lp_store
 1340: lp = (Address)c_addr;
 1341: 
 1342: >l	w --	new	to_l
 1343: lp -= sizeof(Cell);
 1344: *(Cell *)lp = w;
 1345: 
 1346: f>l	r --	new	f_to_l
 1347: lp -= sizeof(Float);
 1348: *(Float *)lp = r;
 1349: 
 1350: up!	a_addr --	new	up_store
 1351: up0=up=(char *)a_addr;

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