sound: Do not access cv_waiters
[freebsd/src.git] / stand / ficl / words.c
blob8d06bedf8375e4493ec19f9fd6c1d6319e7d04a7
1 /*******************************************************************
2 ** w o r d s . c
3 ** Forth Inspired Command Language
4 ** ANS Forth CORE word-set written in C
5 ** Author: John Sadler (john_sadler@alum.mit.edu)
6 ** Created: 19 July 1997
7 ** $Id: words.c,v 1.17 2001/12/05 07:21:34 jsadler Exp $
8 *******************************************************************/
9 /*
10 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
11 ** All rights reserved.
13 ** Get the latest Ficl release at http://ficl.sourceforge.net
15 ** I am interested in hearing from anyone who uses ficl. If you have
16 ** a problem, a success story, a defect, an enhancement request, or
17 ** if you would like to contribute to the ficl release, please
18 ** contact me by email at the address above.
20 ** L I C E N S E and D I S C L A I M E R
21 **
22 ** Redistribution and use in source and binary forms, with or without
23 ** modification, are permitted provided that the following conditions
24 ** are met:
25 ** 1. Redistributions of source code must retain the above copyright
26 ** notice, this list of conditions and the following disclaimer.
27 ** 2. Redistributions in binary form must reproduce the above copyright
28 ** notice, this list of conditions and the following disclaimer in the
29 ** documentation and/or other materials provided with the distribution.
31 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 ** SUCH DAMAGE.
45 #ifdef TESTMAIN
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <fcntl.h>
50 #else
51 #include <stand.h>
52 #endif
53 #include <string.h>
54 #include "ficl.h"
55 #include "math64.h"
57 static void colonParen(FICL_VM *pVM);
58 static void literalIm(FICL_VM *pVM);
59 static int ficlParseWord(FICL_VM *pVM, STRINGINFO si);
62 ** Control structure building words use these
63 ** strings' addresses as markers on the stack to
64 ** check for structure completion.
66 static char doTag[] = "do";
67 static char colonTag[] = "colon";
68 static char leaveTag[] = "leave";
70 static char destTag[] = "target";
71 static char origTag[] = "origin";
73 static char caseTag[] = "case";
74 static char ofTag[] = "of";
75 static char fallthroughTag[] = "fallthrough";
77 #if FICL_WANT_LOCALS
78 static void doLocalIm(FICL_VM *pVM);
79 static void do2LocalIm(FICL_VM *pVM);
80 #endif
84 ** C O N T R O L S T R U C T U R E B U I L D E R S
86 ** Push current dict location for later branch resolution.
87 ** The location may be either a branch target or a patch address...
89 static void markBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
91 PUSHPTR(dp->here);
92 PUSHPTR(tag);
93 return;
96 static void markControlTag(FICL_VM *pVM, char *tag)
98 PUSHPTR(tag);
99 return;
102 static void matchControlTag(FICL_VM *pVM, char *tag)
104 char *cp;
105 #if FICL_ROBUST > 1
106 vmCheckStack(pVM, 1, 0);
107 #endif
108 cp = (char *)stackPopPtr(pVM->pStack);
110 ** Changed the code below to compare the pointers first (by popular demand)
112 if ( (cp != tag) && strcmp(cp, tag) )
114 vmThrowErr(pVM, "Error -- unmatched control structure \"%s\"", tag);
117 return;
121 ** Expect a branch target address on the param stack,
122 ** compile a literal offset from the current dict location
123 ** to the target address
125 static void resolveBackBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
127 FICL_INT offset;
128 CELL *patchAddr;
130 matchControlTag(pVM, tag);
132 #if FICL_ROBUST > 1
133 vmCheckStack(pVM, 1, 0);
134 #endif
135 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
136 offset = patchAddr - dp->here;
137 dictAppendCell(dp, LVALUEtoCELL(offset));
139 return;
144 ** Expect a branch patch address on the param stack,
145 ** compile a literal offset from the patch location
146 ** to the current dict location
148 static void resolveForwardBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
150 FICL_INT offset;
151 CELL *patchAddr;
153 matchControlTag(pVM, tag);
155 #if FICL_ROBUST > 1
156 vmCheckStack(pVM, 1, 0);
157 #endif
158 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
159 offset = dp->here - patchAddr;
160 *patchAddr = LVALUEtoCELL(offset);
162 return;
166 ** Match the tag to the top of the stack. If success,
167 ** sopy "here" address into the cell whose address is next
168 ** on the stack. Used by do..leave..loop.
170 static void resolveAbsBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
172 CELL *patchAddr;
173 char *cp;
175 #if FICL_ROBUST > 1
176 vmCheckStack(pVM, 2, 0);
177 #endif
178 cp = stackPopPtr(pVM->pStack);
180 ** Changed the comparison below to compare the pointers first (by popular demand)
182 if ((cp != tag) && strcmp(cp, tag))
184 vmTextOut(pVM, "Warning -- Unmatched control word: ", 0);
185 vmTextOut(pVM, tag, 1);
188 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
189 *patchAddr = LVALUEtoCELL(dp->here);
191 return;
195 /**************************************************************************
196 f i c l P a r s e N u m b e r
197 ** Attempts to convert the NULL terminated string in the VM's pad to
198 ** a number using the VM's current base. If successful, pushes the number
199 ** onto the param stack and returns TRUE. Otherwise, returns FALSE.
200 ** (jws 8/01) Trailing decimal point causes a zero cell to be pushed. (See
201 ** the standard for DOUBLE wordset.
202 **************************************************************************/
204 int ficlParseNumber(FICL_VM *pVM, STRINGINFO si)
206 FICL_INT accum = 0;
207 char isNeg = FALSE;
208 char hasDP = FALSE;
209 unsigned base = pVM->base;
210 char *cp = SI_PTR(si);
211 FICL_COUNT count= (FICL_COUNT)SI_COUNT(si);
212 unsigned ch;
213 unsigned digit;
215 if (count > 1)
217 switch (*cp)
219 case '-':
220 cp++;
221 count--;
222 isNeg = TRUE;
223 break;
224 case '+':
225 cp++;
226 count--;
227 isNeg = FALSE;
228 break;
229 default:
230 break;
234 if ((count > 0) && (cp[count-1] == '.')) /* detect & remove trailing decimal */
236 hasDP = TRUE;
237 count--;
240 if (count == 0) /* detect "+", "-", ".", "+." etc */
241 return FALSE;
243 while ((count--) && ((ch = *cp++) != '\0'))
245 if (!isalnum(ch))
246 return FALSE;
248 digit = ch - '0';
250 if (digit > 9)
251 digit = tolower(ch) - 'a' + 10;
253 if (digit >= base)
254 return FALSE;
256 accum = accum * base + digit;
259 if (hasDP) /* simple (required) DOUBLE support */
260 PUSHINT(0);
262 if (isNeg)
263 accum = -accum;
265 PUSHINT(accum);
266 if (pVM->state == COMPILE)
267 literalIm(pVM);
269 return TRUE;
273 /**************************************************************************
274 a d d & f r i e n d s
276 **************************************************************************/
278 static void add(FICL_VM *pVM)
280 FICL_INT i;
281 #if FICL_ROBUST > 1
282 vmCheckStack(pVM, 2, 1);
283 #endif
284 i = stackPopINT(pVM->pStack);
285 i += stackGetTop(pVM->pStack).i;
286 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
287 return;
290 static void sub(FICL_VM *pVM)
292 FICL_INT i;
293 #if FICL_ROBUST > 1
294 vmCheckStack(pVM, 2, 1);
295 #endif
296 i = stackPopINT(pVM->pStack);
297 i = stackGetTop(pVM->pStack).i - i;
298 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
299 return;
302 static void mul(FICL_VM *pVM)
304 FICL_INT i;
305 #if FICL_ROBUST > 1
306 vmCheckStack(pVM, 2, 1);
307 #endif
308 i = stackPopINT(pVM->pStack);
309 i *= stackGetTop(pVM->pStack).i;
310 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
311 return;
314 static void negate(FICL_VM *pVM)
316 FICL_INT i;
317 #if FICL_ROBUST > 1
318 vmCheckStack(pVM, 1, 1);
319 #endif
320 i = -stackPopINT(pVM->pStack);
321 PUSHINT(i);
322 return;
325 static void ficlDiv(FICL_VM *pVM)
327 FICL_INT i;
328 #if FICL_ROBUST > 1
329 vmCheckStack(pVM, 2, 1);
330 #endif
331 i = stackPopINT(pVM->pStack);
332 i = stackGetTop(pVM->pStack).i / i;
333 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
334 return;
338 ** slash-mod CORE ( n1 n2 -- n3 n4 )
339 ** Divide n1 by n2, giving the single-cell remainder n3 and the single-cell
340 ** quotient n4. An ambiguous condition exists if n2 is zero. If n1 and n2
341 ** differ in sign, the implementation-defined result returned will be the
342 ** same as that returned by either the phrase
343 ** >R S>D R> FM/MOD or the phrase >R S>D R> SM/REM .
344 ** NOTE: Ficl complies with the second phrase (symmetric division)
346 static void slashMod(FICL_VM *pVM)
348 DPINT n1;
349 FICL_INT n2;
350 INTQR qr;
352 #if FICL_ROBUST > 1
353 vmCheckStack(pVM, 2, 2);
354 #endif
355 n2 = stackPopINT(pVM->pStack);
356 n1.lo = stackPopINT(pVM->pStack);
357 i64Extend(n1);
359 qr = m64SymmetricDivI(n1, n2);
360 PUSHINT(qr.rem);
361 PUSHINT(qr.quot);
362 return;
365 static void onePlus(FICL_VM *pVM)
367 FICL_INT i;
368 #if FICL_ROBUST > 1
369 vmCheckStack(pVM, 1, 1);
370 #endif
371 i = stackGetTop(pVM->pStack).i;
372 i += 1;
373 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
374 return;
377 static void oneMinus(FICL_VM *pVM)
379 FICL_INT i;
380 #if FICL_ROBUST > 1
381 vmCheckStack(pVM, 1, 1);
382 #endif
383 i = stackGetTop(pVM->pStack).i;
384 i -= 1;
385 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
386 return;
389 static void twoMul(FICL_VM *pVM)
391 FICL_INT i;
392 #if FICL_ROBUST > 1
393 vmCheckStack(pVM, 1, 1);
394 #endif
395 i = stackGetTop(pVM->pStack).i;
396 i *= 2;
397 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
398 return;
401 static void twoDiv(FICL_VM *pVM)
403 FICL_INT i;
404 #if FICL_ROBUST > 1
405 vmCheckStack(pVM, 1, 1);
406 #endif
407 i = stackGetTop(pVM->pStack).i;
408 i >>= 1;
409 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
410 return;
413 static void mulDiv(FICL_VM *pVM)
415 FICL_INT x, y, z;
416 DPINT prod;
417 #if FICL_ROBUST > 1
418 vmCheckStack(pVM, 3, 1);
419 #endif
420 z = stackPopINT(pVM->pStack);
421 y = stackPopINT(pVM->pStack);
422 x = stackPopINT(pVM->pStack);
424 prod = m64MulI(x,y);
425 x = m64SymmetricDivI(prod, z).quot;
427 PUSHINT(x);
428 return;
432 static void mulDivRem(FICL_VM *pVM)
434 FICL_INT x, y, z;
435 DPINT prod;
436 INTQR qr;
437 #if FICL_ROBUST > 1
438 vmCheckStack(pVM, 3, 2);
439 #endif
440 z = stackPopINT(pVM->pStack);
441 y = stackPopINT(pVM->pStack);
442 x = stackPopINT(pVM->pStack);
444 prod = m64MulI(x,y);
445 qr = m64SymmetricDivI(prod, z);
447 PUSHINT(qr.rem);
448 PUSHINT(qr.quot);
449 return;
453 /**************************************************************************
454 c o l o n d e f i n i t i o n s
455 ** Code to begin compiling a colon definition
456 ** This function sets the state to COMPILE, then creates a
457 ** new word whose name is the next word in the input stream
458 ** and whose code is colonParen.
459 **************************************************************************/
461 static void colon(FICL_VM *pVM)
463 FICL_DICT *dp = vmGetDict(pVM);
464 STRINGINFO si = vmGetWord(pVM);
466 dictCheckThreshold(dp);
468 pVM->state = COMPILE;
469 markControlTag(pVM, colonTag);
470 dictAppendWord2(dp, si, colonParen, FW_DEFAULT | FW_SMUDGE);
471 #if FICL_WANT_LOCALS
472 pVM->pSys->nLocals = 0;
473 #endif
474 return;
478 /**************************************************************************
479 c o l o n P a r e n
480 ** This is the code that executes a colon definition. It assumes that the
481 ** virtual machine is running a "next" loop (See the vm.c
482 ** for its implementation of member function vmExecute()). The colon
483 ** code simply copies the address of the first word in the list of words
484 ** to interpret into IP after saving its old value. When we return to the
485 ** "next" loop, the virtual machine will call the code for each word in
486 ** turn.
488 **************************************************************************/
490 static void colonParen(FICL_VM *pVM)
492 IPTYPE tempIP = (IPTYPE) (pVM->runningWord->param);
493 vmPushIP(pVM, tempIP);
495 return;
499 /**************************************************************************
500 s e m i c o l o n C o I m
502 ** IMMEDIATE code for ";". This function sets the state to INTERPRET and
503 ** terminates a word under compilation by appending code for "(;)" to
504 ** the definition. TO DO: checks for leftover branch target tags on the
505 ** return stack and complains if any are found.
506 **************************************************************************/
507 static void semiParen(FICL_VM *pVM)
509 vmPopIP(pVM);
510 return;
514 static void semicolonCoIm(FICL_VM *pVM)
516 FICL_DICT *dp = vmGetDict(pVM);
518 assert(pVM->pSys->pSemiParen);
519 matchControlTag(pVM, colonTag);
521 #if FICL_WANT_LOCALS
522 assert(pVM->pSys->pUnLinkParen);
523 if (pVM->pSys->nLocals > 0)
525 FICL_DICT *pLoc = ficlGetLoc(pVM->pSys);
526 dictEmpty(pLoc, pLoc->pForthWords->size);
527 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pUnLinkParen));
529 pVM->pSys->nLocals = 0;
530 #endif
532 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pSemiParen));
533 pVM->state = INTERPRET;
534 dictUnsmudge(dp);
535 return;
539 /**************************************************************************
540 e x i t
541 ** CORE
542 ** This function simply pops the previous instruction
543 ** pointer and returns to the "next" loop. Used for exiting from within
544 ** a definition. Note that exitParen is identical to semiParen - they
545 ** are in two different functions so that "see" can correctly identify
546 ** the end of a colon definition, even if it uses "exit".
547 **************************************************************************/
548 static void exitParen(FICL_VM *pVM)
550 vmPopIP(pVM);
551 return;
554 static void exitCoIm(FICL_VM *pVM)
556 FICL_DICT *dp = vmGetDict(pVM);
557 assert(pVM->pSys->pExitParen);
558 IGNORE(pVM);
560 #if FICL_WANT_LOCALS
561 if (pVM->pSys->nLocals > 0)
563 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pUnLinkParen));
565 #endif
566 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pExitParen));
567 return;
571 /**************************************************************************
572 c o n s t a n t P a r e n
573 ** This is the run-time code for "constant". It simply returns the
574 ** contents of its word's first data cell.
576 **************************************************************************/
578 void constantParen(FICL_VM *pVM)
580 FICL_WORD *pFW = pVM->runningWord;
581 #if FICL_ROBUST > 1
582 vmCheckStack(pVM, 0, 1);
583 #endif
584 stackPush(pVM->pStack, pFW->param[0]);
585 return;
588 void twoConstParen(FICL_VM *pVM)
590 FICL_WORD *pFW = pVM->runningWord;
591 #if FICL_ROBUST > 1
592 vmCheckStack(pVM, 0, 2);
593 #endif
594 stackPush(pVM->pStack, pFW->param[0]); /* lo */
595 stackPush(pVM->pStack, pFW->param[1]); /* hi */
596 return;
600 /**************************************************************************
601 c o n s t a n t
602 ** IMMEDIATE
603 ** Compiles a constant into the dictionary. Constants return their
604 ** value when invoked. Expects a value on top of the parm stack.
605 **************************************************************************/
607 static void constant(FICL_VM *pVM)
609 FICL_DICT *dp = vmGetDict(pVM);
610 STRINGINFO si = vmGetWord(pVM);
612 #if FICL_ROBUST > 1
613 vmCheckStack(pVM, 1, 0);
614 #endif
615 dictAppendWord2(dp, si, constantParen, FW_DEFAULT);
616 dictAppendCell(dp, stackPop(pVM->pStack));
617 return;
621 static void twoConstant(FICL_VM *pVM)
623 FICL_DICT *dp = vmGetDict(pVM);
624 STRINGINFO si = vmGetWord(pVM);
625 CELL c;
627 #if FICL_ROBUST > 1
628 vmCheckStack(pVM, 2, 0);
629 #endif
630 c = stackPop(pVM->pStack);
631 dictAppendWord2(dp, si, twoConstParen, FW_DEFAULT);
632 dictAppendCell(dp, stackPop(pVM->pStack));
633 dictAppendCell(dp, c);
634 return;
638 /**************************************************************************
639 d i s p l a y C e l l
640 ** Drop and print the contents of the cell at the top of the param
641 ** stack
642 **************************************************************************/
644 static void displayCell(FICL_VM *pVM)
646 CELL c;
647 #if FICL_ROBUST > 1
648 vmCheckStack(pVM, 1, 0);
649 #endif
650 c = stackPop(pVM->pStack);
651 ltoa((c).i, pVM->pad, pVM->base);
652 strcat(pVM->pad, " ");
653 vmTextOut(pVM, pVM->pad, 0);
654 return;
657 static void uDot(FICL_VM *pVM)
659 FICL_UNS u;
660 #if FICL_ROBUST > 1
661 vmCheckStack(pVM, 1, 0);
662 #endif
663 u = stackPopUNS(pVM->pStack);
664 ultoa(u, pVM->pad, pVM->base);
665 strcat(pVM->pad, " ");
666 vmTextOut(pVM, pVM->pad, 0);
667 return;
671 static void hexDot(FICL_VM *pVM)
673 FICL_UNS u;
674 #if FICL_ROBUST > 1
675 vmCheckStack(pVM, 1, 0);
676 #endif
677 u = stackPopUNS(pVM->pStack);
678 ultoa(u, pVM->pad, 16);
679 strcat(pVM->pad, " ");
680 vmTextOut(pVM, pVM->pad, 0);
681 return;
685 /**************************************************************************
686 s t r l e n
687 ** FICL ( c-string -- length )
689 ** Returns the length of a C-style (zero-terminated) string.
691 ** --lch
693 static void ficlStrlen(FICL_VM *ficlVM)
695 char *address = (char *)stackPopPtr(ficlVM->pStack);
696 stackPushINT(ficlVM->pStack, strlen(address));
700 /**************************************************************************
701 s p r i n t f
702 ** FICL ( i*x c-addr-fmt u-fmt c-addr-buffer u-buffer -- c-addr-buffer u-written success-flag )
703 ** Similar to the C sprintf() function. It formats into a buffer based on
704 ** a "format" string. Each character in the format string is copied verbatim
705 ** to the output buffer, until SPRINTF encounters a percent sign ("%").
706 ** SPRINTF then skips the percent sign, and examines the next character
707 ** (the "format character"). Here are the valid format characters:
708 ** s - read a C-ADDR U-LENGTH string from the stack and copy it to
709 ** the buffer
710 ** d - read a cell from the stack, format it as a string (base-10,
711 ** signed), and copy it to the buffer
712 ** x - same as d, except in base-16
713 ** u - same as d, but unsigned
714 ** % - output a literal percent-sign to the buffer
715 ** SPRINTF returns the c-addr-buffer argument unchanged, the number of bytes
716 ** written, and a flag indicating whether or not it ran out of space while
717 ** writing to the output buffer (TRUE if it ran out of space).
719 ** If SPRINTF runs out of space in the buffer to store the formatted string,
720 ** it still continues parsing, in an effort to preserve your stack (otherwise
721 ** it might leave uneaten arguments behind).
723 ** --lch
724 **************************************************************************/
725 static void ficlSprintf(FICL_VM *pVM) /* */
727 int bufferLength = stackPopINT(pVM->pStack);
728 char *buffer = (char *)stackPopPtr(pVM->pStack);
729 char *bufferStart = buffer;
731 int formatLength = stackPopINT(pVM->pStack);
732 char *format = (char *)stackPopPtr(pVM->pStack);
733 char *formatStop = format + formatLength;
735 int base = 10;
736 int unsignedInteger = FALSE;
738 FICL_INT append = FICL_TRUE;
740 while (format < formatStop)
742 char scratch[64];
743 char *source;
744 int actualLength;
745 int desiredLength;
746 int leadingZeroes;
749 if (*format != '%')
751 source = format;
752 actualLength = desiredLength = 1;
753 leadingZeroes = 0;
755 else
757 format++;
758 if (format == formatStop)
759 break;
761 leadingZeroes = (*format == '0');
762 if (leadingZeroes)
764 format++;
765 if (format == formatStop)
766 break;
769 desiredLength = isdigit(*format);
770 if (desiredLength)
772 desiredLength = strtol(format, &format, 10);
773 if (format == formatStop)
774 break;
776 else if (*format == '*')
778 desiredLength = stackPopINT(pVM->pStack);
779 format++;
780 if (format == formatStop)
781 break;
785 switch (*format)
787 case 's':
788 case 'S':
790 actualLength = stackPopINT(pVM->pStack);
791 source = (char *)stackPopPtr(pVM->pStack);
792 break;
794 case 'x':
795 case 'X':
796 base = 16;
797 case 'u':
798 case 'U':
799 unsignedInteger = TRUE;
800 case 'd':
801 case 'D':
803 int integer = stackPopINT(pVM->pStack);
804 if (unsignedInteger)
805 ultoa(integer, scratch, base);
806 else
807 ltoa(integer, scratch, base);
808 base = 10;
809 unsignedInteger = FALSE;
810 source = scratch;
811 actualLength = strlen(scratch);
812 break;
814 case '%':
815 source = format;
816 actualLength = 1;
817 default:
818 continue;
822 if (append != FICL_FALSE)
824 if (!desiredLength)
825 desiredLength = actualLength;
826 if (desiredLength > bufferLength)
828 append = FICL_FALSE;
829 desiredLength = bufferLength;
831 while (desiredLength > actualLength)
833 *buffer++ = (char)((leadingZeroes) ? '0' : ' ');
834 bufferLength--;
835 desiredLength--;
837 memcpy(buffer, source, actualLength);
838 buffer += actualLength;
839 bufferLength -= actualLength;
842 format++;
845 stackPushPtr(pVM->pStack, bufferStart);
846 stackPushINT(pVM->pStack, buffer - bufferStart);
847 stackPushINT(pVM->pStack, append);
851 /**************************************************************************
852 d u p & f r i e n d s
854 **************************************************************************/
856 static void depth(FICL_VM *pVM)
858 int i;
859 #if FICL_ROBUST > 1
860 vmCheckStack(pVM, 0, 1);
861 #endif
862 i = stackDepth(pVM->pStack);
863 PUSHINT(i);
864 return;
868 static void drop(FICL_VM *pVM)
870 #if FICL_ROBUST > 1
871 vmCheckStack(pVM, 1, 0);
872 #endif
873 stackDrop(pVM->pStack, 1);
874 return;
878 static void twoDrop(FICL_VM *pVM)
880 #if FICL_ROBUST > 1
881 vmCheckStack(pVM, 2, 0);
882 #endif
883 stackDrop(pVM->pStack, 2);
884 return;
888 static void dup(FICL_VM *pVM)
890 #if FICL_ROBUST > 1
891 vmCheckStack(pVM, 1, 2);
892 #endif
893 stackPick(pVM->pStack, 0);
894 return;
898 static void twoDup(FICL_VM *pVM)
900 #if FICL_ROBUST > 1
901 vmCheckStack(pVM, 2, 4);
902 #endif
903 stackPick(pVM->pStack, 1);
904 stackPick(pVM->pStack, 1);
905 return;
909 static void over(FICL_VM *pVM)
911 #if FICL_ROBUST > 1
912 vmCheckStack(pVM, 2, 3);
913 #endif
914 stackPick(pVM->pStack, 1);
915 return;
918 static void twoOver(FICL_VM *pVM)
920 #if FICL_ROBUST > 1
921 vmCheckStack(pVM, 4, 6);
922 #endif
923 stackPick(pVM->pStack, 3);
924 stackPick(pVM->pStack, 3);
925 return;
929 static void pick(FICL_VM *pVM)
931 CELL c = stackPop(pVM->pStack);
932 #if FICL_ROBUST > 1
933 vmCheckStack(pVM, c.i+1, c.i+2);
934 #endif
935 stackPick(pVM->pStack, c.i);
936 return;
940 static void questionDup(FICL_VM *pVM)
942 CELL c;
943 #if FICL_ROBUST > 1
944 vmCheckStack(pVM, 1, 2);
945 #endif
946 c = stackGetTop(pVM->pStack);
948 if (c.i != 0)
949 stackPick(pVM->pStack, 0);
951 return;
955 static void roll(FICL_VM *pVM)
957 int i = stackPop(pVM->pStack).i;
958 i = (i > 0) ? i : 0;
959 #if FICL_ROBUST > 1
960 vmCheckStack(pVM, i+1, i+1);
961 #endif
962 stackRoll(pVM->pStack, i);
963 return;
967 static void minusRoll(FICL_VM *pVM)
969 int i = stackPop(pVM->pStack).i;
970 i = (i > 0) ? i : 0;
971 #if FICL_ROBUST > 1
972 vmCheckStack(pVM, i+1, i+1);
973 #endif
974 stackRoll(pVM->pStack, -i);
975 return;
979 static void rot(FICL_VM *pVM)
981 #if FICL_ROBUST > 1
982 vmCheckStack(pVM, 3, 3);
983 #endif
984 stackRoll(pVM->pStack, 2);
985 return;
989 static void swap(FICL_VM *pVM)
991 #if FICL_ROBUST > 1
992 vmCheckStack(pVM, 2, 2);
993 #endif
994 stackRoll(pVM->pStack, 1);
995 return;
999 static void twoSwap(FICL_VM *pVM)
1001 #if FICL_ROBUST > 1
1002 vmCheckStack(pVM, 4, 4);
1003 #endif
1004 stackRoll(pVM->pStack, 3);
1005 stackRoll(pVM->pStack, 3);
1006 return;
1010 /**************************************************************************
1011 e m i t & f r i e n d s
1013 **************************************************************************/
1015 static void emit(FICL_VM *pVM)
1017 char cp[2];
1018 int i;
1020 #if FICL_ROBUST > 1
1021 vmCheckStack(pVM, 1, 0);
1022 #endif
1023 i = stackPopINT(pVM->pStack);
1024 cp[0] = (char)i;
1025 cp[1] = '\0';
1026 vmTextOut(pVM, cp, 0);
1027 return;
1031 static void cr(FICL_VM *pVM)
1033 vmTextOut(pVM, "", 1);
1034 return;
1038 static void commentLine(FICL_VM *pVM)
1040 char *cp = vmGetInBuf(pVM);
1041 char *pEnd = vmGetInBufEnd(pVM);
1042 char ch = *cp;
1044 while ((cp != pEnd) && (ch != '\r') && (ch != '\n'))
1046 ch = *++cp;
1050 ** Cope with DOS or UNIX-style EOLs -
1051 ** Check for /r, /n, /r/n, or /n/r end-of-line sequences,
1052 ** and point cp to next char. If EOL is \0, we're done.
1054 if (cp != pEnd)
1056 cp++;
1058 if ( (cp != pEnd) && (ch != *cp)
1059 && ((*cp == '\r') || (*cp == '\n')) )
1060 cp++;
1063 vmUpdateTib(pVM, cp);
1064 return;
1069 ** paren CORE
1070 ** Compilation: Perform the execution semantics given below.
1071 ** Execution: ( "ccc<paren>" -- )
1072 ** Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
1073 ** The number of characters in ccc may be zero to the number of characters
1074 ** in the parse area.
1077 static void commentHang(FICL_VM *pVM)
1079 vmParseStringEx(pVM, ')', 0);
1080 return;
1084 /**************************************************************************
1085 F E T C H & S T O R E
1087 **************************************************************************/
1089 static void fetch(FICL_VM *pVM)
1091 CELL *pCell;
1092 #if FICL_ROBUST > 1
1093 vmCheckStack(pVM, 1, 1);
1094 #endif
1095 pCell = (CELL *)stackPopPtr(pVM->pStack);
1096 stackPush(pVM->pStack, *pCell);
1097 return;
1101 ** two-fetch CORE ( a-addr -- x1 x2 )
1102 ** Fetch the cell pair x1 x2 stored at a-addr. x2 is stored at a-addr and
1103 ** x1 at the next consecutive cell. It is equivalent to the sequence
1104 ** DUP CELL+ @ SWAP @ .
1106 static void twoFetch(FICL_VM *pVM)
1108 CELL *pCell;
1109 #if FICL_ROBUST > 1
1110 vmCheckStack(pVM, 1, 2);
1111 #endif
1112 pCell = (CELL *)stackPopPtr(pVM->pStack);
1113 stackPush(pVM->pStack, *pCell++);
1114 stackPush(pVM->pStack, *pCell);
1115 swap(pVM);
1116 return;
1120 ** store CORE ( x a-addr -- )
1121 ** Store x at a-addr.
1123 static void store(FICL_VM *pVM)
1125 CELL *pCell;
1126 #if FICL_ROBUST > 1
1127 vmCheckStack(pVM, 2, 0);
1128 #endif
1129 pCell = (CELL *)stackPopPtr(pVM->pStack);
1130 *pCell = stackPop(pVM->pStack);
1134 ** two-store CORE ( x1 x2 a-addr -- )
1135 ** Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
1136 ** next consecutive cell. It is equivalent to the sequence
1137 ** SWAP OVER ! CELL+ ! .
1139 static void twoStore(FICL_VM *pVM)
1141 CELL *pCell;
1142 #if FICL_ROBUST > 1
1143 vmCheckStack(pVM, 3, 0);
1144 #endif
1145 pCell = (CELL *)stackPopPtr(pVM->pStack);
1146 *pCell++ = stackPop(pVM->pStack);
1147 *pCell = stackPop(pVM->pStack);
1150 static void plusStore(FICL_VM *pVM)
1152 CELL *pCell;
1153 #if FICL_ROBUST > 1
1154 vmCheckStack(pVM, 2, 0);
1155 #endif
1156 pCell = (CELL *)stackPopPtr(pVM->pStack);
1157 pCell->i += stackPop(pVM->pStack).i;
1161 static void quadFetch(FICL_VM *pVM)
1163 UNS32 *pw;
1164 #if FICL_ROBUST > 1
1165 vmCheckStack(pVM, 1, 1);
1166 #endif
1167 pw = (UNS32 *)stackPopPtr(pVM->pStack);
1168 PUSHUNS((FICL_UNS)*pw);
1169 return;
1172 static void quadStore(FICL_VM *pVM)
1174 UNS32 *pw;
1175 #if FICL_ROBUST > 1
1176 vmCheckStack(pVM, 2, 0);
1177 #endif
1178 pw = (UNS32 *)stackPopPtr(pVM->pStack);
1179 *pw = (UNS32)(stackPop(pVM->pStack).u);
1182 static void wFetch(FICL_VM *pVM)
1184 UNS16 *pw;
1185 #if FICL_ROBUST > 1
1186 vmCheckStack(pVM, 1, 1);
1187 #endif
1188 pw = (UNS16 *)stackPopPtr(pVM->pStack);
1189 PUSHUNS((FICL_UNS)*pw);
1190 return;
1193 static void wStore(FICL_VM *pVM)
1195 UNS16 *pw;
1196 #if FICL_ROBUST > 1
1197 vmCheckStack(pVM, 2, 0);
1198 #endif
1199 pw = (UNS16 *)stackPopPtr(pVM->pStack);
1200 *pw = (UNS16)(stackPop(pVM->pStack).u);
1203 static void cFetch(FICL_VM *pVM)
1205 UNS8 *pc;
1206 #if FICL_ROBUST > 1
1207 vmCheckStack(pVM, 1, 1);
1208 #endif
1209 pc = (UNS8 *)stackPopPtr(pVM->pStack);
1210 PUSHUNS((FICL_UNS)*pc);
1211 return;
1214 static void cStore(FICL_VM *pVM)
1216 UNS8 *pc;
1217 #if FICL_ROBUST > 1
1218 vmCheckStack(pVM, 2, 0);
1219 #endif
1220 pc = (UNS8 *)stackPopPtr(pVM->pStack);
1221 *pc = (UNS8)(stackPop(pVM->pStack).u);
1225 /**************************************************************************
1226 b r a n c h P a r e n
1228 ** Runtime for "(branch)" -- expects a literal offset in the next
1229 ** compilation address, and branches to that location.
1230 **************************************************************************/
1232 static void branchParen(FICL_VM *pVM)
1234 vmBranchRelative(pVM, (uintptr_t)*(pVM->ip));
1235 return;
1239 /**************************************************************************
1240 b r a n c h 0
1241 ** Runtime code for "(branch0)"; pop a flag from the stack,
1242 ** branch if 0. fall through otherwise. The heart of "if" and "until".
1243 **************************************************************************/
1245 static void branch0(FICL_VM *pVM)
1247 FICL_UNS flag;
1249 #if FICL_ROBUST > 1
1250 vmCheckStack(pVM, 1, 0);
1251 #endif
1252 flag = stackPopUNS(pVM->pStack);
1254 if (flag)
1255 { /* fall through */
1256 vmBranchRelative(pVM, 1);
1258 else
1259 { /* take branch (to else/endif/begin) */
1260 vmBranchRelative(pVM, (uintptr_t)*(pVM->ip));
1263 return;
1267 /**************************************************************************
1268 i f C o I m
1269 ** IMMEDIATE COMPILE-ONLY
1270 ** Compiles code for a conditional branch into the dictionary
1271 ** and pushes the branch patch address on the stack for later
1272 ** patching by ELSE or THEN/ENDIF.
1273 **************************************************************************/
1275 static void ifCoIm(FICL_VM *pVM)
1277 FICL_DICT *dp = vmGetDict(pVM);
1279 assert(pVM->pSys->pBranch0);
1281 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranch0));
1282 markBranch(dp, pVM, origTag);
1283 dictAppendUNS(dp, 1);
1284 return;
1288 /**************************************************************************
1289 e l s e C o I m
1291 ** IMMEDIATE COMPILE-ONLY
1292 ** compiles an "else"...
1293 ** 1) Compile a branch and a patch address; the address gets patched
1294 ** by "endif" to point past the "else" code.
1295 ** 2) Pop the "if" patch address
1296 ** 3) Patch the "if" branch to point to the current compile address.
1297 ** 4) Push the "else" patch address. ("endif" patches this to jump past
1298 ** the "else" code.
1299 **************************************************************************/
1301 static void elseCoIm(FICL_VM *pVM)
1303 CELL *patchAddr;
1304 FICL_INT offset;
1305 FICL_DICT *dp = vmGetDict(pVM);
1307 assert(pVM->pSys->pBranchParen);
1308 /* (1) compile branch runtime */
1309 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranchParen));
1310 matchControlTag(pVM, origTag);
1311 patchAddr =
1312 (CELL *)stackPopPtr(pVM->pStack); /* (2) pop "if" patch addr */
1313 markBranch(dp, pVM, origTag); /* (4) push "else" patch addr */
1314 dictAppendUNS(dp, 1); /* (1) compile patch placeholder */
1315 offset = dp->here - patchAddr;
1316 *patchAddr = LVALUEtoCELL(offset); /* (3) Patch "if" */
1318 return;
1322 /**************************************************************************
1323 e n d i f C o I m
1324 ** IMMEDIATE COMPILE-ONLY
1325 **************************************************************************/
1327 static void endifCoIm(FICL_VM *pVM)
1329 FICL_DICT *dp = vmGetDict(pVM);
1330 resolveForwardBranch(dp, pVM, origTag);
1331 return;
1335 /**************************************************************************
1336 c a s e C o I m
1337 ** IMMEDIATE COMPILE-ONLY
1340 ** At compile-time, a CASE-SYS (see DPANS94 6.2.0873) looks like this:
1341 ** i*addr i caseTag
1342 ** and an OF-SYS (see DPANS94 6.2.1950) looks like this:
1343 ** i*addr i caseTag addr ofTag
1344 ** The integer under caseTag is the count of fixup addresses that branch
1345 ** to ENDCASE.
1346 **************************************************************************/
1348 static void caseCoIm(FICL_VM *pVM)
1350 #if FICL_ROBUST > 1
1351 vmCheckStack(pVM, 0, 2);
1352 #endif
1354 PUSHUNS(0);
1355 markControlTag(pVM, caseTag);
1356 return;
1360 /**************************************************************************
1361 e n d c a s eC o I m
1362 ** IMMEDIATE COMPILE-ONLY
1363 **************************************************************************/
1365 static void endcaseCoIm(FICL_VM *pVM)
1367 FICL_UNS fixupCount;
1368 FICL_DICT *dp;
1369 CELL *patchAddr;
1370 FICL_INT offset;
1372 assert(pVM->pSys->pDrop);
1375 ** if the last OF ended with FALLTHROUGH,
1376 ** just add the FALLTHROUGH fixup to the
1377 ** ENDOF fixups
1379 if (stackGetTop(pVM->pStack).p == fallthroughTag)
1381 matchControlTag(pVM, fallthroughTag);
1382 patchAddr = POPPTR();
1383 matchControlTag(pVM, caseTag);
1384 fixupCount = POPUNS();
1385 PUSHPTR(patchAddr);
1386 PUSHUNS(fixupCount + 1);
1387 markControlTag(pVM, caseTag);
1390 matchControlTag(pVM, caseTag);
1392 #if FICL_ROBUST > 1
1393 vmCheckStack(pVM, 1, 0);
1394 #endif
1395 fixupCount = POPUNS();
1396 #if FICL_ROBUST > 1
1397 vmCheckStack(pVM, fixupCount, 0);
1398 #endif
1400 dp = vmGetDict(pVM);
1402 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pDrop));
1404 while (fixupCount--)
1406 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
1407 offset = dp->here - patchAddr;
1408 *patchAddr = LVALUEtoCELL(offset);
1410 return;
1414 static void ofParen(FICL_VM *pVM)
1416 FICL_UNS a, b;
1418 #if FICL_ROBUST > 1
1419 vmCheckStack(pVM, 2, 1);
1420 #endif
1422 a = POPUNS();
1423 b = stackGetTop(pVM->pStack).u;
1425 if (a == b)
1426 { /* fall through */
1427 stackDrop(pVM->pStack, 1);
1428 vmBranchRelative(pVM, 1);
1430 else
1431 { /* take branch to next of or endswitch */
1432 vmBranchRelative(pVM, *(int *)(pVM->ip));
1435 return;
1439 /**************************************************************************
1440 o f C o I m
1441 ** IMMEDIATE COMPILE-ONLY
1442 **************************************************************************/
1444 static void ofCoIm(FICL_VM *pVM)
1446 FICL_DICT *dp = vmGetDict(pVM);
1447 CELL *fallthroughFixup = NULL;
1449 assert(pVM->pSys->pBranch0);
1451 #if FICL_ROBUST > 1
1452 vmCheckStack(pVM, 1, 3);
1453 #endif
1455 if (stackGetTop(pVM->pStack).p == fallthroughTag)
1457 matchControlTag(pVM, fallthroughTag);
1458 fallthroughFixup = POPPTR();
1461 matchControlTag(pVM, caseTag);
1463 markControlTag(pVM, caseTag);
1465 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pOfParen));
1466 markBranch(dp, pVM, ofTag);
1467 dictAppendUNS(dp, 2);
1469 if (fallthroughFixup != NULL)
1471 FICL_INT offset = dp->here - fallthroughFixup;
1472 *fallthroughFixup = LVALUEtoCELL(offset);
1475 return;
1479 /**************************************************************************
1480 e n d o f C o I m
1481 ** IMMEDIATE COMPILE-ONLY
1482 **************************************************************************/
1484 static void endofCoIm(FICL_VM *pVM)
1486 CELL *patchAddr;
1487 FICL_UNS fixupCount;
1488 FICL_INT offset;
1489 FICL_DICT *dp = vmGetDict(pVM);
1491 #if FICL_ROBUST > 1
1492 vmCheckStack(pVM, 4, 3);
1493 #endif
1495 assert(pVM->pSys->pBranchParen);
1497 /* ensure we're in an OF, */
1498 matchControlTag(pVM, ofTag);
1499 /* grab the address of the branch location after the OF */
1500 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
1501 /* ensure we're also in a "case" */
1502 matchControlTag(pVM, caseTag);
1503 /* grab the current number of ENDOF fixups */
1504 fixupCount = POPUNS();
1506 /* compile branch runtime */
1507 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranchParen));
1509 /* push a new ENDOF fixup, the updated count of ENDOF fixups, and the caseTag */
1510 PUSHPTR(dp->here);
1511 PUSHUNS(fixupCount + 1);
1512 markControlTag(pVM, caseTag);
1514 /* reserve space for the ENDOF fixup */
1515 dictAppendUNS(dp, 2);
1517 /* and patch the original OF */
1518 offset = dp->here - patchAddr;
1519 *patchAddr = LVALUEtoCELL(offset);
1523 /**************************************************************************
1524 f a l l t h r o u g h C o I m
1525 ** IMMEDIATE COMPILE-ONLY
1526 **************************************************************************/
1528 static void fallthroughCoIm(FICL_VM *pVM)
1530 CELL *patchAddr;
1531 FICL_INT offset;
1532 FICL_DICT *dp = vmGetDict(pVM);
1534 #if FICL_ROBUST > 1
1535 vmCheckStack(pVM, 4, 3);
1536 #endif
1538 /* ensure we're in an OF, */
1539 matchControlTag(pVM, ofTag);
1540 /* grab the address of the branch location after the OF */
1541 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
1542 /* ensure we're also in a "case" */
1543 matchControlTag(pVM, caseTag);
1545 /* okay, here we go. put the case tag back. */
1546 markControlTag(pVM, caseTag);
1548 /* compile branch runtime */
1549 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranchParen));
1551 /* push a new FALLTHROUGH fixup and the fallthroughTag */
1552 PUSHPTR(dp->here);
1553 markControlTag(pVM, fallthroughTag);
1555 /* reserve space for the FALLTHROUGH fixup */
1556 dictAppendUNS(dp, 2);
1558 /* and patch the original OF */
1559 offset = dp->here - patchAddr;
1560 *patchAddr = LVALUEtoCELL(offset);
1563 /**************************************************************************
1564 h a s h
1565 ** hash ( c-addr u -- code)
1566 ** calculates hashcode of specified string and leaves it on the stack
1567 **************************************************************************/
1569 static void hash(FICL_VM *pVM)
1571 STRINGINFO si;
1572 SI_SETLEN(si, stackPopUNS(pVM->pStack));
1573 SI_SETPTR(si, stackPopPtr(pVM->pStack));
1574 PUSHUNS(hashHashCode(si));
1575 return;
1579 /**************************************************************************
1580 i n t e r p r e t
1581 ** This is the "user interface" of a Forth. It does the following:
1582 ** while there are words in the VM's Text Input Buffer
1583 ** Copy next word into the pad (vmGetWord)
1584 ** Attempt to find the word in the dictionary (dictLookup)
1585 ** If successful, execute the word.
1586 ** Otherwise, attempt to convert the word to a number (isNumber)
1587 ** If successful, push the number onto the parameter stack.
1588 ** Otherwise, print an error message and exit loop...
1589 ** End Loop
1591 ** From the standard, section 3.4
1592 ** Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
1593 ** repeat the following steps until either the parse area is empty or an
1594 ** ambiguous condition exists:
1595 ** a) Skip leading spaces and parse a name (see 3.4.1);
1596 **************************************************************************/
1598 static void interpret(FICL_VM *pVM)
1600 STRINGINFO si;
1601 int i;
1602 FICL_SYSTEM *pSys;
1604 assert(pVM);
1606 pSys = pVM->pSys;
1607 si = vmGetWord0(pVM);
1610 ** Get next word...if out of text, we're done.
1612 if (si.count == 0)
1614 vmThrow(pVM, VM_OUTOFTEXT);
1618 ** Attempt to find the incoming token in the dictionary. If that fails...
1619 ** run the parse chain against the incoming token until somebody eats it.
1620 ** Otherwise emit an error message and give up.
1621 ** Although ficlParseWord could be part of the parse list, I've hard coded it
1622 ** in for robustness. ficlInitSystem adds the other default steps to the list.
1624 if (ficlParseWord(pVM, si))
1625 return;
1627 for (i=0; i < FICL_MAX_PARSE_STEPS; i++)
1629 FICL_WORD *pFW = pSys->parseList[i];
1631 if (pFW == NULL)
1632 break;
1634 if (pFW->code == parseStepParen)
1636 FICL_PARSE_STEP pStep;
1637 pStep = (FICL_PARSE_STEP)(pFW->param->fn);
1638 if ((*pStep)(pVM, si))
1639 return;
1641 else
1643 stackPushPtr(pVM->pStack, SI_PTR(si));
1644 stackPushUNS(pVM->pStack, SI_COUNT(si));
1645 ficlExecXT(pVM, pFW);
1646 if (stackPopINT(pVM->pStack))
1647 return;
1651 i = SI_COUNT(si);
1652 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
1654 return; /* back to inner interpreter */
1658 /**************************************************************************
1659 f i c l P a r s e W o r d
1660 ** From the standard, section 3.4
1661 ** b) Search the dictionary name space (see 3.4.2). If a definition name
1662 ** matching the string is found:
1663 ** 1.if interpreting, perform the interpretation semantics of the definition
1664 ** (see 3.4.3.2), and continue at a);
1665 ** 2.if compiling, perform the compilation semantics of the definition
1666 ** (see 3.4.3.3), and continue at a).
1668 ** c) If a definition name matching the string is not found, attempt to
1669 ** convert the string to a number (see 3.4.1.3). If successful:
1670 ** 1.if interpreting, place the number on the data stack, and continue at a);
1671 ** 2.if compiling, compile code that when executed will place the number on
1672 ** the stack (see 6.1.1780 LITERAL), and continue at a);
1674 ** d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
1676 ** (jws 4/01) Modified to be a FICL_PARSE_STEP
1677 **************************************************************************/
1678 static int ficlParseWord(FICL_VM *pVM, STRINGINFO si)
1680 FICL_DICT *dp = vmGetDict(pVM);
1681 FICL_WORD *tempFW;
1683 #if FICL_ROBUST
1684 dictCheck(dp, pVM, 0);
1685 vmCheckStack(pVM, 0, 0);
1686 #endif
1688 #if FICL_WANT_LOCALS
1689 if (pVM->pSys->nLocals > 0)
1691 tempFW = ficlLookupLoc(pVM->pSys, si);
1693 else
1694 #endif
1695 tempFW = dictLookup(dp, si);
1697 if (pVM->state == INTERPRET)
1699 if (tempFW != NULL)
1701 if (wordIsCompileOnly(tempFW))
1703 vmThrowErr(pVM, "Error: Compile only!");
1706 vmExecute(pVM, tempFW);
1707 return (int)FICL_TRUE;
1711 else /* (pVM->state == COMPILE) */
1713 if (tempFW != NULL)
1715 if (wordIsImmediate(tempFW))
1717 vmExecute(pVM, tempFW);
1719 else
1721 dictAppendCell(dp, LVALUEtoCELL(tempFW));
1723 return (int)FICL_TRUE;
1727 return FICL_FALSE;
1732 ** Surrogate precompiled parse step for ficlParseWord (this step is hard coded in
1733 ** INTERPRET)
1735 static void lookup(FICL_VM *pVM)
1737 STRINGINFO si;
1738 SI_SETLEN(si, stackPopUNS(pVM->pStack));
1739 SI_SETPTR(si, stackPopPtr(pVM->pStack));
1740 stackPushINT(pVM->pStack, ficlParseWord(pVM, si));
1741 return;
1745 /**************************************************************************
1746 p a r e n P a r s e S t e p
1747 ** (parse-step) ( c-addr u -- flag )
1748 ** runtime for a precompiled parse step - pop a counted string off the
1749 ** stack, run the parse step against it, and push the result flag (FICL_TRUE
1750 ** if success, FICL_FALSE otherwise).
1751 **************************************************************************/
1753 void parseStepParen(FICL_VM *pVM)
1755 STRINGINFO si;
1756 FICL_WORD *pFW = pVM->runningWord;
1757 FICL_PARSE_STEP pStep = (FICL_PARSE_STEP)(pFW->param->fn);
1759 SI_SETLEN(si, stackPopINT(pVM->pStack));
1760 SI_SETPTR(si, stackPopPtr(pVM->pStack));
1762 PUSHINT((*pStep)(pVM, si));
1764 return;
1768 static void addParseStep(FICL_VM *pVM)
1770 FICL_WORD *pStep;
1771 FICL_DICT *pd = vmGetDict(pVM);
1772 #if FICL_ROBUST > 1
1773 vmCheckStack(pVM, 1, 0);
1774 #endif
1775 pStep = (FICL_WORD *)(stackPop(pVM->pStack).p);
1776 if ((pStep != NULL) && isAFiclWord(pd, pStep))
1777 ficlAddParseStep(pVM->pSys, pStep);
1778 return;
1782 /**************************************************************************
1783 l i t e r a l P a r e n
1785 ** This is the runtime for (literal). It assumes that it is part of a colon
1786 ** definition, and that the next CELL contains a value to be pushed on the
1787 ** parameter stack at runtime. This code is compiled by "literal".
1789 **************************************************************************/
1791 static void literalParen(FICL_VM *pVM)
1793 #if FICL_ROBUST > 1
1794 vmCheckStack(pVM, 0, 1);
1795 #endif
1796 PUSHINT(*(FICL_INT *)(pVM->ip));
1797 vmBranchRelative(pVM, 1);
1798 return;
1801 static void twoLitParen(FICL_VM *pVM)
1803 #if FICL_ROBUST > 1
1804 vmCheckStack(pVM, 0, 2);
1805 #endif
1806 PUSHINT(*((FICL_INT *)(pVM->ip)+1));
1807 PUSHINT(*(FICL_INT *)(pVM->ip));
1808 vmBranchRelative(pVM, 2);
1809 return;
1813 /**************************************************************************
1814 l i t e r a l I m
1816 ** IMMEDIATE code for "literal". This function gets a value from the stack
1817 ** and compiles it into the dictionary preceded by the code for "(literal)".
1818 ** IMMEDIATE
1819 **************************************************************************/
1821 static void literalIm(FICL_VM *pVM)
1823 FICL_DICT *dp = vmGetDict(pVM);
1824 assert(pVM->pSys->pLitParen);
1826 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pLitParen));
1827 dictAppendCell(dp, stackPop(pVM->pStack));
1829 return;
1833 static void twoLiteralIm(FICL_VM *pVM)
1835 FICL_DICT *dp = vmGetDict(pVM);
1836 assert(pVM->pSys->pTwoLitParen);
1838 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pTwoLitParen));
1839 dictAppendCell(dp, stackPop(pVM->pStack));
1840 dictAppendCell(dp, stackPop(pVM->pStack));
1842 return;
1845 /**************************************************************************
1846 l o g i c a n d c o m p a r i s o n s
1848 **************************************************************************/
1850 static void zeroEquals(FICL_VM *pVM)
1852 CELL c;
1853 #if FICL_ROBUST > 1
1854 vmCheckStack(pVM, 1, 1);
1855 #endif
1856 c.i = FICL_BOOL(stackPopINT(pVM->pStack) == 0);
1857 stackPush(pVM->pStack, c);
1858 return;
1861 static void zeroLess(FICL_VM *pVM)
1863 CELL c;
1864 #if FICL_ROBUST > 1
1865 vmCheckStack(pVM, 1, 1);
1866 #endif
1867 c.i = FICL_BOOL(stackPopINT(pVM->pStack) < 0);
1868 stackPush(pVM->pStack, c);
1869 return;
1872 static void zeroGreater(FICL_VM *pVM)
1874 CELL c;
1875 #if FICL_ROBUST > 1
1876 vmCheckStack(pVM, 1, 1);
1877 #endif
1878 c.i = FICL_BOOL(stackPopINT(pVM->pStack) > 0);
1879 stackPush(pVM->pStack, c);
1880 return;
1883 static void isEqual(FICL_VM *pVM)
1885 CELL x, y;
1887 #if FICL_ROBUST > 1
1888 vmCheckStack(pVM, 2, 1);
1889 #endif
1890 x = stackPop(pVM->pStack);
1891 y = stackPop(pVM->pStack);
1892 PUSHINT(FICL_BOOL(x.i == y.i));
1893 return;
1896 static void isLess(FICL_VM *pVM)
1898 CELL x, y;
1899 #if FICL_ROBUST > 1
1900 vmCheckStack(pVM, 2, 1);
1901 #endif
1902 y = stackPop(pVM->pStack);
1903 x = stackPop(pVM->pStack);
1904 PUSHINT(FICL_BOOL(x.i < y.i));
1905 return;
1908 static void uIsLess(FICL_VM *pVM)
1910 FICL_UNS u1, u2;
1911 #if FICL_ROBUST > 1
1912 vmCheckStack(pVM, 2, 1);
1913 #endif
1914 u2 = stackPopUNS(pVM->pStack);
1915 u1 = stackPopUNS(pVM->pStack);
1916 PUSHINT(FICL_BOOL(u1 < u2));
1917 return;
1920 static void isGreater(FICL_VM *pVM)
1922 CELL x, y;
1923 #if FICL_ROBUST > 1
1924 vmCheckStack(pVM, 2, 1);
1925 #endif
1926 y = stackPop(pVM->pStack);
1927 x = stackPop(pVM->pStack);
1928 PUSHINT(FICL_BOOL(x.i > y.i));
1929 return;
1932 static void uIsGreater(FICL_VM *pVM)
1934 FICL_UNS u1, u2;
1935 #if FICL_ROBUST > 1
1936 vmCheckStack(pVM, 2, 1);
1937 #endif
1938 u2 = stackPopUNS(pVM->pStack);
1939 u1 = stackPopUNS(pVM->pStack);
1940 PUSHINT(FICL_BOOL(u1 > u2));
1941 return;
1944 static void bitwiseAnd(FICL_VM *pVM)
1946 CELL x, y;
1947 #if FICL_ROBUST > 1
1948 vmCheckStack(pVM, 2, 1);
1949 #endif
1950 x = stackPop(pVM->pStack);
1951 y = stackPop(pVM->pStack);
1952 PUSHINT(x.i & y.i);
1953 return;
1956 static void bitwiseOr(FICL_VM *pVM)
1958 CELL x, y;
1959 #if FICL_ROBUST > 1
1960 vmCheckStack(pVM, 2, 1);
1961 #endif
1962 x = stackPop(pVM->pStack);
1963 y = stackPop(pVM->pStack);
1964 PUSHINT(x.i | y.i);
1965 return;
1968 static void bitwiseXor(FICL_VM *pVM)
1970 CELL x, y;
1971 #if FICL_ROBUST > 1
1972 vmCheckStack(pVM, 2, 1);
1973 #endif
1974 x = stackPop(pVM->pStack);
1975 y = stackPop(pVM->pStack);
1976 PUSHINT(x.i ^ y.i);
1977 return;
1980 static void bitwiseNot(FICL_VM *pVM)
1982 CELL x;
1983 #if FICL_ROBUST > 1
1984 vmCheckStack(pVM, 1, 1);
1985 #endif
1986 x = stackPop(pVM->pStack);
1987 PUSHINT(~x.i);
1988 return;
1992 /**************************************************************************
1993 D o / L o o p
1994 ** do -- IMMEDIATE COMPILE ONLY
1995 ** Compiles code to initialize a loop: compile (do),
1996 ** allot space to hold the "leave" address, push a branch
1997 ** target address for the loop.
1998 ** (do) -- runtime for "do"
1999 ** pops index and limit from the p stack and moves them
2000 ** to the r stack, then skips to the loop body.
2001 ** loop -- IMMEDIATE COMPILE ONLY
2002 ** +loop
2003 ** Compiles code for the test part of a loop:
2004 ** compile (loop), resolve forward branch from "do", and
2005 ** copy "here" address to the "leave" address allotted by "do"
2006 ** i,j,k -- COMPILE ONLY
2007 ** Runtime: Push loop indices on param stack (i is innermost loop...)
2008 ** Note: each loop has three values on the return stack:
2009 ** ( R: leave limit index )
2010 ** "leave" is the absolute address of the next cell after the loop
2011 ** limit and index are the loop control variables.
2012 ** leave -- COMPILE ONLY
2013 ** Runtime: pop the loop control variables, then pop the
2014 ** "leave" address and jump (absolute) there.
2015 **************************************************************************/
2017 static void doCoIm(FICL_VM *pVM)
2019 FICL_DICT *dp = vmGetDict(pVM);
2021 assert(pVM->pSys->pDoParen);
2023 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pDoParen));
2025 ** Allot space for a pointer to the end
2026 ** of the loop - "leave" uses this...
2028 markBranch(dp, pVM, leaveTag);
2029 dictAppendUNS(dp, 0);
2031 ** Mark location of head of loop...
2033 markBranch(dp, pVM, doTag);
2035 return;
2039 static void doParen(FICL_VM *pVM)
2041 CELL index, limit;
2042 #if FICL_ROBUST > 1
2043 vmCheckStack(pVM, 2, 0);
2044 #endif
2045 index = stackPop(pVM->pStack);
2046 limit = stackPop(pVM->pStack);
2048 /* copy "leave" target addr to stack */
2049 stackPushPtr(pVM->rStack, *(pVM->ip++));
2050 stackPush(pVM->rStack, limit);
2051 stackPush(pVM->rStack, index);
2053 return;
2057 static void qDoCoIm(FICL_VM *pVM)
2059 FICL_DICT *dp = vmGetDict(pVM);
2061 assert(pVM->pSys->pQDoParen);
2063 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pQDoParen));
2065 ** Allot space for a pointer to the end
2066 ** of the loop - "leave" uses this...
2068 markBranch(dp, pVM, leaveTag);
2069 dictAppendUNS(dp, 0);
2071 ** Mark location of head of loop...
2073 markBranch(dp, pVM, doTag);
2075 return;
2079 static void qDoParen(FICL_VM *pVM)
2081 CELL index, limit;
2082 #if FICL_ROBUST > 1
2083 vmCheckStack(pVM, 2, 0);
2084 #endif
2085 index = stackPop(pVM->pStack);
2086 limit = stackPop(pVM->pStack);
2088 /* copy "leave" target addr to stack */
2089 stackPushPtr(pVM->rStack, *(pVM->ip++));
2091 if (limit.u == index.u)
2093 vmPopIP(pVM);
2095 else
2097 stackPush(pVM->rStack, limit);
2098 stackPush(pVM->rStack, index);
2101 return;
2106 ** Runtime code to break out of a do..loop construct
2107 ** Drop the loop control variables; the branch address
2108 ** past "loop" is next on the return stack.
2110 static void leaveCo(FICL_VM *pVM)
2112 /* almost unloop */
2113 stackDrop(pVM->rStack, 2);
2114 /* exit */
2115 vmPopIP(pVM);
2116 return;
2120 static void unloopCo(FICL_VM *pVM)
2122 stackDrop(pVM->rStack, 3);
2123 return;
2127 static void loopCoIm(FICL_VM *pVM)
2129 FICL_DICT *dp = vmGetDict(pVM);
2131 assert(pVM->pSys->pLoopParen);
2133 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pLoopParen));
2134 resolveBackBranch(dp, pVM, doTag);
2135 resolveAbsBranch(dp, pVM, leaveTag);
2136 return;
2140 static void plusLoopCoIm(FICL_VM *pVM)
2142 FICL_DICT *dp = vmGetDict(pVM);
2144 assert(pVM->pSys->pPLoopParen);
2146 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pPLoopParen));
2147 resolveBackBranch(dp, pVM, doTag);
2148 resolveAbsBranch(dp, pVM, leaveTag);
2149 return;
2153 static void loopParen(FICL_VM *pVM)
2155 FICL_INT index = stackGetTop(pVM->rStack).i;
2156 FICL_INT limit = stackFetch(pVM->rStack, 1).i;
2158 index++;
2160 if (index >= limit)
2162 stackDrop(pVM->rStack, 3); /* nuke the loop indices & "leave" addr */
2163 vmBranchRelative(pVM, 1); /* fall through the loop */
2165 else
2166 { /* update index, branch to loop head */
2167 stackSetTop(pVM->rStack, LVALUEtoCELL(index));
2168 vmBranchRelative(pVM, (uintptr_t)*(pVM->ip));
2171 return;
2175 static void plusLoopParen(FICL_VM *pVM)
2177 FICL_INT index,limit,increment;
2178 int flag;
2180 #if FICL_ROBUST > 1
2181 vmCheckStack(pVM, 1, 0);
2182 #endif
2184 index = stackGetTop(pVM->rStack).i;
2185 limit = stackFetch(pVM->rStack, 1).i;
2186 increment = POP().i;
2188 index += increment;
2190 if (increment < 0)
2191 flag = (index < limit);
2192 else
2193 flag = (index >= limit);
2195 if (flag)
2197 stackDrop(pVM->rStack, 3); /* nuke the loop indices & "leave" addr */
2198 vmBranchRelative(pVM, 1); /* fall through the loop */
2200 else
2201 { /* update index, branch to loop head */
2202 stackSetTop(pVM->rStack, LVALUEtoCELL(index));
2203 vmBranchRelative(pVM, (uintptr_t)*(pVM->ip));
2206 return;
2210 static void loopICo(FICL_VM *pVM)
2212 CELL index = stackGetTop(pVM->rStack);
2213 stackPush(pVM->pStack, index);
2215 return;
2219 static void loopJCo(FICL_VM *pVM)
2221 CELL index = stackFetch(pVM->rStack, 3);
2222 stackPush(pVM->pStack, index);
2224 return;
2228 static void loopKCo(FICL_VM *pVM)
2230 CELL index = stackFetch(pVM->rStack, 6);
2231 stackPush(pVM->pStack, index);
2233 return;
2237 /**************************************************************************
2238 r e t u r n s t a c k
2240 **************************************************************************/
2241 static void toRStack(FICL_VM *pVM)
2243 #if FICL_ROBUST > 1
2244 vmCheckStack(pVM, 1, 0);
2245 #endif
2247 stackPush(pVM->rStack, POP());
2250 static void fromRStack(FICL_VM *pVM)
2252 #if FICL_ROBUST > 1
2253 vmCheckStack(pVM, 0, 1);
2254 #endif
2256 PUSH(stackPop(pVM->rStack));
2259 static void fetchRStack(FICL_VM *pVM)
2261 #if FICL_ROBUST > 1
2262 vmCheckStack(pVM, 0, 1);
2263 #endif
2265 PUSH(stackGetTop(pVM->rStack));
2268 static void twoToR(FICL_VM *pVM)
2270 #if FICL_ROBUST > 1
2271 vmCheckStack(pVM, 2, 0);
2272 #endif
2273 stackRoll(pVM->pStack, 1);
2274 stackPush(pVM->rStack, stackPop(pVM->pStack));
2275 stackPush(pVM->rStack, stackPop(pVM->pStack));
2276 return;
2279 static void twoRFrom(FICL_VM *pVM)
2281 #if FICL_ROBUST > 1
2282 vmCheckStack(pVM, 0, 2);
2283 #endif
2284 stackPush(pVM->pStack, stackPop(pVM->rStack));
2285 stackPush(pVM->pStack, stackPop(pVM->rStack));
2286 stackRoll(pVM->pStack, 1);
2287 return;
2290 static void twoRFetch(FICL_VM *pVM)
2292 #if FICL_ROBUST > 1
2293 vmCheckStack(pVM, 0, 2);
2294 #endif
2295 stackPush(pVM->pStack, stackFetch(pVM->rStack, 1));
2296 stackPush(pVM->pStack, stackFetch(pVM->rStack, 0));
2297 return;
2301 /**************************************************************************
2302 v a r i a b l e
2304 **************************************************************************/
2306 static void variableParen(FICL_VM *pVM)
2308 FICL_WORD *fw;
2309 #if FICL_ROBUST > 1
2310 vmCheckStack(pVM, 0, 1);
2311 #endif
2313 fw = pVM->runningWord;
2314 PUSHPTR(fw->param);
2318 static void variable(FICL_VM *pVM)
2320 FICL_DICT *dp = vmGetDict(pVM);
2321 STRINGINFO si = vmGetWord(pVM);
2323 dictAppendWord2(dp, si, variableParen, FW_DEFAULT);
2324 dictAllotCells(dp, 1);
2325 return;
2329 static void twoVariable(FICL_VM *pVM)
2331 FICL_DICT *dp = vmGetDict(pVM);
2332 STRINGINFO si = vmGetWord(pVM);
2334 dictAppendWord2(dp, si, variableParen, FW_DEFAULT);
2335 dictAllotCells(dp, 2);
2336 return;
2340 /**************************************************************************
2341 b a s e & f r i e n d s
2343 **************************************************************************/
2345 static void base(FICL_VM *pVM)
2347 CELL *pBase;
2348 #if FICL_ROBUST > 1
2349 vmCheckStack(pVM, 0, 1);
2350 #endif
2352 pBase = (CELL *)(&pVM->base);
2353 stackPush(pVM->pStack, LVALUEtoCELL(pBase));
2354 return;
2358 static void decimal(FICL_VM *pVM)
2360 pVM->base = 10;
2361 return;
2365 static void hex(FICL_VM *pVM)
2367 pVM->base = 16;
2368 return;
2372 /**************************************************************************
2373 a l l o t & f r i e n d s
2375 **************************************************************************/
2377 static void allot(FICL_VM *pVM)
2379 FICL_DICT *dp;
2380 FICL_INT i;
2381 #if FICL_ROBUST > 1
2382 vmCheckStack(pVM, 1, 0);
2383 #endif
2385 dp = vmGetDict(pVM);
2386 i = POPINT();
2388 #if FICL_ROBUST
2389 dictCheck(dp, pVM, i);
2390 #endif
2392 dictAllot(dp, i);
2393 return;
2397 static void here(FICL_VM *pVM)
2399 FICL_DICT *dp;
2400 #if FICL_ROBUST > 1
2401 vmCheckStack(pVM, 0, 1);
2402 #endif
2404 dp = vmGetDict(pVM);
2405 PUSHPTR(dp->here);
2406 return;
2409 static void comma(FICL_VM *pVM)
2411 FICL_DICT *dp;
2412 CELL c;
2413 #if FICL_ROBUST > 1
2414 vmCheckStack(pVM, 1, 0);
2415 #endif
2417 dp = vmGetDict(pVM);
2418 c = POP();
2419 dictAppendCell(dp, c);
2420 return;
2423 static void cComma(FICL_VM *pVM)
2425 FICL_DICT *dp;
2426 char c;
2427 #if FICL_ROBUST > 1
2428 vmCheckStack(pVM, 1, 0);
2429 #endif
2431 dp = vmGetDict(pVM);
2432 c = (char)POPINT();
2433 dictAppendChar(dp, c);
2434 return;
2437 static void cells(FICL_VM *pVM)
2439 FICL_INT i;
2440 #if FICL_ROBUST > 1
2441 vmCheckStack(pVM, 1, 1);
2442 #endif
2444 i = POPINT();
2445 PUSHINT(i * (FICL_INT)sizeof (CELL));
2446 return;
2449 static void cellPlus(FICL_VM *pVM)
2451 char *cp;
2452 #if FICL_ROBUST > 1
2453 vmCheckStack(pVM, 1, 1);
2454 #endif
2456 cp = POPPTR();
2457 PUSHPTR(cp + sizeof (CELL));
2458 return;
2463 /**************************************************************************
2464 t i c k
2465 ** tick CORE ( "<spaces>name" -- xt )
2466 ** Skip leading space delimiters. Parse name delimited by a space. Find
2467 ** name and return xt, the execution token for name. An ambiguous condition
2468 ** exists if name is not found.
2469 **************************************************************************/
2470 void ficlTick(FICL_VM *pVM)
2472 FICL_WORD *pFW = NULL;
2473 STRINGINFO si = vmGetWord(pVM);
2474 #if FICL_ROBUST > 1
2475 vmCheckStack(pVM, 0, 1);
2476 #endif
2478 pFW = dictLookup(vmGetDict(pVM), si);
2479 if (!pFW)
2481 int i = SI_COUNT(si);
2482 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
2484 PUSHPTR(pFW);
2485 return;
2489 static void bracketTickCoIm(FICL_VM *pVM)
2491 ficlTick(pVM);
2492 literalIm(pVM);
2494 return;
2498 /**************************************************************************
2499 p o s t p o n e
2500 ** Lookup the next word in the input stream and compile code to
2501 ** insert it into definitions created by the resulting word
2502 ** (defers compilation, even of immediate words)
2503 **************************************************************************/
2505 static void postponeCoIm(FICL_VM *pVM)
2507 FICL_DICT *dp = vmGetDict(pVM);
2508 FICL_WORD *pFW;
2509 FICL_WORD *pComma = ficlLookup(pVM->pSys, ",");
2510 assert(pComma);
2512 ficlTick(pVM);
2513 pFW = stackGetTop(pVM->pStack).p;
2514 if (wordIsImmediate(pFW))
2516 dictAppendCell(dp, stackPop(pVM->pStack));
2518 else
2520 literalIm(pVM);
2521 dictAppendCell(dp, LVALUEtoCELL(pComma));
2524 return;
2529 /**************************************************************************
2530 e x e c u t e
2531 ** Pop an execution token (pointer to a word) off the stack and
2532 ** run it
2533 **************************************************************************/
2535 static void execute(FICL_VM *pVM)
2537 FICL_WORD *pFW;
2538 #if FICL_ROBUST > 1
2539 vmCheckStack(pVM, 1, 0);
2540 #endif
2542 pFW = stackPopPtr(pVM->pStack);
2543 vmExecute(pVM, pFW);
2545 return;
2549 /**************************************************************************
2550 i m m e d i a t e
2551 ** Make the most recently compiled word IMMEDIATE -- it executes even
2552 ** in compile state (most often used for control compiling words
2553 ** such as IF, THEN, etc)
2554 **************************************************************************/
2556 static void immediate(FICL_VM *pVM)
2558 IGNORE(pVM);
2559 dictSetImmediate(vmGetDict(pVM));
2560 return;
2564 static void compileOnly(FICL_VM *pVM)
2566 IGNORE(pVM);
2567 dictSetFlags(vmGetDict(pVM), FW_COMPILE, 0);
2568 return;
2572 static void setObjectFlag(FICL_VM *pVM)
2574 IGNORE(pVM);
2575 dictSetFlags(vmGetDict(pVM), FW_ISOBJECT, 0);
2576 return;
2579 static void isObject(FICL_VM *pVM)
2581 FICL_INT flag;
2582 FICL_WORD *pFW = (FICL_WORD *)stackPopPtr(pVM->pStack);
2584 flag = ((pFW != NULL) && (pFW->flags & FW_ISOBJECT)) ? FICL_TRUE : FICL_FALSE;
2585 stackPushINT(pVM->pStack, flag);
2586 return;
2589 static void cstringLit(FICL_VM *pVM)
2591 FICL_STRING *sp = (FICL_STRING *)(pVM->ip);
2593 char *cp = sp->text;
2594 cp += sp->count + 1;
2595 cp = alignPtr(cp);
2596 pVM->ip = (IPTYPE)(void *)cp;
2598 stackPushPtr(pVM->pStack, sp);
2599 return;
2603 static void cstringQuoteIm(FICL_VM *pVM)
2605 FICL_DICT *dp = vmGetDict(pVM);
2607 if (pVM->state == INTERPRET)
2609 FICL_STRING *sp = (FICL_STRING *) dp->here;
2610 vmGetString(pVM, sp, '\"');
2611 stackPushPtr(pVM->pStack, sp);
2612 /* move HERE past string so it doesn't get overwritten. --lch */
2613 dictAllot(dp, sp->count + sizeof(FICL_COUNT));
2615 else /* COMPILE state */
2617 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pCStringLit));
2618 dp->here = PTRtoCELL vmGetString(pVM, (FICL_STRING *)dp->here, '\"');
2619 dictAlign(dp);
2622 return;
2625 /**************************************************************************
2626 d o t Q u o t e
2627 ** IMMEDIATE word that compiles a string literal for later display
2628 ** Compile stringLit, then copy the bytes of the string from the TIB
2629 ** to the dictionary. Backpatch the count byte and align the dictionary.
2631 ** stringlit: Fetch the count from the dictionary, then push the address
2632 ** and count on the stack. Finally, update ip to point to the first
2633 ** aligned address after the string text.
2634 **************************************************************************/
2636 static void stringLit(FICL_VM *pVM)
2638 FICL_STRING *sp;
2639 FICL_COUNT count;
2640 char *cp;
2641 #if FICL_ROBUST > 1
2642 vmCheckStack(pVM, 0, 2);
2643 #endif
2645 sp = (FICL_STRING *)(pVM->ip);
2646 count = sp->count;
2647 cp = sp->text;
2648 PUSHPTR(cp);
2649 PUSHUNS(count);
2650 cp += count + 1;
2651 cp = alignPtr(cp);
2652 pVM->ip = (IPTYPE)(void *)cp;
2655 static void dotQuoteCoIm(FICL_VM *pVM)
2657 FICL_DICT *dp = vmGetDict(pVM);
2658 FICL_WORD *pType = ficlLookup(pVM->pSys, "type");
2659 assert(pType);
2660 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pStringLit));
2661 dp->here = PTRtoCELL vmGetString(pVM, (FICL_STRING *)dp->here, '\"');
2662 dictAlign(dp);
2663 dictAppendCell(dp, LVALUEtoCELL(pType));
2664 return;
2668 static void dotParen(FICL_VM *pVM)
2670 char *pSrc = vmGetInBuf(pVM);
2671 char *pEnd = vmGetInBufEnd(pVM);
2672 char *pDest = pVM->pad;
2673 char ch;
2676 ** Note: the standard does not want leading spaces skipped (apparently)
2678 for (ch = *pSrc; (pEnd != pSrc) && (ch != ')'); ch = *++pSrc)
2679 *pDest++ = ch;
2681 *pDest = '\0';
2682 if ((pEnd != pSrc) && (ch == ')'))
2683 pSrc++;
2685 vmTextOut(pVM, pVM->pad, 0);
2686 vmUpdateTib(pVM, pSrc);
2688 return;
2692 /**************************************************************************
2693 s l i t e r a l
2694 ** STRING
2695 ** Interpretation: Interpretation semantics for this word are undefined.
2696 ** Compilation: ( c-addr1 u -- )
2697 ** Append the run-time semantics given below to the current definition.
2698 ** Run-time: ( -- c-addr2 u )
2699 ** Return c-addr2 u describing a string consisting of the characters
2700 ** specified by c-addr1 u during compilation. A program shall not alter
2701 ** the returned string.
2702 **************************************************************************/
2703 static void sLiteralCoIm(FICL_VM *pVM)
2705 FICL_DICT *dp;
2706 char *cp, *cpDest;
2707 FICL_UNS u;
2709 #if FICL_ROBUST > 1
2710 vmCheckStack(pVM, 2, 0);
2711 #endif
2713 dp = vmGetDict(pVM);
2714 u = POPUNS();
2715 cp = POPPTR();
2717 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pStringLit));
2718 cpDest = (char *) dp->here;
2719 *cpDest++ = (char) u;
2721 for (; u > 0; --u)
2723 *cpDest++ = *cp++;
2726 *cpDest++ = 0;
2727 dp->here = PTRtoCELL alignPtr(cpDest);
2728 return;
2732 /**************************************************************************
2733 s t a t e
2734 ** Return the address of the VM's state member (must be sized the
2735 ** same as a CELL for this reason)
2736 **************************************************************************/
2737 static void state(FICL_VM *pVM)
2739 #if FICL_ROBUST > 1
2740 vmCheckStack(pVM, 0, 1);
2741 #endif
2742 PUSHPTR(&pVM->state);
2743 return;
2747 /**************************************************************************
2748 c r e a t e . . . d o e s >
2749 ** Make a new word in the dictionary with the run-time effect of
2750 ** a variable (push my address), but with extra space allotted
2751 ** for use by does> .
2752 **************************************************************************/
2754 static void createParen(FICL_VM *pVM)
2756 CELL *pCell;
2758 #if FICL_ROBUST > 1
2759 vmCheckStack(pVM, 0, 1);
2760 #endif
2762 pCell = pVM->runningWord->param;
2763 PUSHPTR(pCell+1);
2764 return;
2768 static void create(FICL_VM *pVM)
2770 FICL_DICT *dp = vmGetDict(pVM);
2771 STRINGINFO si = vmGetWord(pVM);
2773 dictCheckThreshold(dp);
2775 dictAppendWord2(dp, si, createParen, FW_DEFAULT);
2776 dictAllotCells(dp, 1);
2777 return;
2781 static void doDoes(FICL_VM *pVM)
2783 CELL *pCell;
2784 IPTYPE tempIP;
2785 #if FICL_ROBUST > 1
2786 vmCheckStack(pVM, 0, 1);
2787 #endif
2789 pCell = pVM->runningWord->param;
2790 tempIP = (IPTYPE)((*pCell).p);
2791 PUSHPTR(pCell+1);
2792 vmPushIP(pVM, tempIP);
2793 return;
2797 static void doesParen(FICL_VM *pVM)
2799 FICL_DICT *dp = vmGetDict(pVM);
2800 dp->smudge->code = doDoes;
2801 dp->smudge->param[0] = LVALUEtoCELL(pVM->ip);
2802 vmPopIP(pVM);
2803 return;
2807 static void doesCoIm(FICL_VM *pVM)
2809 FICL_DICT *dp = vmGetDict(pVM);
2810 #if FICL_WANT_LOCALS
2811 assert(pVM->pSys->pUnLinkParen);
2812 if (pVM->pSys->nLocals > 0)
2814 FICL_DICT *pLoc = ficlGetLoc(pVM->pSys);
2815 dictEmpty(pLoc, pLoc->pForthWords->size);
2816 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pUnLinkParen));
2819 pVM->pSys->nLocals = 0;
2820 #endif
2821 IGNORE(pVM);
2823 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pDoesParen));
2824 return;
2828 /**************************************************************************
2829 t o b o d y
2830 ** to-body CORE ( xt -- a-addr )
2831 ** a-addr is the data-field address corresponding to xt. An ambiguous
2832 ** condition exists if xt is not for a word defined via CREATE.
2833 **************************************************************************/
2834 static void toBody(FICL_VM *pVM)
2836 FICL_WORD *pFW;
2837 /*#$-GUY CHANGE: Added robustness.-$#*/
2838 #if FICL_ROBUST > 1
2839 vmCheckStack(pVM, 1, 1);
2840 #endif
2842 pFW = POPPTR();
2843 PUSHPTR(pFW->param + 1);
2844 return;
2849 ** from-body ficl ( a-addr -- xt )
2850 ** Reverse effect of >body
2852 static void fromBody(FICL_VM *pVM)
2854 char *ptr;
2855 #if FICL_ROBUST > 1
2856 vmCheckStack(pVM, 1, 1);
2857 #endif
2859 ptr = (char *)POPPTR() - sizeof (FICL_WORD);
2860 PUSHPTR(ptr);
2861 return;
2866 ** >name ficl ( xt -- c-addr u )
2867 ** Push the address and length of a word's name given its address
2868 ** xt.
2870 static void toName(FICL_VM *pVM)
2872 FICL_WORD *pFW;
2873 #if FICL_ROBUST > 1
2874 vmCheckStack(pVM, 1, 2);
2875 #endif
2877 pFW = POPPTR();
2878 PUSHPTR(pFW->name);
2879 PUSHUNS(pFW->nName);
2880 return;
2884 static void getLastWord(FICL_VM *pVM)
2886 FICL_DICT *pDict = vmGetDict(pVM);
2887 FICL_WORD *wp = pDict->smudge;
2888 assert(wp);
2889 vmPush(pVM, LVALUEtoCELL(wp));
2890 return;
2894 /**************************************************************************
2895 l b r a c k e t e t c
2897 **************************************************************************/
2899 static void lbracketCoIm(FICL_VM *pVM)
2901 pVM->state = INTERPRET;
2902 return;
2906 static void rbracket(FICL_VM *pVM)
2908 pVM->state = COMPILE;
2909 return;
2913 /**************************************************************************
2914 p i c t u r e d n u m e r i c w o r d s
2916 ** less-number-sign CORE ( -- )
2917 ** Initialize the pictured numeric output conversion process.
2918 ** (clear the pad)
2919 **************************************************************************/
2920 static void lessNumberSign(FICL_VM *pVM)
2922 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2923 sp->count = 0;
2924 return;
2928 ** number-sign CORE ( ud1 -- ud2 )
2929 ** Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
2930 ** n. (n is the least-significant digit of ud1.) Convert n to external form
2931 ** and add the resulting character to the beginning of the pictured numeric
2932 ** output string. An ambiguous condition exists if # executes outside of a
2933 ** <# #> delimited number conversion.
2935 static void numberSign(FICL_VM *pVM)
2937 FICL_STRING *sp;
2938 DPUNS u;
2939 UNS16 rem;
2940 #if FICL_ROBUST > 1
2941 vmCheckStack(pVM, 2, 2);
2942 #endif
2944 sp = PTRtoSTRING pVM->pad;
2945 u = u64Pop(pVM->pStack);
2946 rem = m64UMod(&u, (UNS16)(pVM->base));
2947 sp->text[sp->count++] = digit_to_char(rem);
2948 u64Push(pVM->pStack, u);
2949 return;
2953 ** number-sign-greater CORE ( xd -- c-addr u )
2954 ** Drop xd. Make the pictured numeric output string available as a character
2955 ** string. c-addr and u specify the resulting character string. A program
2956 ** may replace characters within the string.
2958 static void numberSignGreater(FICL_VM *pVM)
2960 FICL_STRING *sp;
2961 #if FICL_ROBUST > 1
2962 vmCheckStack(pVM, 2, 2);
2963 #endif
2965 sp = PTRtoSTRING pVM->pad;
2966 sp->text[sp->count] = 0;
2967 strrev(sp->text);
2968 DROP(2);
2969 PUSHPTR(sp->text);
2970 PUSHUNS(sp->count);
2971 return;
2975 ** number-sign-s CORE ( ud1 -- ud2 )
2976 ** Convert one digit of ud1 according to the rule for #. Continue conversion
2977 ** until the quotient is zero. ud2 is zero. An ambiguous condition exists if
2978 ** #S executes outside of a <# #> delimited number conversion.
2979 ** TO DO: presently does not use ud1 hi cell - use it!
2981 static void numberSignS(FICL_VM *pVM)
2983 FICL_STRING *sp;
2984 DPUNS u;
2985 UNS16 rem;
2986 #if FICL_ROBUST > 1
2987 vmCheckStack(pVM, 2, 2);
2988 #endif
2990 sp = PTRtoSTRING pVM->pad;
2991 u = u64Pop(pVM->pStack);
2995 rem = m64UMod(&u, (UNS16)(pVM->base));
2996 sp->text[sp->count++] = digit_to_char(rem);
2998 while (u.hi || u.lo);
3000 u64Push(pVM->pStack, u);
3001 return;
3005 ** HOLD CORE ( char -- )
3006 ** Add char to the beginning of the pictured numeric output string. An ambiguous
3007 ** condition exists if HOLD executes outside of a <# #> delimited number conversion.
3009 static void hold(FICL_VM *pVM)
3011 FICL_STRING *sp;
3012 int i;
3013 #if FICL_ROBUST > 1
3014 vmCheckStack(pVM, 1, 0);
3015 #endif
3017 sp = PTRtoSTRING pVM->pad;
3018 i = POPINT();
3019 sp->text[sp->count++] = (char) i;
3020 return;
3024 ** SIGN CORE ( n -- )
3025 ** If n is negative, add a minus sign to the beginning of the pictured
3026 ** numeric output string. An ambiguous condition exists if SIGN
3027 ** executes outside of a <# #> delimited number conversion.
3029 static void sign(FICL_VM *pVM)
3031 FICL_STRING *sp;
3032 int i;
3033 #if FICL_ROBUST > 1
3034 vmCheckStack(pVM, 1, 0);
3035 #endif
3037 sp = PTRtoSTRING pVM->pad;
3038 i = POPINT();
3039 if (i < 0)
3040 sp->text[sp->count++] = '-';
3041 return;
3045 /**************************************************************************
3046 t o N u m b e r
3047 ** to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
3048 ** ud2 is the unsigned result of converting the characters within the
3049 ** string specified by c-addr1 u1 into digits, using the number in BASE,
3050 ** and adding each into ud1 after multiplying ud1 by the number in BASE.
3051 ** Conversion continues left-to-right until a character that is not
3052 ** convertible, including any + or -, is encountered or the string is
3053 ** entirely converted. c-addr2 is the location of the first unconverted
3054 ** character or the first character past the end of the string if the string
3055 ** was entirely converted. u2 is the number of unconverted characters in the
3056 ** string. An ambiguous condition exists if ud2 overflows during the
3057 ** conversion.
3058 **************************************************************************/
3059 static void toNumber(FICL_VM *pVM)
3061 FICL_UNS count;
3062 char *cp;
3063 DPUNS accum;
3064 FICL_UNS base = pVM->base;
3065 FICL_UNS ch;
3066 FICL_UNS digit;
3068 #if FICL_ROBUST > 1
3069 vmCheckStack(pVM,4,4);
3070 #endif
3072 count = POPUNS();
3073 cp = (char *)POPPTR();
3074 accum = u64Pop(pVM->pStack);
3076 for (ch = *cp; count > 0; ch = *++cp, count--)
3078 if (ch < '0')
3079 break;
3081 digit = ch - '0';
3083 if (digit > 9)
3084 digit = tolower(ch) - 'a' + 10;
3086 ** Note: following test also catches chars between 9 and a
3087 ** because 'digit' is unsigned!
3089 if (digit >= base)
3090 break;
3092 accum = m64Mac(accum, base, digit);
3095 u64Push(pVM->pStack, accum);
3096 PUSHPTR(cp);
3097 PUSHUNS(count);
3099 return;
3104 /**************************************************************************
3105 q u i t & a b o r t
3106 ** quit CORE ( -- ) ( R: i*x -- )
3107 ** Empty the return stack, store zero in SOURCE-ID if it is present, make
3108 ** the user input device the input source, and enter interpretation state.
3109 ** Do not display a message. Repeat the following:
3111 ** Accept a line from the input source into the input buffer, set >IN to
3112 ** zero, and interpret.
3113 ** Display the implementation-defined system prompt if in
3114 ** interpretation state, all processing has been completed, and no
3115 ** ambiguous condition exists.
3116 **************************************************************************/
3118 static void quit(FICL_VM *pVM)
3120 vmThrow(pVM, VM_QUIT);
3121 return;
3125 static void ficlAbort(FICL_VM *pVM)
3127 vmThrow(pVM, VM_ABORT);
3128 return;
3132 /**************************************************************************
3133 a c c e p t
3134 ** accept CORE ( c-addr +n1 -- +n2 )
3135 ** Receive a string of at most +n1 characters. An ambiguous condition
3136 ** exists if +n1 is zero or greater than 32,767. Display graphic characters
3137 ** as they are received. A program that depends on the presence or absence
3138 ** of non-graphic characters in the string has an environmental dependency.
3139 ** The editing functions, if any, that the system performs in order to
3140 ** construct the string are implementation-defined.
3142 ** (Although the standard text doesn't say so, I assume that the intent
3143 ** of 'accept' is to store the string at the address specified on
3144 ** the stack.)
3145 ** Implementation: if there's more text in the TIB, use it. Otherwise
3146 ** throw out for more text. Copy characters up to the max count into the
3147 ** address given, and return the number of actual characters copied.
3149 ** Note (sobral) this may not be the behavior you'd expect if you're
3150 ** trying to get user input at load time!
3151 **************************************************************************/
3152 static void accept(FICL_VM *pVM)
3154 FICL_UNS count, len;
3155 char *cp;
3156 char *pBuf, *pEnd;
3158 #if FICL_ROBUST > 1
3159 vmCheckStack(pVM,2,1);
3160 #endif
3162 pBuf = vmGetInBuf(pVM);
3163 pEnd = vmGetInBufEnd(pVM);
3164 len = pEnd - pBuf;
3165 if (len == 0)
3166 vmThrow(pVM, VM_RESTART);
3169 ** Now we have something in the text buffer - use it
3171 count = stackPopINT(pVM->pStack);
3172 cp = stackPopPtr(pVM->pStack);
3174 len = (count < len) ? count : len;
3175 strncpy(cp, vmGetInBuf(pVM), len);
3176 pBuf += len;
3177 vmUpdateTib(pVM, pBuf);
3178 PUSHINT(len);
3180 return;
3184 /**************************************************************************
3185 a l i g n
3186 ** 6.1.0705 ALIGN CORE ( -- )
3187 ** If the data-space pointer is not aligned, reserve enough space to
3188 ** align it.
3189 **************************************************************************/
3190 static void align(FICL_VM *pVM)
3192 FICL_DICT *dp = vmGetDict(pVM);
3193 IGNORE(pVM);
3194 dictAlign(dp);
3195 return;
3199 /**************************************************************************
3200 a l i g n e d
3202 **************************************************************************/
3203 static void aligned(FICL_VM *pVM)
3205 void *addr;
3206 #if FICL_ROBUST > 1
3207 vmCheckStack(pVM,1,1);
3208 #endif
3210 addr = POPPTR();
3211 PUSHPTR(alignPtr(addr));
3212 return;
3216 /**************************************************************************
3217 b e g i n & f r i e n d s
3218 ** Indefinite loop control structures
3219 ** A.6.1.0760 BEGIN
3220 ** Typical use:
3221 ** : X ... BEGIN ... test UNTIL ;
3222 ** or
3223 ** : X ... BEGIN ... test WHILE ... REPEAT ;
3224 **************************************************************************/
3225 static void beginCoIm(FICL_VM *pVM)
3227 FICL_DICT *dp = vmGetDict(pVM);
3228 markBranch(dp, pVM, destTag);
3229 return;
3232 static void untilCoIm(FICL_VM *pVM)
3234 FICL_DICT *dp = vmGetDict(pVM);
3236 assert(pVM->pSys->pBranch0);
3238 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranch0));
3239 resolveBackBranch(dp, pVM, destTag);
3240 return;
3243 static void whileCoIm(FICL_VM *pVM)
3245 FICL_DICT *dp = vmGetDict(pVM);
3247 assert(pVM->pSys->pBranch0);
3249 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranch0));
3250 markBranch(dp, pVM, origTag);
3251 twoSwap(pVM);
3252 dictAppendUNS(dp, 1);
3253 return;
3256 static void repeatCoIm(FICL_VM *pVM)
3258 FICL_DICT *dp = vmGetDict(pVM);
3260 assert(pVM->pSys->pBranchParen);
3261 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranchParen));
3263 /* expect "begin" branch marker */
3264 resolveBackBranch(dp, pVM, destTag);
3265 /* expect "while" branch marker */
3266 resolveForwardBranch(dp, pVM, origTag);
3267 return;
3271 static void againCoIm(FICL_VM *pVM)
3273 FICL_DICT *dp = vmGetDict(pVM);
3275 assert(pVM->pSys->pBranchParen);
3276 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pBranchParen));
3278 /* expect "begin" branch marker */
3279 resolveBackBranch(dp, pVM, destTag);
3280 return;
3284 /**************************************************************************
3285 c h a r & f r i e n d s
3286 ** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
3287 ** Skip leading space delimiters. Parse name delimited by a space.
3288 ** Put the value of its first character onto the stack.
3290 ** bracket-char CORE
3291 ** Interpretation: Interpretation semantics for this word are undefined.
3292 ** Compilation: ( "<spaces>name" -- )
3293 ** Skip leading space delimiters. Parse name delimited by a space.
3294 ** Append the run-time semantics given below to the current definition.
3295 ** Run-time: ( -- char )
3296 ** Place char, the value of the first character of name, on the stack.
3297 **************************************************************************/
3298 static void ficlChar(FICL_VM *pVM)
3300 STRINGINFO si;
3301 #if FICL_ROBUST > 1
3302 vmCheckStack(pVM,0,1);
3303 #endif
3305 si = vmGetWord(pVM);
3306 PUSHUNS((FICL_UNS)(si.cp[0]));
3307 return;
3310 static void charCoIm(FICL_VM *pVM)
3312 ficlChar(pVM);
3313 literalIm(pVM);
3314 return;
3317 /**************************************************************************
3318 c h a r P l u s
3319 ** char-plus CORE ( c-addr1 -- c-addr2 )
3320 ** Add the size in address units of a character to c-addr1, giving c-addr2.
3321 **************************************************************************/
3322 static void charPlus(FICL_VM *pVM)
3324 char *cp;
3325 #if FICL_ROBUST > 1
3326 vmCheckStack(pVM,1,1);
3327 #endif
3329 cp = POPPTR();
3330 PUSHPTR(cp + 1);
3331 return;
3334 /**************************************************************************
3335 c h a r s
3336 ** chars CORE ( n1 -- n2 )
3337 ** n2 is the size in address units of n1 characters.
3338 ** For most processors, this function can be a no-op. To guarantee
3339 ** portability, we'll multiply by sizeof (char).
3340 **************************************************************************/
3341 #if defined (_M_IX86)
3342 #pragma warning(disable: 4127)
3343 #endif
3344 static void ficlChars(FICL_VM *pVM)
3346 if (sizeof (char) > 1)
3348 FICL_INT i;
3349 #if FICL_ROBUST > 1
3350 vmCheckStack(pVM,1,1);
3351 #endif
3352 i = POPINT();
3353 PUSHINT(i * sizeof (char));
3355 /* otherwise no-op! */
3356 return;
3358 #if defined (_M_IX86)
3359 #pragma warning(default: 4127)
3360 #endif
3363 /**************************************************************************
3364 c o u n t
3365 ** COUNT CORE ( c-addr1 -- c-addr2 u )
3366 ** Return the character string specification for the counted string stored
3367 ** at c-addr1. c-addr2 is the address of the first character after c-addr1.
3368 ** u is the contents of the character at c-addr1, which is the length in
3369 ** characters of the string at c-addr2.
3370 **************************************************************************/
3371 static void count(FICL_VM *pVM)
3373 FICL_STRING *sp;
3374 #if FICL_ROBUST > 1
3375 vmCheckStack(pVM,1,2);
3376 #endif
3378 sp = POPPTR();
3379 PUSHPTR(sp->text);
3380 PUSHUNS(sp->count);
3381 return;
3384 /**************************************************************************
3385 e n v i r o n m e n t ?
3386 ** environment-query CORE ( c-addr u -- false | i*x true )
3387 ** c-addr is the address of a character string and u is the string's
3388 ** character count. u may have a value in the range from zero to an
3389 ** implementation-defined maximum which shall not be less than 31. The
3390 ** character string should contain a keyword from 3.2.6 Environmental
3391 ** queries or the optional word sets to be checked for correspondence
3392 ** with an attribute of the present environment. If the system treats the
3393 ** attribute as unknown, the returned flag is false; otherwise, the flag
3394 ** is true and the i*x returned is of the type specified in the table for
3395 ** the attribute queried.
3396 **************************************************************************/
3397 static void environmentQ(FICL_VM *pVM)
3399 FICL_DICT *envp;
3400 FICL_WORD *pFW;
3401 STRINGINFO si;
3402 #if FICL_ROBUST > 1
3403 vmCheckStack(pVM,2,1);
3404 #endif
3406 envp = pVM->pSys->envp;
3407 si.count = (FICL_COUNT)stackPopUNS(pVM->pStack);
3408 si.cp = stackPopPtr(pVM->pStack);
3410 pFW = dictLookup(envp, si);
3412 if (pFW != NULL)
3414 vmExecute(pVM, pFW);
3415 PUSHINT(FICL_TRUE);
3417 else
3419 PUSHINT(FICL_FALSE);
3421 return;
3424 /**************************************************************************
3425 e v a l u a t e
3426 ** EVALUATE CORE ( i*x c-addr u -- j*x )
3427 ** Save the current input source specification. Store minus-one (-1) in
3428 ** SOURCE-ID if it is present. Make the string described by c-addr and u
3429 ** both the input source and input buffer, set >IN to zero, and interpret.
3430 ** When the parse area is empty, restore the prior input source
3431 ** specification. Other stack effects are due to the words EVALUATEd.
3433 **************************************************************************/
3434 static void evaluate(FICL_VM *pVM)
3436 FICL_UNS count;
3437 char *cp;
3438 CELL id;
3439 int result;
3440 #if FICL_ROBUST > 1
3441 vmCheckStack(pVM,2,0);
3442 #endif
3444 count = POPUNS();
3445 cp = POPPTR();
3447 IGNORE(count);
3448 id = pVM->sourceID;
3449 pVM->sourceID.i = -1;
3450 result = ficlExecC(pVM, cp, count);
3451 pVM->sourceID = id;
3452 if (result != VM_OUTOFTEXT)
3453 vmThrow(pVM, result);
3455 return;
3459 /**************************************************************************
3460 s t r i n g q u o t e
3461 ** Interpreting: get string delimited by a quote from the input stream,
3462 ** copy to a scratch area, and put its count and address on the stack.
3463 ** Compiling: compile code to push the address and count of a string
3464 ** literal, compile the string from the input stream, and align the dict
3465 ** pointer.
3466 **************************************************************************/
3467 static void stringQuoteIm(FICL_VM *pVM)
3469 FICL_DICT *dp = vmGetDict(pVM);
3471 if (pVM->state == INTERPRET)
3473 FICL_STRING *sp = (FICL_STRING *) dp->here;
3474 vmGetString(pVM, sp, '\"');
3475 PUSHPTR(sp->text);
3476 PUSHUNS(sp->count);
3478 else /* COMPILE state */
3480 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pStringLit));
3481 dp->here = PTRtoCELL vmGetString(pVM, (FICL_STRING *)dp->here, '\"');
3482 dictAlign(dp);
3485 return;
3489 /**************************************************************************
3490 t y p e
3491 ** Pop count and char address from stack and print the designated string.
3492 **************************************************************************/
3493 static void type(FICL_VM *pVM)
3495 FICL_UNS count = stackPopUNS(pVM->pStack);
3496 char *cp = stackPopPtr(pVM->pStack);
3497 char *pDest = (char *)ficlMalloc(count + 1);
3500 ** Since we don't have an output primitive for a counted string
3501 ** (oops), make sure the string is null terminated. If not, copy
3502 ** and terminate it.
3504 if (!pDest)
3505 vmThrowErr(pVM, "Error: out of memory");
3507 strncpy(pDest, cp, count);
3508 pDest[count] = '\0';
3510 vmTextOut(pVM, pDest, 0);
3512 ficlFree(pDest);
3513 return;
3516 /**************************************************************************
3517 w o r d
3518 ** word CORE ( char "<chars>ccc<char>" -- c-addr )
3519 ** Skip leading delimiters. Parse characters ccc delimited by char. An
3520 ** ambiguous condition exists if the length of the parsed string is greater
3521 ** than the implementation-defined length of a counted string.
3523 ** c-addr is the address of a transient region containing the parsed word
3524 ** as a counted string. If the parse area was empty or contained no
3525 ** characters other than the delimiter, the resulting string has a zero
3526 ** length. A space, not included in the length, follows the string. A
3527 ** program may replace characters within the string.
3528 ** NOTE! Ficl also NULL-terminates the dest string.
3529 **************************************************************************/
3530 static void ficlWord(FICL_VM *pVM)
3532 FICL_STRING *sp;
3533 char delim;
3534 STRINGINFO si;
3535 #if FICL_ROBUST > 1
3536 vmCheckStack(pVM,1,1);
3537 #endif
3539 sp = (FICL_STRING *)pVM->pad;
3540 delim = (char)POPINT();
3541 si = vmParseStringEx(pVM, delim, 1);
3543 if (SI_COUNT(si) > nPAD-1)
3544 SI_SETLEN(si, nPAD-1);
3546 sp->count = (FICL_COUNT)SI_COUNT(si);
3547 strncpy(sp->text, SI_PTR(si), SI_COUNT(si));
3548 /*#$-GUY CHANGE: I added this.-$#*/
3549 sp->text[sp->count] = 0;
3550 strcat(sp->text, " ");
3552 PUSHPTR(sp);
3553 return;
3557 /**************************************************************************
3558 p a r s e - w o r d
3559 ** ficl PARSE-WORD ( <spaces>name -- c-addr u )
3560 ** Skip leading spaces and parse name delimited by a space. c-addr is the
3561 ** address within the input buffer and u is the length of the selected
3562 ** string. If the parse area is empty, the resulting string has a zero length.
3563 **************************************************************************/
3564 static void parseNoCopy(FICL_VM *pVM)
3566 STRINGINFO si;
3567 #if FICL_ROBUST > 1
3568 vmCheckStack(pVM,0,2);
3569 #endif
3571 si = vmGetWord0(pVM);
3572 PUSHPTR(SI_PTR(si));
3573 PUSHUNS(SI_COUNT(si));
3574 return;
3578 /**************************************************************************
3579 p a r s e
3580 ** CORE EXT ( char "ccc<char>" -- c-addr u )
3581 ** Parse ccc delimited by the delimiter char.
3582 ** c-addr is the address (within the input buffer) and u is the length of
3583 ** the parsed string. If the parse area was empty, the resulting string has
3584 ** a zero length.
3585 ** NOTE! PARSE differs from WORD: it does not skip leading delimiters.
3586 **************************************************************************/
3587 static void parse(FICL_VM *pVM)
3589 STRINGINFO si;
3590 char delim;
3592 #if FICL_ROBUST > 1
3593 vmCheckStack(pVM,1,2);
3594 #endif
3596 delim = (char)POPINT();
3598 si = vmParseStringEx(pVM, delim, 0);
3599 PUSHPTR(SI_PTR(si));
3600 PUSHUNS(SI_COUNT(si));
3601 return;
3605 /**************************************************************************
3606 f i l l
3607 ** CORE ( c-addr u char -- )
3608 ** If u is greater than zero, store char in each of u consecutive
3609 ** characters of memory beginning at c-addr.
3610 **************************************************************************/
3611 static void fill(FICL_VM *pVM)
3613 char ch;
3614 FICL_UNS u;
3615 char *cp;
3616 #if FICL_ROBUST > 1
3617 vmCheckStack(pVM,3,0);
3618 #endif
3619 ch = (char)POPINT();
3620 u = POPUNS();
3621 cp = (char *)POPPTR();
3623 while (u > 0)
3625 *cp++ = ch;
3626 u--;
3628 return;
3632 /**************************************************************************
3633 f i n d
3634 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3635 ** Find the definition named in the counted string at c-addr. If the
3636 ** definition is not found, return c-addr and zero. If the definition is
3637 ** found, return its execution token xt. If the definition is immediate,
3638 ** also return one (1), otherwise also return minus-one (-1). For a given
3639 ** string, the values returned by FIND while compiling may differ from
3640 ** those returned while not compiling.
3641 **************************************************************************/
3642 static void do_find(FICL_VM *pVM, STRINGINFO si, void *returnForFailure)
3644 FICL_WORD *pFW;
3646 pFW = dictLookup(vmGetDict(pVM), si);
3647 if (pFW)
3649 PUSHPTR(pFW);
3650 PUSHINT((wordIsImmediate(pFW) ? 1 : -1));
3652 else
3654 PUSHPTR(returnForFailure);
3655 PUSHUNS(0);
3657 return;
3662 /**************************************************************************
3663 f i n d
3664 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3665 ** Find the definition named in the counted string at c-addr. If the
3666 ** definition is not found, return c-addr and zero. If the definition is
3667 ** found, return its execution token xt. If the definition is immediate,
3668 ** also return one (1), otherwise also return minus-one (-1). For a given
3669 ** string, the values returned by FIND while compiling may differ from
3670 ** those returned while not compiling.
3671 **************************************************************************/
3672 static void cFind(FICL_VM *pVM)
3674 FICL_STRING *sp;
3675 STRINGINFO si;
3677 #if FICL_ROBUST > 1
3678 vmCheckStack(pVM,1,2);
3679 #endif
3680 sp = POPPTR();
3681 SI_PFS(si, sp);
3682 do_find(pVM, si, sp);
3687 /**************************************************************************
3688 s f i n d
3689 ** FICL ( c-addr u -- 0 0 | xt 1 | xt -1 )
3690 ** Like FIND, but takes "c-addr u" for the string.
3691 **************************************************************************/
3692 static void sFind(FICL_VM *pVM)
3694 STRINGINFO si;
3696 #if FICL_ROBUST > 1
3697 vmCheckStack(pVM,2,2);
3698 #endif
3700 si.count = stackPopINT(pVM->pStack);
3701 si.cp = stackPopPtr(pVM->pStack);
3703 do_find(pVM, si, NULL);
3708 /**************************************************************************
3709 f m S l a s h M o d
3710 ** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
3711 ** Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
3712 ** Input and output stack arguments are signed. An ambiguous condition
3713 ** exists if n1 is zero or if the quotient lies outside the range of a
3714 ** single-cell signed integer.
3715 **************************************************************************/
3716 static void fmSlashMod(FICL_VM *pVM)
3718 DPINT d1;
3719 FICL_INT n1;
3720 INTQR qr;
3721 #if FICL_ROBUST > 1
3722 vmCheckStack(pVM,3,2);
3723 #endif
3725 n1 = POPINT();
3726 d1 = i64Pop(pVM->pStack);
3727 qr = m64FlooredDivI(d1, n1);
3728 PUSHINT(qr.rem);
3729 PUSHINT(qr.quot);
3730 return;
3734 /**************************************************************************
3735 s m S l a s h R e m
3736 ** s-m-slash-rem CORE ( d1 n1 -- n2 n3 )
3737 ** Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
3738 ** Input and output stack arguments are signed. An ambiguous condition
3739 ** exists if n1 is zero or if the quotient lies outside the range of a
3740 ** single-cell signed integer.
3741 **************************************************************************/
3742 static void smSlashRem(FICL_VM *pVM)
3744 DPINT d1;
3745 FICL_INT n1;
3746 INTQR qr;
3747 #if FICL_ROBUST > 1
3748 vmCheckStack(pVM,3,2);
3749 #endif
3751 n1 = POPINT();
3752 d1 = i64Pop(pVM->pStack);
3753 qr = m64SymmetricDivI(d1, n1);
3754 PUSHINT(qr.rem);
3755 PUSHINT(qr.quot);
3756 return;
3760 static void ficlMod(FICL_VM *pVM)
3762 DPINT d1;
3763 FICL_INT n1;
3764 INTQR qr;
3765 #if FICL_ROBUST > 1
3766 vmCheckStack(pVM,2,1);
3767 #endif
3769 n1 = POPINT();
3770 d1.lo = POPINT();
3771 i64Extend(d1);
3772 qr = m64SymmetricDivI(d1, n1);
3773 PUSHINT(qr.rem);
3774 return;
3778 /**************************************************************************
3779 u m S l a s h M o d
3780 ** u-m-slash-mod CORE ( ud u1 -- u2 u3 )
3781 ** Divide ud by u1, giving the quotient u3 and the remainder u2.
3782 ** All values and arithmetic are unsigned. An ambiguous condition
3783 ** exists if u1 is zero or if the quotient lies outside the range of a
3784 ** single-cell unsigned integer.
3785 *************************************************************************/
3786 static void umSlashMod(FICL_VM *pVM)
3788 DPUNS ud;
3789 FICL_UNS u1;
3790 UNSQR qr;
3792 u1 = stackPopUNS(pVM->pStack);
3793 ud = u64Pop(pVM->pStack);
3794 qr = ficlLongDiv(ud, u1);
3795 PUSHUNS(qr.rem);
3796 PUSHUNS(qr.quot);
3797 return;
3801 /**************************************************************************
3802 l s h i f t
3803 ** l-shift CORE ( x1 u -- x2 )
3804 ** Perform a logical left shift of u bit-places on x1, giving x2.
3805 ** Put zeroes into the least significant bits vacated by the shift.
3806 ** An ambiguous condition exists if u is greater than or equal to the
3807 ** number of bits in a cell.
3809 ** r-shift CORE ( x1 u -- x2 )
3810 ** Perform a logical right shift of u bit-places on x1, giving x2.
3811 ** Put zeroes into the most significant bits vacated by the shift. An
3812 ** ambiguous condition exists if u is greater than or equal to the
3813 ** number of bits in a cell.
3814 **************************************************************************/
3815 static void lshift(FICL_VM *pVM)
3817 FICL_UNS nBits;
3818 FICL_UNS x1;
3819 #if FICL_ROBUST > 1
3820 vmCheckStack(pVM,2,1);
3821 #endif
3823 nBits = POPUNS();
3824 x1 = POPUNS();
3825 PUSHUNS(x1 << nBits);
3826 return;
3830 static void rshift(FICL_VM *pVM)
3832 FICL_UNS nBits;
3833 FICL_UNS x1;
3834 #if FICL_ROBUST > 1
3835 vmCheckStack(pVM,2,1);
3836 #endif
3838 nBits = POPUNS();
3839 x1 = POPUNS();
3841 PUSHUNS(x1 >> nBits);
3842 return;
3846 /**************************************************************************
3847 m S t a r
3848 ** m-star CORE ( n1 n2 -- d )
3849 ** d is the signed product of n1 times n2.
3850 **************************************************************************/
3851 static void mStar(FICL_VM *pVM)
3853 FICL_INT n2;
3854 FICL_INT n1;
3855 DPINT d;
3856 #if FICL_ROBUST > 1
3857 vmCheckStack(pVM,2,2);
3858 #endif
3860 n2 = POPINT();
3861 n1 = POPINT();
3863 d = m64MulI(n1, n2);
3864 i64Push(pVM->pStack, d);
3865 return;
3869 static void umStar(FICL_VM *pVM)
3871 FICL_UNS u2;
3872 FICL_UNS u1;
3873 DPUNS ud;
3874 #if FICL_ROBUST > 1
3875 vmCheckStack(pVM,2,2);
3876 #endif
3878 u2 = POPUNS();
3879 u1 = POPUNS();
3881 ud = ficlLongMul(u1, u2);
3882 u64Push(pVM->pStack, ud);
3883 return;
3887 /**************************************************************************
3888 m a x & m i n
3890 **************************************************************************/
3891 static void ficlMax(FICL_VM *pVM)
3893 FICL_INT n2;
3894 FICL_INT n1;
3895 #if FICL_ROBUST > 1
3896 vmCheckStack(pVM,2,1);
3897 #endif
3899 n2 = POPINT();
3900 n1 = POPINT();
3902 PUSHINT((n1 > n2) ? n1 : n2);
3903 return;
3906 static void ficlMin(FICL_VM *pVM)
3908 FICL_INT n2;
3909 FICL_INT n1;
3910 #if FICL_ROBUST > 1
3911 vmCheckStack(pVM,2,1);
3912 #endif
3914 n2 = POPINT();
3915 n1 = POPINT();
3917 PUSHINT((n1 < n2) ? n1 : n2);
3918 return;
3922 /**************************************************************************
3923 m o v e
3924 ** CORE ( addr1 addr2 u -- )
3925 ** If u is greater than zero, copy the contents of u consecutive address
3926 ** units at addr1 to the u consecutive address units at addr2. After MOVE
3927 ** completes, the u consecutive address units at addr2 contain exactly
3928 ** what the u consecutive address units at addr1 contained before the move.
3929 ** NOTE! This implementation assumes that a char is the same size as
3930 ** an address unit.
3931 **************************************************************************/
3932 static void move(FICL_VM *pVM)
3934 FICL_UNS u;
3935 char *addr2;
3936 char *addr1;
3937 #if FICL_ROBUST > 1
3938 vmCheckStack(pVM,3,0);
3939 #endif
3941 u = POPUNS();
3942 addr2 = POPPTR();
3943 addr1 = POPPTR();
3945 if (u == 0)
3946 return;
3948 ** Do the copy carefully, so as to be
3949 ** correct even if the two ranges overlap
3951 if (addr1 >= addr2)
3953 for (; u > 0; u--)
3954 *addr2++ = *addr1++;
3956 else
3958 addr2 += u-1;
3959 addr1 += u-1;
3960 for (; u > 0; u--)
3961 *addr2-- = *addr1--;
3964 return;
3968 /**************************************************************************
3969 r e c u r s e
3971 **************************************************************************/
3972 static void recurseCoIm(FICL_VM *pVM)
3974 FICL_DICT *pDict = vmGetDict(pVM);
3976 IGNORE(pVM);
3977 dictAppendCell(pDict, LVALUEtoCELL(pDict->smudge));
3978 return;
3982 /**************************************************************************
3983 s t o d
3984 ** s-to-d CORE ( n -- d )
3985 ** Convert the number n to the double-cell number d with the same
3986 ** numerical value.
3987 **************************************************************************/
3988 static void sToD(FICL_VM *pVM)
3990 FICL_INT s;
3991 #if FICL_ROBUST > 1
3992 vmCheckStack(pVM,1,2);
3993 #endif
3995 s = POPINT();
3997 /* sign extend to 64 bits.. */
3998 PUSHINT(s);
3999 PUSHINT((s < 0) ? -1 : 0);
4000 return;
4004 /**************************************************************************
4005 s o u r c e
4006 ** CORE ( -- c-addr u )
4007 ** c-addr is the address of, and u is the number of characters in, the
4008 ** input buffer.
4009 **************************************************************************/
4010 static void source(FICL_VM *pVM)
4012 #if FICL_ROBUST > 1
4013 vmCheckStack(pVM,0,2);
4014 #endif
4015 PUSHPTR(pVM->tib.cp);
4016 PUSHINT(vmGetInBufLen(pVM));
4017 return;
4021 /**************************************************************************
4022 v e r s i o n
4023 ** non-standard...
4024 **************************************************************************/
4025 static void ficlVersion(FICL_VM *pVM)
4027 vmTextOut(pVM, "ficl Version " FICL_VER, 1);
4028 return;
4032 /**************************************************************************
4033 t o I n
4034 ** to-in CORE
4035 **************************************************************************/
4036 static void toIn(FICL_VM *pVM)
4038 #if FICL_ROBUST > 1
4039 vmCheckStack(pVM,0,1);
4040 #endif
4041 PUSHPTR(&pVM->tib.index);
4042 return;
4046 /**************************************************************************
4047 c o l o n N o N a m e
4048 ** CORE EXT ( C: -- colon-sys ) ( S: -- xt )
4049 ** Create an unnamed colon definition and push its address.
4050 ** Change state to compile.
4051 **************************************************************************/
4052 static void colonNoName(FICL_VM *pVM)
4054 FICL_DICT *dp = vmGetDict(pVM);
4055 FICL_WORD *pFW;
4056 STRINGINFO si;
4058 SI_SETLEN(si, 0);
4059 SI_SETPTR(si, NULL);
4061 pVM->state = COMPILE;
4062 pFW = dictAppendWord2(dp, si, colonParen, FW_DEFAULT | FW_SMUDGE);
4063 PUSHPTR(pFW);
4064 markControlTag(pVM, colonTag);
4065 return;
4069 /**************************************************************************
4070 u s e r V a r i a b l e
4071 ** user ( u -- ) "<spaces>name"
4072 ** Get a name from the input stream and create a user variable
4073 ** with the name and the index supplied. The run-time effect
4074 ** of a user variable is to push the address of the indexed cell
4075 ** in the running vm's user array.
4077 ** User variables are vm local cells. Each vm has an array of
4078 ** FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
4079 ** Ficl's user facility is implemented with two primitives,
4080 ** "user" and "(user)", a variable ("nUser") (in softcore.c) that
4081 ** holds the index of the next free user cell, and a redefinition
4082 ** (also in softcore) of "user" that defines a user word and increments
4083 ** nUser.
4084 **************************************************************************/
4085 #if FICL_WANT_USER
4086 static void userParen(FICL_VM *pVM)
4088 FICL_INT i = pVM->runningWord->param[0].i;
4089 PUSHPTR(&pVM->user[i]);
4090 return;
4094 static void userVariable(FICL_VM *pVM)
4096 FICL_DICT *dp = vmGetDict(pVM);
4097 STRINGINFO si = vmGetWord(pVM);
4098 CELL c;
4100 c = stackPop(pVM->pStack);
4101 if (c.i >= FICL_USER_CELLS)
4103 vmThrowErr(pVM, "Error - out of user space");
4106 dictAppendWord2(dp, si, userParen, FW_DEFAULT);
4107 dictAppendCell(dp, c);
4108 return;
4110 #endif
4113 /**************************************************************************
4114 t o V a l u e
4115 ** CORE EXT
4116 ** Interpretation: ( x "<spaces>name" -- )
4117 ** Skip leading spaces and parse name delimited by a space. Store x in
4118 ** name. An ambiguous condition exists if name was not defined by VALUE.
4119 ** NOTE: In ficl, VALUE is an alias of CONSTANT
4120 **************************************************************************/
4121 static void toValue(FICL_VM *pVM)
4123 STRINGINFO si = vmGetWord(pVM);
4124 FICL_DICT *dp = vmGetDict(pVM);
4125 FICL_WORD *pFW;
4127 #if FICL_WANT_LOCALS
4128 if ((pVM->pSys->nLocals > 0) && (pVM->state == COMPILE))
4130 FICL_DICT *pLoc = ficlGetLoc(pVM->pSys);
4131 pFW = dictLookup(pLoc, si);
4132 if (pFW && (pFW->code == doLocalIm))
4134 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pToLocalParen));
4135 dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
4136 return;
4138 else if (pFW && pFW->code == do2LocalIm)
4140 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pTo2LocalParen));
4141 dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
4142 return;
4145 #endif
4147 assert(pVM->pSys->pStore);
4149 pFW = dictLookup(dp, si);
4150 if (!pFW)
4152 int i = SI_COUNT(si);
4153 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
4156 if (pVM->state == INTERPRET)
4157 pFW->param[0] = stackPop(pVM->pStack);
4158 else /* compile code to store to word's param */
4160 PUSHPTR(&pFW->param[0]);
4161 literalIm(pVM);
4162 dictAppendCell(dp, LVALUEtoCELL(pVM->pSys->pStore));
4164 return;
4168 #if FICL_WANT_LOCALS
4169 /**************************************************************************
4170 l i n k P a r e n
4171 ** ( -- )
4172 ** Link a frame on the return stack, reserving nCells of space for
4173 ** locals - the value of nCells is the next cell in the instruction
4174 ** stream.
4175 **************************************************************************/
4176 static void linkParen(FICL_VM *pVM)
4178 FICL_INT nLink = *(FICL_INT *)(pVM->ip);
4179 vmBranchRelative(pVM, 1);
4180 stackLink(pVM->rStack, nLink);
4181 return;
4185 static void unlinkParen(FICL_VM *pVM)
4187 stackUnlink(pVM->rStack);
4188 return;
4192 /**************************************************************************
4193 d o L o c a l I m
4194 ** Immediate - cfa of a local while compiling - when executed, compiles
4195 ** code to fetch the value of a local given the local's index in the
4196 ** word's pfa
4197 **************************************************************************/
4198 static void getLocalParen(FICL_VM *pVM)
4200 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
4201 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
4202 return;
4206 static void toLocalParen(FICL_VM *pVM)
4208 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
4209 pVM->rStack->pFrame[nLocal] = stackPop(pVM->pStack);
4210 return;
4214 static void getLocal0(FICL_VM *pVM)
4216 stackPush(pVM->pStack, pVM->rStack->pFrame[0]);
4217 return;
4221 static void toLocal0(FICL_VM *pVM)
4223 pVM->rStack->pFrame[0] = stackPop(pVM->pStack);
4224 return;
4228 static void getLocal1(FICL_VM *pVM)
4230 stackPush(pVM->pStack, pVM->rStack->pFrame[1]);
4231 return;
4235 static void toLocal1(FICL_VM *pVM)
4237 pVM->rStack->pFrame[1] = stackPop(pVM->pStack);
4238 return;
4243 ** Each local is recorded in a private locals dictionary as a
4244 ** word that does doLocalIm at runtime. DoLocalIm compiles code
4245 ** into the client definition to fetch the value of the
4246 ** corresponding local variable from the return stack.
4247 ** The private dictionary gets initialized at the end of each block
4248 ** that uses locals (in ; and does> for example).
4250 static void doLocalIm(FICL_VM *pVM)
4252 FICL_DICT *pDict = vmGetDict(pVM);
4253 FICL_INT nLocal = pVM->runningWord->param[0].i;
4255 if (pVM->state == INTERPRET)
4257 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
4259 else
4262 if (nLocal == 0)
4264 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pGetLocal0));
4266 else if (nLocal == 1)
4268 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pGetLocal1));
4270 else
4272 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pGetLocalParen));
4273 dictAppendCell(pDict, LVALUEtoCELL(nLocal));
4276 return;
4280 /**************************************************************************
4281 l o c a l P a r e n
4282 ** paren-local-paren LOCAL
4283 ** Interpretation: Interpretation semantics for this word are undefined.
4284 ** Execution: ( c-addr u -- )
4285 ** When executed during compilation, (LOCAL) passes a message to the
4286 ** system that has one of two meanings. If u is non-zero,
4287 ** the message identifies a new local whose definition name is given by
4288 ** the string of characters identified by c-addr u. If u is zero,
4289 ** the message is last local and c-addr has no significance.
4291 ** The result of executing (LOCAL) during compilation of a definition is
4292 ** to create a set of named local identifiers, each of which is
4293 ** a definition name, that only have execution semantics within the scope
4294 ** of that definition's source.
4296 ** local Execution: ( -- x )
4298 ** Push the local's value, x, onto the stack. The local's value is
4299 ** initialized as described in 13.3.3 Processing locals and may be
4300 ** changed by preceding the local's name with TO. An ambiguous condition
4301 ** exists when local is executed while in interpretation state.
4302 **************************************************************************/
4303 static void localParen(FICL_VM *pVM)
4305 FICL_DICT *pDict;
4306 STRINGINFO si;
4307 #if FICL_ROBUST > 1
4308 vmCheckStack(pVM,2,0);
4309 #endif
4311 pDict = vmGetDict(pVM);
4312 SI_SETLEN(si, POPUNS());
4313 SI_SETPTR(si, (char *)POPPTR());
4315 if (SI_COUNT(si) > 0)
4316 { /* add a local to the **locals** dict and update nLocals */
4317 FICL_DICT *pLoc = ficlGetLoc(pVM->pSys);
4318 if (pVM->pSys->nLocals >= FICL_MAX_LOCALS)
4320 vmThrowErr(pVM, "Error: out of local space");
4323 dictAppendWord2(pLoc, si, doLocalIm, FW_COMPIMMED);
4324 dictAppendCell(pLoc, LVALUEtoCELL(pVM->pSys->nLocals));
4326 if (pVM->pSys->nLocals == 0)
4327 { /* compile code to create a local stack frame */
4328 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pLinkParen));
4329 /* save location in dictionary for #locals */
4330 pVM->pSys->pMarkLocals = pDict->here;
4331 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->nLocals));
4332 /* compile code to initialize first local */
4333 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pToLocal0));
4335 else if (pVM->pSys->nLocals == 1)
4337 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pToLocal1));
4339 else
4341 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pToLocalParen));
4342 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->nLocals));
4345 (pVM->pSys->nLocals)++;
4347 else if (pVM->pSys->nLocals > 0)
4348 { /* write nLocals to (link) param area in dictionary */
4349 *(FICL_INT *)(pVM->pSys->pMarkLocals) = pVM->pSys->nLocals;
4352 return;
4356 static void get2LocalParen(FICL_VM *pVM)
4358 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
4359 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
4360 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
4361 return;
4365 static void do2LocalIm(FICL_VM *pVM)
4367 FICL_DICT *pDict = vmGetDict(pVM);
4368 FICL_INT nLocal = pVM->runningWord->param[0].i;
4370 if (pVM->state == INTERPRET)
4372 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
4373 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
4375 else
4377 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pGet2LocalParen));
4378 dictAppendCell(pDict, LVALUEtoCELL(nLocal));
4380 return;
4384 static void to2LocalParen(FICL_VM *pVM)
4386 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
4387 pVM->rStack->pFrame[nLocal+1] = stackPop(pVM->pStack);
4388 pVM->rStack->pFrame[nLocal] = stackPop(pVM->pStack);
4389 return;
4393 static void twoLocalParen(FICL_VM *pVM)
4395 FICL_DICT *pDict = vmGetDict(pVM);
4396 STRINGINFO si;
4397 SI_SETLEN(si, stackPopUNS(pVM->pStack));
4398 SI_SETPTR(si, (char *)stackPopPtr(pVM->pStack));
4400 if (SI_COUNT(si) > 0)
4401 { /* add a local to the **locals** dict and update nLocals */
4402 FICL_DICT *pLoc = ficlGetLoc(pVM->pSys);
4403 if (pVM->pSys->nLocals >= FICL_MAX_LOCALS)
4405 vmThrowErr(pVM, "Error: out of local space");
4408 dictAppendWord2(pLoc, si, do2LocalIm, FW_COMPIMMED);
4409 dictAppendCell(pLoc, LVALUEtoCELL(pVM->pSys->nLocals));
4411 if (pVM->pSys->nLocals == 0)
4412 { /* compile code to create a local stack frame */
4413 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pLinkParen));
4414 /* save location in dictionary for #locals */
4415 pVM->pSys->pMarkLocals = pDict->here;
4416 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->nLocals));
4419 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->pTo2LocalParen));
4420 dictAppendCell(pDict, LVALUEtoCELL(pVM->pSys->nLocals));
4422 pVM->pSys->nLocals += 2;
4424 else if (pVM->pSys->nLocals > 0)
4425 { /* write nLocals to (link) param area in dictionary */
4426 *(FICL_INT *)(pVM->pSys->pMarkLocals) = pVM->pSys->nLocals;
4429 return;
4433 #endif
4434 /**************************************************************************
4435 c o m p a r e
4436 ** STRING ( c-addr1 u1 c-addr2 u2 -- n )
4437 ** Compare the string specified by c-addr1 u1 to the string specified by
4438 ** c-addr2 u2. The strings are compared, beginning at the given addresses,
4439 ** character by character, up to the length of the shorter string or until a
4440 ** difference is found. If the two strings are identical, n is zero. If the two
4441 ** strings are identical up to the length of the shorter string, n is minus-one
4442 ** (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not
4443 ** identical up to the length of the shorter string, n is minus-one (-1) if the
4444 ** first non-matching character in the string specified by c-addr1 u1 has a
4445 ** lesser numeric value than the corresponding character in the string specified
4446 ** by c-addr2 u2 and one (1) otherwise.
4447 **************************************************************************/
4448 static void compareInternal(FICL_VM *pVM, int caseInsensitive)
4450 char *cp1, *cp2;
4451 FICL_UNS u1, u2, uMin;
4452 int n = 0;
4454 vmCheckStack(pVM, 4, 1);
4455 u2 = stackPopUNS(pVM->pStack);
4456 cp2 = (char *)stackPopPtr(pVM->pStack);
4457 u1 = stackPopUNS(pVM->pStack);
4458 cp1 = (char *)stackPopPtr(pVM->pStack);
4460 uMin = (u1 < u2)? u1 : u2;
4461 for ( ; (uMin > 0) && (n == 0); uMin--)
4463 char c1 = *cp1++;
4464 char c2 = *cp2++;
4465 if (caseInsensitive)
4467 c1 = (char)tolower(c1);
4468 c2 = (char)tolower(c2);
4470 n = (int)(c1 - c2);
4473 if (n == 0)
4474 n = (int)(u1 - u2);
4476 if (n < 0)
4477 n = -1;
4478 else if (n > 0)
4479 n = 1;
4481 PUSHINT(n);
4482 return;
4486 static void compareString(FICL_VM *pVM)
4488 compareInternal(pVM, FALSE);
4492 static void compareStringInsensitive(FICL_VM *pVM)
4494 compareInternal(pVM, TRUE);
4498 /**************************************************************************
4499 p a d
4500 ** CORE EXT ( -- c-addr )
4501 ** c-addr is the address of a transient region that can be used to hold
4502 ** data for intermediate processing.
4503 **************************************************************************/
4504 static void pad(FICL_VM *pVM)
4506 stackPushPtr(pVM->pStack, pVM->pad);
4510 /**************************************************************************
4511 s o u r c e - i d
4512 ** CORE EXT, FILE ( -- 0 | -1 | fileid )
4513 ** Identifies the input source as follows:
4515 ** SOURCE-ID Input source
4516 ** --------- ------------
4517 ** fileid Text file fileid
4518 ** -1 String (via EVALUATE)
4519 ** 0 User input device
4520 **************************************************************************/
4521 static void sourceid(FICL_VM *pVM)
4523 PUSHINT(pVM->sourceID.i);
4524 return;
4528 /**************************************************************************
4529 r e f i l l
4530 ** CORE EXT ( -- flag )
4531 ** Attempt to fill the input buffer from the input source, returning a true
4532 ** flag if successful.
4533 ** When the input source is the user input device, attempt to receive input
4534 ** into the terminal input buffer. If successful, make the result the input
4535 ** buffer, set >IN to zero, and return true. Receipt of a line containing no
4536 ** characters is considered successful. If there is no input available from
4537 ** the current input source, return false.
4538 ** When the input source is a string from EVALUATE, return false and
4539 ** perform no other action.
4540 **************************************************************************/
4541 static void refill(FICL_VM *pVM)
4543 FICL_INT ret = (pVM->sourceID.i == -1) ? FICL_FALSE : FICL_TRUE;
4544 if (ret && (pVM->fRestart == 0))
4545 vmThrow(pVM, VM_RESTART);
4547 PUSHINT(ret);
4548 return;
4552 /**************************************************************************
4553 freebsd exception handling words
4554 ** Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
4555 ** the word in ToS. If an exception happens, restore the state to what
4556 ** it was before, and pushes the exception value on the stack. If not,
4557 ** push zero.
4559 ** Notice that Catch implements an inner interpreter. This is ugly,
4560 ** but given how ficl works, it cannot be helped. The problem is that
4561 ** colon definitions will be executed *after* the function returns,
4562 ** while "code" definitions will be executed immediately. I considered
4563 ** other solutions to this problem, but all of them shared the same
4564 ** basic problem (with added disadvantages): if ficl ever changes it's
4565 ** inner thread modus operandi, one would have to fix this word.
4567 ** More comments can be found throughout catch's code.
4569 ** Daniel C. Sobral Jan 09/1999
4570 ** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
4571 **************************************************************************/
4573 static void ficlCatch(FICL_VM *pVM)
4575 int except;
4576 jmp_buf vmState;
4577 FICL_VM VM;
4578 FICL_STACK pStack;
4579 FICL_STACK rStack;
4580 FICL_WORD *pFW;
4582 assert(pVM);
4583 assert(pVM->pSys->pExitInner);
4587 ** Get xt.
4588 ** We need this *before* we save the stack pointer, or
4589 ** we'll have to pop one element out of the stack after
4590 ** an exception. I prefer to get done with it up front. :-)
4592 #if FICL_ROBUST > 1
4593 vmCheckStack(pVM, 1, 0);
4594 #endif
4595 pFW = stackPopPtr(pVM->pStack);
4598 ** Save vm's state -- a catch will not back out environmental
4599 ** changes.
4601 ** We are *not* saving dictionary state, since it is
4602 ** global instead of per vm, and we are not saving
4603 ** stack contents, since we are not required to (and,
4604 ** thus, it would be useless). We save pVM, and pVM
4605 ** "stacks" (a structure containing general information
4606 ** about it, including the current stack pointer).
4608 memcpy((void*)&VM, (void*)pVM, sizeof(FICL_VM));
4609 memcpy((void*)&pStack, (void*)pVM->pStack, sizeof(FICL_STACK));
4610 memcpy((void*)&rStack, (void*)pVM->rStack, sizeof(FICL_STACK));
4613 ** Give pVM a jmp_buf
4615 pVM->pState = &vmState;
4618 ** Safety net
4620 except = setjmp(vmState);
4622 switch (except)
4625 ** Setup condition - push poison pill so that the VM throws
4626 ** VM_INNEREXIT if the XT terminates normally, then execute
4627 ** the XT
4629 case 0:
4630 vmPushIP(pVM, &(pVM->pSys->pExitInner)); /* Open mouth, insert emetic */
4631 vmExecute(pVM, pFW);
4632 vmInnerLoop(pVM);
4633 break;
4636 ** Normal exit from XT - lose the poison pill,
4637 ** restore old setjmp vector and push a zero.
4639 case VM_INNEREXIT:
4640 vmPopIP(pVM); /* Gack - hurl poison pill */
4641 pVM->pState = VM.pState; /* Restore just the setjmp vector */
4642 PUSHINT(0); /* Push 0 -- everything is ok */
4643 break;
4646 ** Some other exception got thrown - restore pre-existing VM state
4647 ** and push the exception code
4649 default:
4650 /* Restore vm's state */
4651 memcpy((void*)pVM, (void*)&VM, sizeof(FICL_VM));
4652 memcpy((void*)pVM->pStack, (void*)&pStack, sizeof(FICL_STACK));
4653 memcpy((void*)pVM->rStack, (void*)&rStack, sizeof(FICL_STACK));
4655 PUSHINT(except);/* Push error */
4656 break;
4660 /**************************************************************************
4661 ** t h r o w
4662 ** EXCEPTION
4663 ** Throw -- From ANS Forth standard.
4665 ** Throw takes the ToS and, if that's different from zero,
4666 ** returns to the last executed catch context. Further throws will
4667 ** unstack previously executed "catches", in LIFO mode.
4669 ** Daniel C. Sobral Jan 09/1999
4670 **************************************************************************/
4671 static void ficlThrow(FICL_VM *pVM)
4673 int except;
4675 except = stackPopINT(pVM->pStack);
4677 if (except)
4678 vmThrow(pVM, except);
4682 /**************************************************************************
4683 ** a l l o c a t e
4684 ** MEMORY
4685 **************************************************************************/
4686 static void ansAllocate(FICL_VM *pVM)
4688 size_t size;
4689 void *p;
4691 size = stackPopINT(pVM->pStack);
4692 p = ficlMalloc(size);
4693 PUSHPTR(p);
4694 if (p)
4695 PUSHINT(0);
4696 else
4697 PUSHINT(1);
4701 /**************************************************************************
4702 ** f r e e
4703 ** MEMORY
4704 **************************************************************************/
4705 static void ansFree(FICL_VM *pVM)
4707 void *p;
4709 p = stackPopPtr(pVM->pStack);
4710 ficlFree(p);
4711 PUSHINT(0);
4715 /**************************************************************************
4716 ** r e s i z e
4717 ** MEMORY
4718 **************************************************************************/
4719 static void ansResize(FICL_VM *pVM)
4721 size_t size;
4722 void *new, *old;
4724 size = stackPopINT(pVM->pStack);
4725 old = stackPopPtr(pVM->pStack);
4726 new = ficlRealloc(old, size);
4727 if (new)
4729 PUSHPTR(new);
4730 PUSHINT(0);
4732 else
4734 PUSHPTR(old);
4735 PUSHINT(1);
4740 /**************************************************************************
4741 ** e x i t - i n n e r
4742 ** Signals execXT that an inner loop has completed
4743 **************************************************************************/
4744 static void ficlExitInner(FICL_VM *pVM)
4746 vmThrow(pVM, VM_INNEREXIT);
4750 /**************************************************************************
4751 d n e g a t e
4752 ** DOUBLE ( d1 -- d2 )
4753 ** d2 is the negation of d1.
4754 **************************************************************************/
4755 static void dnegate(FICL_VM *pVM)
4757 DPINT i = i64Pop(pVM->pStack);
4758 i = m64Negate(i);
4759 i64Push(pVM->pStack, i);
4761 return;
4765 #if 0
4766 /**************************************************************************
4769 **************************************************************************/
4770 static void funcname(FICL_VM *pVM)
4772 IGNORE(pVM);
4773 return;
4777 #endif
4778 /**************************************************************************
4779 f i c l W o r d C l a s s i f y
4780 ** This public function helps to classify word types for SEE
4781 ** and the deugger in tools.c. Given a pointer to a word, it returns
4782 ** a member of WOR
4783 **************************************************************************/
4784 WORDKIND ficlWordClassify(FICL_WORD *pFW)
4786 typedef struct
4788 WORDKIND kind;
4789 FICL_CODE code;
4790 } CODEtoKIND;
4792 static CODEtoKIND codeMap[] =
4794 {BRANCH, branchParen},
4795 {COLON, colonParen},
4796 {CONSTANT, constantParen},
4797 {CREATE, createParen},
4798 {DO, doParen},
4799 {DOES, doDoes},
4800 {IF, branch0},
4801 {LITERAL, literalParen},
4802 {LOOP, loopParen},
4803 {OF, ofParen},
4804 {PLOOP, plusLoopParen},
4805 {QDO, qDoParen},
4806 {CSTRINGLIT, cstringLit},
4807 {STRINGLIT, stringLit},
4808 #if FICL_WANT_USER
4809 {USER, userParen},
4810 #endif
4811 {VARIABLE, variableParen},
4814 #define nMAP (sizeof(codeMap) / sizeof(CODEtoKIND))
4816 FICL_CODE code = pFW->code;
4817 int i;
4819 for (i=0; i < nMAP; i++)
4821 if (codeMap[i].code == code)
4822 return codeMap[i].kind;
4825 return PRIMITIVE;
4829 #ifdef TESTMAIN
4830 /**************************************************************************
4831 ** r a n d o m
4832 ** FICL-specific
4833 **************************************************************************/
4834 static void ficlRandom(FICL_VM *pVM)
4836 PUSHUNS(random());
4840 /**************************************************************************
4841 ** s e e d - r a n d o m
4842 ** FICL-specific
4843 **************************************************************************/
4844 static void ficlSeedRandom(FICL_VM *pVM)
4846 srandom(POPUNS());
4848 #endif
4851 /**************************************************************************
4852 f i c l C o m p i l e C o r e
4853 ** Builds the primitive wordset and the environment-query namespace.
4854 **************************************************************************/
4856 void ficlCompileCore(FICL_SYSTEM *pSys)
4858 FICL_DICT *dp = pSys->dp;
4859 assert (dp);
4863 ** CORE word set
4864 ** see softcore.c for definitions of: abs bl space spaces abort"
4866 pSys->pStore =
4867 dictAppendWord(dp, "!", store, FW_DEFAULT);
4868 dictAppendWord(dp, "#", numberSign, FW_DEFAULT);
4869 dictAppendWord(dp, "#>", numberSignGreater,FW_DEFAULT);
4870 dictAppendWord(dp, "#s", numberSignS, FW_DEFAULT);
4871 dictAppendWord(dp, "\'", ficlTick, FW_DEFAULT);
4872 dictAppendWord(dp, "(", commentHang, FW_IMMEDIATE);
4873 dictAppendWord(dp, "*", mul, FW_DEFAULT);
4874 dictAppendWord(dp, "*/", mulDiv, FW_DEFAULT);
4875 dictAppendWord(dp, "*/mod", mulDivRem, FW_DEFAULT);
4876 dictAppendWord(dp, "+", add, FW_DEFAULT);
4877 dictAppendWord(dp, "+!", plusStore, FW_DEFAULT);
4878 dictAppendWord(dp, "+loop", plusLoopCoIm, FW_COMPIMMED);
4879 dictAppendWord(dp, ",", comma, FW_DEFAULT);
4880 dictAppendWord(dp, "-", sub, FW_DEFAULT);
4881 dictAppendWord(dp, ".", displayCell, FW_DEFAULT);
4882 dictAppendWord(dp, ".\"", dotQuoteCoIm, FW_COMPIMMED);
4883 dictAppendWord(dp, "/", ficlDiv, FW_DEFAULT);
4884 dictAppendWord(dp, "/mod", slashMod, FW_DEFAULT);
4885 dictAppendWord(dp, "0<", zeroLess, FW_DEFAULT);
4886 dictAppendWord(dp, "0=", zeroEquals, FW_DEFAULT);
4887 dictAppendWord(dp, "1+", onePlus, FW_DEFAULT);
4888 dictAppendWord(dp, "1-", oneMinus, FW_DEFAULT);
4889 dictAppendWord(dp, "2!", twoStore, FW_DEFAULT);
4890 dictAppendWord(dp, "2*", twoMul, FW_DEFAULT);
4891 dictAppendWord(dp, "2/", twoDiv, FW_DEFAULT);
4892 dictAppendWord(dp, "2@", twoFetch, FW_DEFAULT);
4893 dictAppendWord(dp, "2drop", twoDrop, FW_DEFAULT);
4894 dictAppendWord(dp, "2dup", twoDup, FW_DEFAULT);
4895 dictAppendWord(dp, "2over", twoOver, FW_DEFAULT);
4896 dictAppendWord(dp, "2swap", twoSwap, FW_DEFAULT);
4897 dictAppendWord(dp, ":", colon, FW_DEFAULT);
4898 dictAppendWord(dp, ";", semicolonCoIm, FW_COMPIMMED);
4899 dictAppendWord(dp, "<", isLess, FW_DEFAULT);
4900 dictAppendWord(dp, "<#", lessNumberSign, FW_DEFAULT);
4901 dictAppendWord(dp, "=", isEqual, FW_DEFAULT);
4902 dictAppendWord(dp, ">", isGreater, FW_DEFAULT);
4903 dictAppendWord(dp, ">body", toBody, FW_DEFAULT);
4904 dictAppendWord(dp, ">in", toIn, FW_DEFAULT);
4905 dictAppendWord(dp, ">number", toNumber, FW_DEFAULT);
4906 dictAppendWord(dp, ">r", toRStack, FW_COMPILE);
4907 dictAppendWord(dp, "?dup", questionDup, FW_DEFAULT);
4908 dictAppendWord(dp, "@", fetch, FW_DEFAULT);
4909 dictAppendWord(dp, "abort", ficlAbort, FW_DEFAULT);
4910 dictAppendWord(dp, "accept", accept, FW_DEFAULT);
4911 dictAppendWord(dp, "align", align, FW_DEFAULT);
4912 dictAppendWord(dp, "aligned", aligned, FW_DEFAULT);
4913 dictAppendWord(dp, "allot", allot, FW_DEFAULT);
4914 dictAppendWord(dp, "and", bitwiseAnd, FW_DEFAULT);
4915 dictAppendWord(dp, "base", base, FW_DEFAULT);
4916 dictAppendWord(dp, "begin", beginCoIm, FW_COMPIMMED);
4917 dictAppendWord(dp, "c!", cStore, FW_DEFAULT);
4918 dictAppendWord(dp, "c,", cComma, FW_DEFAULT);
4919 dictAppendWord(dp, "c@", cFetch, FW_DEFAULT);
4920 dictAppendWord(dp, "case", caseCoIm, FW_COMPIMMED);
4921 dictAppendWord(dp, "cell+", cellPlus, FW_DEFAULT);
4922 dictAppendWord(dp, "cells", cells, FW_DEFAULT);
4923 dictAppendWord(dp, "char", ficlChar, FW_DEFAULT);
4924 dictAppendWord(dp, "char+", charPlus, FW_DEFAULT);
4925 dictAppendWord(dp, "chars", ficlChars, FW_DEFAULT);
4926 dictAppendWord(dp, "constant", constant, FW_DEFAULT);
4927 dictAppendWord(dp, "count", count, FW_DEFAULT);
4928 dictAppendWord(dp, "cr", cr, FW_DEFAULT);
4929 dictAppendWord(dp, "create", create, FW_DEFAULT);
4930 dictAppendWord(dp, "decimal", decimal, FW_DEFAULT);
4931 dictAppendWord(dp, "depth", depth, FW_DEFAULT);
4932 dictAppendWord(dp, "do", doCoIm, FW_COMPIMMED);
4933 dictAppendWord(dp, "does>", doesCoIm, FW_COMPIMMED);
4934 pSys->pDrop =
4935 dictAppendWord(dp, "drop", drop, FW_DEFAULT);
4936 dictAppendWord(dp, "dup", dup, FW_DEFAULT);
4937 dictAppendWord(dp, "else", elseCoIm, FW_COMPIMMED);
4938 dictAppendWord(dp, "emit", emit, FW_DEFAULT);
4939 dictAppendWord(dp, "endcase", endcaseCoIm, FW_COMPIMMED);
4940 dictAppendWord(dp, "endof", endofCoIm, FW_COMPIMMED);
4941 dictAppendWord(dp, "environment?", environmentQ,FW_DEFAULT);
4942 dictAppendWord(dp, "evaluate", evaluate, FW_DEFAULT);
4943 dictAppendWord(dp, "execute", execute, FW_DEFAULT);
4944 dictAppendWord(dp, "exit", exitCoIm, FW_COMPIMMED);
4945 dictAppendWord(dp, "fallthrough",fallthroughCoIm,FW_COMPIMMED);
4946 dictAppendWord(dp, "fill", fill, FW_DEFAULT);
4947 dictAppendWord(dp, "find", cFind, FW_DEFAULT);
4948 dictAppendWord(dp, "fm/mod", fmSlashMod, FW_DEFAULT);
4949 dictAppendWord(dp, "here", here, FW_DEFAULT);
4950 dictAppendWord(dp, "hold", hold, FW_DEFAULT);
4951 dictAppendWord(dp, "i", loopICo, FW_COMPILE);
4952 dictAppendWord(dp, "if", ifCoIm, FW_COMPIMMED);
4953 dictAppendWord(dp, "immediate", immediate, FW_DEFAULT);
4954 dictAppendWord(dp, "invert", bitwiseNot, FW_DEFAULT);
4955 dictAppendWord(dp, "j", loopJCo, FW_COMPILE);
4956 dictAppendWord(dp, "k", loopKCo, FW_COMPILE);
4957 dictAppendWord(dp, "leave", leaveCo, FW_COMPILE);
4958 dictAppendWord(dp, "literal", literalIm, FW_IMMEDIATE);
4959 dictAppendWord(dp, "loop", loopCoIm, FW_COMPIMMED);
4960 dictAppendWord(dp, "lshift", lshift, FW_DEFAULT);
4961 dictAppendWord(dp, "m*", mStar, FW_DEFAULT);
4962 dictAppendWord(dp, "max", ficlMax, FW_DEFAULT);
4963 dictAppendWord(dp, "min", ficlMin, FW_DEFAULT);
4964 dictAppendWord(dp, "mod", ficlMod, FW_DEFAULT);
4965 dictAppendWord(dp, "move", move, FW_DEFAULT);
4966 dictAppendWord(dp, "negate", negate, FW_DEFAULT);
4967 dictAppendWord(dp, "of", ofCoIm, FW_COMPIMMED);
4968 dictAppendWord(dp, "or", bitwiseOr, FW_DEFAULT);
4969 dictAppendWord(dp, "over", over, FW_DEFAULT);
4970 dictAppendWord(dp, "postpone", postponeCoIm, FW_COMPIMMED);
4971 dictAppendWord(dp, "quit", quit, FW_DEFAULT);
4972 dictAppendWord(dp, "r>", fromRStack, FW_COMPILE);
4973 dictAppendWord(dp, "r@", fetchRStack, FW_COMPILE);
4974 dictAppendWord(dp, "recurse", recurseCoIm, FW_COMPIMMED);
4975 dictAppendWord(dp, "repeat", repeatCoIm, FW_COMPIMMED);
4976 dictAppendWord(dp, "rot", rot, FW_DEFAULT);
4977 dictAppendWord(dp, "rshift", rshift, FW_DEFAULT);
4978 dictAppendWord(dp, "s\"", stringQuoteIm, FW_IMMEDIATE);
4979 dictAppendWord(dp, "s>d", sToD, FW_DEFAULT);
4980 dictAppendWord(dp, "sign", sign, FW_DEFAULT);
4981 dictAppendWord(dp, "sm/rem", smSlashRem, FW_DEFAULT);
4982 dictAppendWord(dp, "source", source, FW_DEFAULT);
4983 dictAppendWord(dp, "state", state, FW_DEFAULT);
4984 dictAppendWord(dp, "swap", swap, FW_DEFAULT);
4985 dictAppendWord(dp, "then", endifCoIm, FW_COMPIMMED);
4986 dictAppendWord(dp, "type", type, FW_DEFAULT);
4987 dictAppendWord(dp, "u.", uDot, FW_DEFAULT);
4988 dictAppendWord(dp, "u<", uIsLess, FW_DEFAULT);
4989 dictAppendWord(dp, "u>", uIsGreater, FW_DEFAULT);
4990 dictAppendWord(dp, "um*", umStar, FW_DEFAULT);
4991 dictAppendWord(dp, "um/mod", umSlashMod, FW_DEFAULT);
4992 dictAppendWord(dp, "unloop", unloopCo, FW_COMPILE);
4993 dictAppendWord(dp, "until", untilCoIm, FW_COMPIMMED);
4994 dictAppendWord(dp, "variable", variable, FW_DEFAULT);
4995 dictAppendWord(dp, "while", whileCoIm, FW_COMPIMMED);
4996 dictAppendWord(dp, "word", ficlWord, FW_DEFAULT);
4997 dictAppendWord(dp, "xor", bitwiseXor, FW_DEFAULT);
4998 dictAppendWord(dp, "[", lbracketCoIm, FW_COMPIMMED);
4999 dictAppendWord(dp, "[\']", bracketTickCoIm,FW_COMPIMMED);
5000 dictAppendWord(dp, "[char]", charCoIm, FW_COMPIMMED);
5001 dictAppendWord(dp, "]", rbracket, FW_DEFAULT);
5003 ** CORE EXT word set...
5004 ** see softcore.fr for other definitions
5006 /* "#tib" */
5007 dictAppendWord(dp, ".(", dotParen, FW_IMMEDIATE);
5008 /* ".r" */
5009 dictAppendWord(dp, "0>", zeroGreater, FW_DEFAULT);
5010 dictAppendWord(dp, "2>r", twoToR, FW_COMPILE);
5011 dictAppendWord(dp, "2r>", twoRFrom, FW_COMPILE);
5012 dictAppendWord(dp, "2r@", twoRFetch, FW_COMPILE);
5013 dictAppendWord(dp, ":noname", colonNoName, FW_DEFAULT);
5014 dictAppendWord(dp, "?do", qDoCoIm, FW_COMPIMMED);
5015 dictAppendWord(dp, "again", againCoIm, FW_COMPIMMED);
5016 dictAppendWord(dp, "c\"", cstringQuoteIm, FW_IMMEDIATE);
5017 dictAppendWord(dp, "hex", hex, FW_DEFAULT);
5018 dictAppendWord(dp, "pad", pad, FW_DEFAULT);
5019 dictAppendWord(dp, "parse", parse, FW_DEFAULT);
5020 dictAppendWord(dp, "pick", pick, FW_DEFAULT);
5021 /* query restore-input save-input tib u.r u> unused [compile] */
5022 dictAppendWord(dp, "roll", roll, FW_DEFAULT);
5023 dictAppendWord(dp, "refill", refill, FW_DEFAULT);
5024 dictAppendWord(dp, "source-id", sourceid, FW_DEFAULT);
5025 dictAppendWord(dp, "to", toValue, FW_IMMEDIATE);
5026 dictAppendWord(dp, "value", constant, FW_DEFAULT);
5027 dictAppendWord(dp, "\\", commentLine, FW_IMMEDIATE);
5031 ** Set CORE environment query values
5033 ficlSetEnv(pSys, "/counted-string", FICL_STRING_MAX);
5034 ficlSetEnv(pSys, "/hold", nPAD);
5035 ficlSetEnv(pSys, "/pad", nPAD);
5036 ficlSetEnv(pSys, "address-unit-bits", 8);
5037 ficlSetEnv(pSys, "core", FICL_TRUE);
5038 ficlSetEnv(pSys, "core-ext", FICL_FALSE);
5039 ficlSetEnv(pSys, "floored", FICL_FALSE);
5040 ficlSetEnv(pSys, "max-char", UCHAR_MAX);
5041 ficlSetEnvD(pSys,"max-d", 0x7fffffff, 0xffffffff);
5042 ficlSetEnv(pSys, "max-n", 0x7fffffff);
5043 ficlSetEnv(pSys, "max-u", 0xffffffff);
5044 ficlSetEnvD(pSys,"max-ud", 0xffffffff, 0xffffffff);
5045 ficlSetEnv(pSys, "return-stack-cells",FICL_DEFAULT_STACK);
5046 ficlSetEnv(pSys, "stack-cells", FICL_DEFAULT_STACK);
5049 ** DOUBLE word set (partial)
5051 dictAppendWord(dp, "2constant", twoConstant, FW_IMMEDIATE);
5052 dictAppendWord(dp, "2literal", twoLiteralIm, FW_IMMEDIATE);
5053 dictAppendWord(dp, "2variable", twoVariable, FW_IMMEDIATE);
5054 dictAppendWord(dp, "dnegate", dnegate, FW_DEFAULT);
5058 ** EXCEPTION word set
5060 dictAppendWord(dp, "catch", ficlCatch, FW_DEFAULT);
5061 dictAppendWord(dp, "throw", ficlThrow, FW_DEFAULT);
5063 ficlSetEnv(pSys, "exception", FICL_TRUE);
5064 ficlSetEnv(pSys, "exception-ext", FICL_TRUE);
5067 ** LOCAL and LOCAL EXT
5068 ** see softcore.c for implementation of locals|
5070 #if FICL_WANT_LOCALS
5071 pSys->pLinkParen =
5072 dictAppendWord(dp, "(link)", linkParen, FW_COMPILE);
5073 pSys->pUnLinkParen =
5074 dictAppendWord(dp, "(unlink)", unlinkParen, FW_COMPILE);
5075 dictAppendWord(dp, "doLocal", doLocalIm, FW_COMPIMMED);
5076 pSys->pGetLocalParen =
5077 dictAppendWord(dp, "(@local)", getLocalParen, FW_COMPILE);
5078 pSys->pToLocalParen =
5079 dictAppendWord(dp, "(toLocal)", toLocalParen, FW_COMPILE);
5080 pSys->pGetLocal0 =
5081 dictAppendWord(dp, "(@local0)", getLocal0, FW_COMPILE);
5082 pSys->pToLocal0 =
5083 dictAppendWord(dp, "(toLocal0)",toLocal0, FW_COMPILE);
5084 pSys->pGetLocal1 =
5085 dictAppendWord(dp, "(@local1)", getLocal1, FW_COMPILE);
5086 pSys->pToLocal1 =
5087 dictAppendWord(dp, "(toLocal1)",toLocal1, FW_COMPILE);
5088 dictAppendWord(dp, "(local)", localParen, FW_COMPILE);
5090 pSys->pGet2LocalParen =
5091 dictAppendWord(dp, "(@2local)", get2LocalParen, FW_COMPILE);
5092 pSys->pTo2LocalParen =
5093 dictAppendWord(dp, "(to2Local)",to2LocalParen, FW_COMPILE);
5094 dictAppendWord(dp, "(2local)", twoLocalParen, FW_COMPILE);
5096 ficlSetEnv(pSys, "locals", FICL_TRUE);
5097 ficlSetEnv(pSys, "locals-ext", FICL_TRUE);
5098 ficlSetEnv(pSys, "#locals", FICL_MAX_LOCALS);
5099 #endif
5102 ** Optional MEMORY-ALLOC word set
5105 dictAppendWord(dp, "allocate", ansAllocate, FW_DEFAULT);
5106 dictAppendWord(dp, "free", ansFree, FW_DEFAULT);
5107 dictAppendWord(dp, "resize", ansResize, FW_DEFAULT);
5109 ficlSetEnv(pSys, "memory-alloc", FICL_TRUE);
5112 ** optional SEARCH-ORDER word set
5114 ficlCompileSearch(pSys);
5117 ** TOOLS and TOOLS EXT
5119 ficlCompileTools(pSys);
5122 ** FILE and FILE EXT
5124 #if FICL_WANT_FILE
5125 ficlCompileFile(pSys);
5126 #endif
5129 ** Ficl extras
5131 #if FICL_WANT_FLOAT
5132 dictAppendWord(dp, ".hash", dictHashSummary,FW_DEFAULT);
5133 #endif
5134 dictAppendWord(dp, ".ver", ficlVersion, FW_DEFAULT);
5135 dictAppendWord(dp, "-roll", minusRoll, FW_DEFAULT);
5136 dictAppendWord(dp, ">name", toName, FW_DEFAULT);
5137 dictAppendWord(dp, "add-parse-step",
5138 addParseStep, FW_DEFAULT);
5139 dictAppendWord(dp, "body>", fromBody, FW_DEFAULT);
5140 dictAppendWord(dp, "compare", compareString, FW_DEFAULT); /* STRING */
5141 dictAppendWord(dp, "compare-insensitive", compareStringInsensitive, FW_DEFAULT); /* STRING */
5142 dictAppendWord(dp, "compile-only",
5143 compileOnly, FW_DEFAULT);
5144 dictAppendWord(dp, "endif", endifCoIm, FW_COMPIMMED);
5145 dictAppendWord(dp, "last-word", getLastWord, FW_DEFAULT);
5146 dictAppendWord(dp, "hash", hash, FW_DEFAULT);
5147 dictAppendWord(dp, "objectify", setObjectFlag, FW_DEFAULT);
5148 dictAppendWord(dp, "?object", isObject, FW_DEFAULT);
5149 dictAppendWord(dp, "parse-word",parseNoCopy, FW_DEFAULT);
5150 dictAppendWord(dp, "sfind", sFind, FW_DEFAULT);
5151 dictAppendWord(dp, "sliteral", sLiteralCoIm, FW_COMPIMMED); /* STRING */
5152 dictAppendWord(dp, "sprintf", ficlSprintf, FW_DEFAULT);
5153 dictAppendWord(dp, "strlen", ficlStrlen, FW_DEFAULT);
5154 dictAppendWord(dp, "q@", quadFetch, FW_DEFAULT);
5155 dictAppendWord(dp, "q!", quadStore, FW_DEFAULT);
5156 dictAppendWord(dp, "w@", wFetch, FW_DEFAULT);
5157 dictAppendWord(dp, "w!", wStore, FW_DEFAULT);
5158 dictAppendWord(dp, "x.", hexDot, FW_DEFAULT);
5159 #if FICL_WANT_USER
5160 dictAppendWord(dp, "(user)", userParen, FW_DEFAULT);
5161 dictAppendWord(dp, "user", userVariable, FW_DEFAULT);
5162 #endif
5163 #ifdef TESTMAIN
5164 dictAppendWord(dp, "random", ficlRandom, FW_DEFAULT);
5165 dictAppendWord(dp, "seed-random",ficlSeedRandom,FW_DEFAULT);
5166 #endif
5169 ** internal support words
5171 dictAppendWord(dp, "(create)", createParen, FW_COMPILE);
5172 pSys->pExitParen =
5173 dictAppendWord(dp, "(exit)", exitParen, FW_COMPILE);
5174 pSys->pSemiParen =
5175 dictAppendWord(dp, "(;)", semiParen, FW_COMPILE);
5176 pSys->pLitParen =
5177 dictAppendWord(dp, "(literal)", literalParen, FW_COMPILE);
5178 pSys->pTwoLitParen =
5179 dictAppendWord(dp, "(2literal)",twoLitParen, FW_COMPILE);
5180 pSys->pStringLit =
5181 dictAppendWord(dp, "(.\")", stringLit, FW_COMPILE);
5182 pSys->pCStringLit =
5183 dictAppendWord(dp, "(c\")", cstringLit, FW_COMPILE);
5184 pSys->pBranch0 =
5185 dictAppendWord(dp, "(branch0)", branch0, FW_COMPILE);
5186 pSys->pBranchParen =
5187 dictAppendWord(dp, "(branch)", branchParen, FW_COMPILE);
5188 pSys->pDoParen =
5189 dictAppendWord(dp, "(do)", doParen, FW_COMPILE);
5190 pSys->pDoesParen =
5191 dictAppendWord(dp, "(does>)", doesParen, FW_COMPILE);
5192 pSys->pQDoParen =
5193 dictAppendWord(dp, "(?do)", qDoParen, FW_COMPILE);
5194 pSys->pLoopParen =
5195 dictAppendWord(dp, "(loop)", loopParen, FW_COMPILE);
5196 pSys->pPLoopParen =
5197 dictAppendWord(dp, "(+loop)", plusLoopParen, FW_COMPILE);
5198 pSys->pInterpret =
5199 dictAppendWord(dp, "interpret", interpret, FW_DEFAULT);
5200 dictAppendWord(dp, "lookup", lookup, FW_DEFAULT);
5201 pSys->pOfParen =
5202 dictAppendWord(dp, "(of)", ofParen, FW_DEFAULT);
5203 dictAppendWord(dp, "(variable)",variableParen, FW_COMPILE);
5204 dictAppendWord(dp, "(constant)",constantParen, FW_COMPILE);
5205 dictAppendWord(dp, "(parse-step)",
5206 parseStepParen, FW_DEFAULT);
5207 pSys->pExitInner =
5208 dictAppendWord(dp, "exit-inner",ficlExitInner, FW_DEFAULT);
5211 ** Set up system's outer interpreter loop - maybe this should be in initSystem?
5213 pSys->pInterp[0] = pSys->pInterpret;
5214 pSys->pInterp[1] = pSys->pBranchParen;
5215 pSys->pInterp[2] = (FICL_WORD *)(void *)(-2);
5217 assert(dictCellsAvail(dp) > 0);
5219 return;