1 /*******************************************************************
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
8 *******************************************************************/
10 /* $FreeBSD: src/sys/boot/ficl/words.c,v 1.23.2.2 2001/10/10 08:05:43 jkh Exp $ */
11 /* $DragonFly: src/sys/boot/ficl/words.c,v 1.2 2003/06/17 04:28:17 dillon Exp $ */
25 static void colonParen(FICL_VM *pVM);
26 static void literalIm(FICL_VM *pVM);
27 static void interpWord(FICL_VM *pVM, STRINGINFO si);
30 ** Control structure building words use these
31 ** strings' addresses as markers on the stack to
32 ** check for structure completion.
34 static char doTag[] = "do";
35 static char colonTag[] = "colon";
36 static char leaveTag[] = "leave";
38 static char destTag[] = "target";
39 static char origTag[] = "origin";
42 ** Pointers to various words in the dictionary
43 ** -- initialized by ficlCompileCore, below --
44 ** for use by compiling words. Colon definitions
45 ** in ficl are lists of pointers to words. A bit
48 static FICL_WORD *pBranchParen = NULL;
49 static FICL_WORD *pComma = NULL;
50 static FICL_WORD *pDoParen = NULL;
51 static FICL_WORD *pDoesParen = NULL;
52 static FICL_WORD *pExitParen = NULL;
53 static FICL_WORD *pIfParen = NULL;
54 static FICL_WORD *pInterpret = NULL;
55 static FICL_WORD *pLitParen = NULL;
56 static FICL_WORD *pTwoLitParen = NULL;
57 static FICL_WORD *pLoopParen = NULL;
58 static FICL_WORD *pPLoopParen = NULL;
59 static FICL_WORD *pQDoParen = NULL;
60 static FICL_WORD *pSemiParen = NULL;
61 static FICL_WORD *pStore = NULL;
62 static FICL_WORD *pStringLit = NULL;
63 static FICL_WORD *pType = NULL;
66 static FICL_WORD *pGetLocalParen= NULL;
67 static FICL_WORD *pGet2LocalParen= NULL;
68 static FICL_WORD *pGetLocal0 = NULL;
69 static FICL_WORD *pGetLocal1 = NULL;
70 static FICL_WORD *pToLocalParen = NULL;
71 static FICL_WORD *pTo2LocalParen = NULL;
72 static FICL_WORD *pToLocal0 = NULL;
73 static FICL_WORD *pToLocal1 = NULL;
74 static FICL_WORD *pLinkParen = NULL;
75 static FICL_WORD *pUnLinkParen = NULL;
76 static int nLocals = 0;
77 static CELL *pMarkLocals = NULL;
79 static void doLocalIm(FICL_VM *pVM);
80 static void do2LocalIm(FICL_VM *pVM);
86 ** C O N T R O L S T R U C T U R E B U I L D E R S
88 ** Push current dict location for later branch resolution.
89 ** The location may be either a branch target or a patch address...
91 static void markBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
93 stackPushPtr(pVM->pStack, dp->here);
94 stackPushPtr(pVM->pStack, tag);
98 static void markControlTag(FICL_VM *pVM, char *tag)
100 stackPushPtr(pVM->pStack, tag);
104 static void matchControlTag(FICL_VM *pVM, char *tag)
106 char *cp = (char *)stackPopPtr(pVM->pStack);
107 if ( strcmp(cp, tag) )
109 vmThrowErr(pVM, "Error -- unmatched control structure \"%s\"", tag);
116 ** Expect a branch target address on the param stack,
117 ** compile a literal offset from the current dict location
118 ** to the target address
120 static void resolveBackBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
125 matchControlTag(pVM, tag);
127 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
128 offset = patchAddr - dp->here;
129 dictAppendCell(dp, LVALUEtoCELL(offset));
136 ** Expect a branch patch address on the param stack,
137 ** compile a literal offset from the patch location
138 ** to the current dict location
140 static void resolveForwardBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
145 matchControlTag(pVM, tag);
147 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
148 offset = dp->here - patchAddr;
149 *patchAddr = LVALUEtoCELL(offset);
155 ** Match the tag to the top of the stack. If success,
156 ** sopy "here" address into the cell whose address is next
157 ** on the stack. Used by do..leave..loop.
159 static void resolveAbsBranch(FICL_DICT *dp, FICL_VM *pVM, char *tag)
164 cp = stackPopPtr(pVM->pStack);
167 vmTextOut(pVM, "Warning -- Unmatched control word: ", 0);
168 vmTextOut(pVM, tag, 1);
171 patchAddr = (CELL *)stackPopPtr(pVM->pStack);
172 *patchAddr = LVALUEtoCELL(dp->here);
178 /**************************************************************************
180 ** Attempts to convert the NULL terminated string in the VM's pad to
181 ** a number using the VM's current base. If successful, pushes the number
182 ** onto the param stack and returns TRUE. Otherwise, returns FALSE.
183 **************************************************************************/
185 static int isNumber(FICL_VM *pVM, STRINGINFO si)
189 unsigned base = pVM->base;
190 char *cp = SI_PTR(si);
191 FICL_COUNT count= (FICL_COUNT)SI_COUNT(si);
201 else if ((cp[0] == '0') && (cp[1] == 'x'))
202 { /* detect 0xNNNN format for hex numbers */
211 while (count-- && ((ch = *cp++) != '\0'))
213 if (!(isdigit(ch)||isalpha(ch)))
219 digit = tolower(ch) - 'a' + 10;
224 accum = accum * base + digit;
230 stackPushINT(pVM->pStack, accum);
236 static void ficlIsNum(FICL_VM *pVM)
241 SI_SETLEN(si, stackPopINT(pVM->pStack));
242 SI_SETPTR(si, stackPopPtr(pVM->pStack));
243 ret = isNumber(pVM, si) ? FICL_TRUE : FICL_FALSE;
244 stackPushINT(pVM->pStack, ret);
248 /**************************************************************************
249 a d d & f r i e n d s
251 **************************************************************************/
253 static void add(FICL_VM *pVM)
257 vmCheckStack(pVM, 2, 1);
259 i = stackPopINT(pVM->pStack);
260 i += stackGetTop(pVM->pStack).i;
261 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
265 static void sub(FICL_VM *pVM)
269 vmCheckStack(pVM, 2, 1);
271 i = stackPopINT(pVM->pStack);
272 i = stackGetTop(pVM->pStack).i - i;
273 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
277 static void mul(FICL_VM *pVM)
281 vmCheckStack(pVM, 2, 1);
283 i = stackPopINT(pVM->pStack);
284 i *= stackGetTop(pVM->pStack).i;
285 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
289 static void negate(FICL_VM *pVM)
293 vmCheckStack(pVM, 1, 1);
295 i = -stackPopINT(pVM->pStack);
296 stackPushINT(pVM->pStack, i);
300 static void ficlDiv(FICL_VM *pVM)
304 vmCheckStack(pVM, 2, 1);
306 i = stackPopINT(pVM->pStack);
307 i = stackGetTop(pVM->pStack).i / i;
308 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
313 ** slash-mod CORE ( n1 n2 -- n3 n4 )
314 ** Divide n1 by n2, giving the single-cell remainder n3 and the single-cell
315 ** quotient n4. An ambiguous condition exists if n2 is zero. If n1 and n2
316 ** differ in sign, the implementation-defined result returned will be the
317 ** same as that returned by either the phrase
318 ** >R S>D R> FM/MOD or the phrase >R S>D R> SM/REM .
319 ** NOTE: Ficl complies with the second phrase (symmetric division)
321 static void slashMod(FICL_VM *pVM)
328 vmCheckStack(pVM, 2, 2);
330 n2 = stackPopINT(pVM->pStack);
331 n1.lo = stackPopINT(pVM->pStack);
334 qr = m64SymmetricDivI(n1, n2);
335 stackPushINT(pVM->pStack, qr.rem);
336 stackPushINT(pVM->pStack, qr.quot);
340 static void onePlus(FICL_VM *pVM)
344 vmCheckStack(pVM, 1, 1);
346 i = stackGetTop(pVM->pStack).i;
348 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
352 static void oneMinus(FICL_VM *pVM)
356 vmCheckStack(pVM, 1, 1);
358 i = stackGetTop(pVM->pStack).i;
360 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
364 static void twoMul(FICL_VM *pVM)
368 vmCheckStack(pVM, 1, 1);
370 i = stackGetTop(pVM->pStack).i;
372 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
376 static void twoDiv(FICL_VM *pVM)
380 vmCheckStack(pVM, 1, 1);
382 i = stackGetTop(pVM->pStack).i;
384 stackSetTop(pVM->pStack, LVALUEtoCELL(i));
388 static void mulDiv(FICL_VM *pVM)
393 vmCheckStack(pVM, 3, 1);
395 z = stackPopINT(pVM->pStack);
396 y = stackPopINT(pVM->pStack);
397 x = stackPopINT(pVM->pStack);
400 x = m64SymmetricDivI(prod, z).quot;
402 stackPushINT(pVM->pStack, x);
407 static void mulDivRem(FICL_VM *pVM)
413 vmCheckStack(pVM, 3, 2);
415 z = stackPopINT(pVM->pStack);
416 y = stackPopINT(pVM->pStack);
417 x = stackPopINT(pVM->pStack);
420 qr = m64SymmetricDivI(prod, z);
422 stackPushINT(pVM->pStack, qr.rem);
423 stackPushINT(pVM->pStack, qr.quot);
428 /**************************************************************************
431 ** Signal the system to shut down - this causes ficlExec to return
432 ** VM_USEREXIT. The rest is up to you.
433 **************************************************************************/
435 static void bye(FICL_VM *pVM)
437 vmThrow(pVM, VM_USEREXIT);
442 /**************************************************************************
443 c o l o n d e f i n i t i o n s
444 ** Code to begin compiling a colon definition
445 ** This function sets the state to COMPILE, then creates a
446 ** new word whose name is the next word in the input stream
447 ** and whose code is colonParen.
448 **************************************************************************/
450 static void colon(FICL_VM *pVM)
452 FICL_DICT *dp = ficlGetDict();
453 STRINGINFO si = vmGetWord(pVM);
455 dictCheckThreshold(dp);
457 pVM->state = COMPILE;
458 markControlTag(pVM, colonTag);
459 dictAppendWord2(dp, si, colonParen, FW_DEFAULT | FW_SMUDGE);
467 /**************************************************************************
469 ** This is the code that executes a colon definition. It assumes that the
470 ** virtual machine is running a "next" loop (See the vm.c
471 ** for its implementation of member function vmExecute()). The colon
472 ** code simply copies the address of the first word in the list of words
473 ** to interpret into IP after saving its old value. When we return to the
474 ** "next" loop, the virtual machine will call the code for each word in
477 **************************************************************************/
479 static void colonParen(FICL_VM *pVM)
481 IPTYPE tempIP = (IPTYPE) (pVM->runningWord->param);
482 vmPushIP(pVM, tempIP);
488 /**************************************************************************
489 s e m i c o l o n C o I m
491 ** IMMEDIATE code for ";". This function sets the state to INTERPRET and
492 ** terminates a word under compilation by appending code for "(;)" to
493 ** the definition. TO DO: checks for leftover branch target tags on the
494 ** return stack and complains if any are found.
495 **************************************************************************/
496 static void semiParen(FICL_VM *pVM)
503 static void semicolonCoIm(FICL_VM *pVM)
505 FICL_DICT *dp = ficlGetDict();
508 matchControlTag(pVM, colonTag);
511 assert(pUnLinkParen);
514 FICL_DICT *pLoc = ficlGetLoc();
515 dictEmpty(pLoc, pLoc->pForthWords->size);
516 dictAppendCell(dp, LVALUEtoCELL(pUnLinkParen));
521 dictAppendCell(dp, LVALUEtoCELL(pSemiParen));
522 pVM->state = INTERPRET;
528 /**************************************************************************
531 ** This function simply pops the previous instruction
532 ** pointer and returns to the "next" loop. Used for exiting from within
533 ** a definition. Note that exitParen is identical to semiParen - they
534 ** are in two different functions so that "see" can correctly identify
535 ** the end of a colon definition, even if it uses "exit".
536 **************************************************************************/
537 static void exitParen(FICL_VM *pVM)
543 static void exitCoIm(FICL_VM *pVM)
545 FICL_DICT *dp = ficlGetDict();
552 dictAppendCell(dp, LVALUEtoCELL(pUnLinkParen));
555 dictAppendCell(dp, LVALUEtoCELL(pExitParen));
560 /**************************************************************************
561 c o n s t a n t P a r e n
562 ** This is the run-time code for "constant". It simply returns the
563 ** contents of its word's first data cell.
565 **************************************************************************/
567 void constantParen(FICL_VM *pVM)
569 FICL_WORD *pFW = pVM->runningWord;
571 vmCheckStack(pVM, 0, 1);
573 stackPush(pVM->pStack, pFW->param[0]);
577 void twoConstParen(FICL_VM *pVM)
579 FICL_WORD *pFW = pVM->runningWord;
581 vmCheckStack(pVM, 0, 2);
583 stackPush(pVM->pStack, pFW->param[0]); /* lo */
584 stackPush(pVM->pStack, pFW->param[1]); /* hi */
589 /**************************************************************************
592 ** Compiles a constant into the dictionary. Constants return their
593 ** value when invoked. Expects a value on top of the parm stack.
594 **************************************************************************/
596 static void constant(FICL_VM *pVM)
598 FICL_DICT *dp = ficlGetDict();
599 STRINGINFO si = vmGetWord(pVM);
602 vmCheckStack(pVM, 1, 0);
604 dictAppendWord2(dp, si, constantParen, FW_DEFAULT);
605 dictAppendCell(dp, stackPop(pVM->pStack));
610 static void twoConstant(FICL_VM *pVM)
612 FICL_DICT *dp = ficlGetDict();
613 STRINGINFO si = vmGetWord(pVM);
617 vmCheckStack(pVM, 2, 0);
619 c = stackPop(pVM->pStack);
620 dictAppendWord2(dp, si, twoConstParen, FW_DEFAULT);
621 dictAppendCell(dp, stackPop(pVM->pStack));
622 dictAppendCell(dp, c);
627 /**************************************************************************
628 d i s p l a y C e l l
629 ** Drop and print the contents of the cell at the top of the param
631 **************************************************************************/
633 static void displayCell(FICL_VM *pVM)
637 vmCheckStack(pVM, 1, 0);
639 c = stackPop(pVM->pStack);
640 ltoa((c).i, pVM->pad, pVM->base);
641 strcat(pVM->pad, " ");
642 vmTextOut(pVM, pVM->pad, 0);
646 static void displayCellNoPad(FICL_VM *pVM)
650 vmCheckStack(pVM, 1, 0);
652 c = stackPop(pVM->pStack);
653 ltoa((c).i, pVM->pad, pVM->base);
654 vmTextOut(pVM, pVM->pad, 0);
658 static void uDot(FICL_VM *pVM)
662 vmCheckStack(pVM, 1, 0);
664 u = stackPopUNS(pVM->pStack);
665 ultoa(u, pVM->pad, pVM->base);
666 strcat(pVM->pad, " ");
667 vmTextOut(pVM, pVM->pad, 0);
672 static void hexDot(FICL_VM *pVM)
676 vmCheckStack(pVM, 1, 0);
678 u = stackPopUNS(pVM->pStack);
679 ultoa(u, pVM->pad, 16);
680 strcat(pVM->pad, " ");
681 vmTextOut(pVM, pVM->pad, 0);
686 /**************************************************************************
687 d i s p l a y S t a c k
688 ** Display the parameter stack (code for ".s")
689 **************************************************************************/
691 static void displayStack(FICL_VM *pVM)
693 int d = stackDepth(pVM->pStack);
697 vmCheckStack(pVM, 0, 0);
700 vmTextOut(pVM, "(Stack Empty)", 1);
703 pCell = pVM->pStack->sp;
704 for (i = 0; i < d; i++)
706 vmTextOut(pVM, ltoa((*--pCell).i, pVM->pad, pVM->base), 1);
712 /**************************************************************************
713 d u p & f r i e n d s
715 **************************************************************************/
717 static void depth(FICL_VM *pVM)
721 vmCheckStack(pVM, 0, 1);
723 i = stackDepth(pVM->pStack);
724 stackPushINT(pVM->pStack, i);
729 static void drop(FICL_VM *pVM)
732 vmCheckStack(pVM, 1, 0);
734 stackDrop(pVM->pStack, 1);
739 static void twoDrop(FICL_VM *pVM)
742 vmCheckStack(pVM, 2, 0);
744 stackDrop(pVM->pStack, 2);
749 static void dup(FICL_VM *pVM)
752 vmCheckStack(pVM, 1, 2);
754 stackPick(pVM->pStack, 0);
759 static void twoDup(FICL_VM *pVM)
762 vmCheckStack(pVM, 2, 4);
764 stackPick(pVM->pStack, 1);
765 stackPick(pVM->pStack, 1);
770 static void over(FICL_VM *pVM)
773 vmCheckStack(pVM, 2, 3);
775 stackPick(pVM->pStack, 1);
779 static void twoOver(FICL_VM *pVM)
782 vmCheckStack(pVM, 4, 6);
784 stackPick(pVM->pStack, 3);
785 stackPick(pVM->pStack, 3);
790 static void pick(FICL_VM *pVM)
792 CELL c = stackPop(pVM->pStack);
794 vmCheckStack(pVM, c.i+1, c.i+2);
796 stackPick(pVM->pStack, c.i);
801 static void questionDup(FICL_VM *pVM)
805 vmCheckStack(pVM, 1, 2);
807 c = stackGetTop(pVM->pStack);
810 stackPick(pVM->pStack, 0);
816 static void roll(FICL_VM *pVM)
818 int i = stackPop(pVM->pStack).i;
821 vmCheckStack(pVM, i+1, i+1);
823 stackRoll(pVM->pStack, i);
828 static void minusRoll(FICL_VM *pVM)
830 int i = stackPop(pVM->pStack).i;
833 vmCheckStack(pVM, i+1, i+1);
835 stackRoll(pVM->pStack, -i);
840 static void rot(FICL_VM *pVM)
843 vmCheckStack(pVM, 3, 3);
845 stackRoll(pVM->pStack, 2);
850 static void swap(FICL_VM *pVM)
853 vmCheckStack(pVM, 2, 2);
855 stackRoll(pVM->pStack, 1);
860 static void twoSwap(FICL_VM *pVM)
863 vmCheckStack(pVM, 4, 4);
865 stackRoll(pVM->pStack, 3);
866 stackRoll(pVM->pStack, 3);
871 /**************************************************************************
872 e m i t & f r i e n d s
874 **************************************************************************/
876 static void emit(FICL_VM *pVM)
882 vmCheckStack(pVM, 1, 0);
884 i = stackPopINT(pVM->pStack);
887 vmTextOut(pVM, cp, 0);
892 static void cr(FICL_VM *pVM)
894 vmTextOut(pVM, "", 1);
899 static void commentLine(FICL_VM *pVM)
901 char *cp = vmGetInBuf(pVM);
902 char *pEnd = vmGetInBufEnd(pVM);
905 while ((cp != pEnd) && (ch != '\r') && (ch != '\n'))
911 ** Cope with DOS or UNIX-style EOLs -
912 ** Check for /r, /n, /r/n, or /n/r end-of-line sequences,
913 ** and point cp to next char. If EOL is \0, we're done.
919 if ( (cp != pEnd) && (ch != *cp)
920 && ((*cp == '\r') || (*cp == '\n')) )
924 vmUpdateTib(pVM, cp);
931 ** Compilation: Perform the execution semantics given below.
932 ** Execution: ( "ccc<paren>" -- )
933 ** Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
934 ** The number of characters in ccc may be zero to the number of characters
935 ** in the parse area.
938 static void commentHang(FICL_VM *pVM)
940 vmParseStringEx(pVM, ')', 0);
945 /**************************************************************************
946 F E T C H & S T O R E
948 **************************************************************************/
950 static void fetch(FICL_VM *pVM)
954 vmCheckStack(pVM, 1, 1);
956 pCell = (CELL *)stackPopPtr(pVM->pStack);
957 stackPush(pVM->pStack, *pCell);
962 ** two-fetch CORE ( a-addr -- x1 x2 )
963 ** Fetch the cell pair x1 x2 stored at a-addr. x2 is stored at a-addr and
964 ** x1 at the next consecutive cell. It is equivalent to the sequence
965 ** DUP CELL+ @ SWAP @ .
967 static void twoFetch(FICL_VM *pVM)
971 vmCheckStack(pVM, 1, 2);
973 pCell = (CELL *)stackPopPtr(pVM->pStack);
974 stackPush(pVM->pStack, *pCell++);
975 stackPush(pVM->pStack, *pCell);
981 ** store CORE ( x a-addr -- )
982 ** Store x at a-addr.
984 static void store(FICL_VM *pVM)
988 vmCheckStack(pVM, 2, 0);
990 pCell = (CELL *)stackPopPtr(pVM->pStack);
991 *pCell = stackPop(pVM->pStack);
995 ** two-store CORE ( x1 x2 a-addr -- )
996 ** Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
997 ** next consecutive cell. It is equivalent to the sequence
998 ** SWAP OVER ! CELL+ ! .
1000 static void twoStore(FICL_VM *pVM)
1004 vmCheckStack(pVM, 3, 0);
1006 pCell = (CELL *)stackPopPtr(pVM->pStack);
1007 *pCell++ = stackPop(pVM->pStack);
1008 *pCell = stackPop(pVM->pStack);
1011 static void plusStore(FICL_VM *pVM)
1015 vmCheckStack(pVM, 2, 0);
1017 pCell = (CELL *)stackPopPtr(pVM->pStack);
1018 pCell->i += stackPop(pVM->pStack).i;
1022 static void iFetch(FICL_VM *pVM)
1026 vmCheckStack(pVM, 1, 1);
1028 pw = (UNS32 *)stackPopPtr(pVM->pStack);
1029 stackPushUNS(pVM->pStack, (FICL_UNS)*pw);
1033 static void iStore(FICL_VM *pVM)
1037 vmCheckStack(pVM, 2, 0);
1039 pw = (UNS32 *)stackPopPtr(pVM->pStack);
1040 *pw = (UNS32)(stackPop(pVM->pStack).u);
1043 static void wFetch(FICL_VM *pVM)
1047 vmCheckStack(pVM, 1, 1);
1049 pw = (UNS16 *)stackPopPtr(pVM->pStack);
1050 stackPushUNS(pVM->pStack, (FICL_UNS)*pw);
1054 static void wStore(FICL_VM *pVM)
1058 vmCheckStack(pVM, 2, 0);
1060 pw = (UNS16 *)stackPopPtr(pVM->pStack);
1061 *pw = (UNS16)(stackPop(pVM->pStack).u);
1064 static void cFetch(FICL_VM *pVM)
1068 vmCheckStack(pVM, 1, 1);
1070 pc = (UNS8 *)stackPopPtr(pVM->pStack);
1071 stackPushUNS(pVM->pStack, (FICL_UNS)*pc);
1075 static void cStore(FICL_VM *pVM)
1079 vmCheckStack(pVM, 2, 0);
1081 pc = (UNS8 *)stackPopPtr(pVM->pStack);
1082 *pc = (UNS8)(stackPop(pVM->pStack).u);
1086 /**************************************************************************
1089 ** Compiles code for a conditional branch into the dictionary
1090 ** and pushes the branch patch address on the stack for later
1091 ** patching by ELSE or THEN/ENDIF.
1092 **************************************************************************/
1094 static void ifCoIm(FICL_VM *pVM)
1096 FICL_DICT *dp = ficlGetDict();
1100 dictAppendCell(dp, LVALUEtoCELL(pIfParen));
1101 markBranch(dp, pVM, origTag);
1102 dictAppendUNS(dp, 1);
1107 /**************************************************************************
1109 ** Runtime code to do "if" or "until": pop a flag from the stack,
1110 ** fall through if true, branch if false. Probably ought to be
1111 ** called (not?branch) since it does "branch if false".
1112 **************************************************************************/
1114 static void ifParen(FICL_VM *pVM)
1119 vmCheckStack(pVM, 1, 0);
1121 flag = stackPopUNS(pVM->pStack);
1124 { /* fall through */
1125 vmBranchRelative(pVM, 1);
1128 { /* take branch (to else/endif/begin) */
1129 vmBranchRelative(pVM, *(int*)(pVM->ip));
1136 /**************************************************************************
1139 ** IMMEDIATE -- compiles an "else"...
1140 ** 1) Compile a branch and a patch address; the address gets patched
1141 ** by "endif" to point past the "else" code.
1142 ** 2) Pop the the "if" patch address
1143 ** 3) Patch the "if" branch to point to the current compile address.
1144 ** 4) Push the "else" patch address. ("endif" patches this to jump past
1146 **************************************************************************/
1148 static void elseCoIm(FICL_VM *pVM)
1152 FICL_DICT *dp = ficlGetDict();
1154 assert(pBranchParen);
1155 /* (1) compile branch runtime */
1156 dictAppendCell(dp, LVALUEtoCELL(pBranchParen));
1157 matchControlTag(pVM, origTag);
1159 (CELL *)stackPopPtr(pVM->pStack); /* (2) pop "if" patch addr */
1160 markBranch(dp, pVM, origTag); /* (4) push "else" patch addr */
1161 dictAppendUNS(dp, 1); /* (1) compile patch placeholder */
1162 offset = dp->here - patchAddr;
1163 *patchAddr = LVALUEtoCELL(offset); /* (3) Patch "if" */
1169 /**************************************************************************
1170 b r a n c h P a r e n
1172 ** Runtime for "(branch)" -- expects a literal offset in the next
1173 ** compilation address, and branches to that location.
1174 **************************************************************************/
1176 static void branchParen(FICL_VM *pVM)
1178 vmBranchRelative(pVM, *(int *)(pVM->ip));
1183 /**************************************************************************
1186 **************************************************************************/
1188 static void endifCoIm(FICL_VM *pVM)
1190 FICL_DICT *dp = ficlGetDict();
1191 resolveForwardBranch(dp, pVM, origTag);
1196 /**************************************************************************
1198 ** hash ( c-addr u -- code)
1199 ** calculates hashcode of specified string and leaves it on the stack
1200 **************************************************************************/
1202 static void hash(FICL_VM *pVM)
1205 SI_SETLEN(si, stackPopUNS(pVM->pStack));
1206 SI_SETPTR(si, stackPopPtr(pVM->pStack));
1207 stackPushUNS(pVM->pStack, hashHashCode(si));
1212 /**************************************************************************
1214 ** This is the "user interface" of a Forth. It does the following:
1215 ** while there are words in the VM's Text Input Buffer
1216 ** Copy next word into the pad (vmGetWord)
1217 ** Attempt to find the word in the dictionary (dictLookup)
1218 ** If successful, execute the word.
1219 ** Otherwise, attempt to convert the word to a number (isNumber)
1220 ** If successful, push the number onto the parameter stack.
1221 ** Otherwise, print an error message and exit loop...
1224 ** From the standard, section 3.4
1225 ** Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
1226 ** repeat the following steps until either the parse area is empty or an
1227 ** ambiguous condition exists:
1228 ** a) Skip leading spaces and parse a name (see 3.4.1);
1229 **************************************************************************/
1231 static void interpret(FICL_VM *pVM)
1233 STRINGINFO si = vmGetWord0(pVM);
1236 vmBranchRelative(pVM, -1);
1239 ** Get next word...if out of text, we're done.
1243 vmThrow(pVM, VM_OUTOFTEXT);
1246 interpWord(pVM, si);
1249 return; /* back to inner interpreter */
1252 /**************************************************************************
1253 ** From the standard, section 3.4
1254 ** b) Search the dictionary name space (see 3.4.2). If a definition name
1255 ** matching the string is found:
1256 ** 1.if interpreting, perform the interpretation semantics of the definition
1257 ** (see 3.4.3.2), and continue at a);
1258 ** 2.if compiling, perform the compilation semantics of the definition
1259 ** (see 3.4.3.3), and continue at a).
1261 ** c) If a definition name matching the string is not found, attempt to
1262 ** convert the string to a number (see 3.4.1.3). If successful:
1263 ** 1.if interpreting, place the number on the data stack, and continue at a);
1264 ** 2.if compiling, compile code that when executed will place the number on
1265 ** the stack (see 6.1.1780 LITERAL), and continue at a);
1267 ** d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
1268 **************************************************************************/
1269 static void interpWord(FICL_VM *pVM, STRINGINFO si)
1271 FICL_DICT *dp = ficlGetDict();
1275 dictCheck(dp, pVM, 0);
1276 vmCheckStack(pVM, 0, 0);
1279 #if FICL_WANT_LOCALS
1282 tempFW = dictLookupLoc(dp, si);
1286 tempFW = dictLookup(dp, si);
1288 if (pVM->state == INTERPRET)
1292 if (wordIsCompileOnly(tempFW))
1294 vmThrowErr(pVM, "Error: Compile only!");
1297 vmExecute(pVM, tempFW);
1300 else if (!isNumber(pVM, si))
1302 int i = SI_COUNT(si);
1303 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
1307 else /* (pVM->state == COMPILE) */
1311 if (wordIsImmediate(tempFW))
1313 vmExecute(pVM, tempFW);
1317 dictAppendCell(dp, LVALUEtoCELL(tempFW));
1320 else if (isNumber(pVM, si))
1326 int i = SI_COUNT(si);
1327 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
1335 /**************************************************************************
1336 l i t e r a l P a r e n
1338 ** This is the runtime for (literal). It assumes that it is part of a colon
1339 ** definition, and that the next CELL contains a value to be pushed on the
1340 ** parameter stack at runtime. This code is compiled by "literal".
1342 **************************************************************************/
1344 static void literalParen(FICL_VM *pVM)
1347 vmCheckStack(pVM, 0, 1);
1349 stackPushINT(pVM->pStack, *(FICL_INT *)(pVM->ip));
1350 vmBranchRelative(pVM, 1);
1354 static void twoLitParen(FICL_VM *pVM)
1357 vmCheckStack(pVM, 0, 2);
1359 stackPushINT(pVM->pStack, *((FICL_INT *)(pVM->ip)+1));
1360 stackPushINT(pVM->pStack, *(FICL_INT *)(pVM->ip));
1361 vmBranchRelative(pVM, 2);
1366 /**************************************************************************
1369 ** IMMEDIATE code for "literal". This function gets a value from the stack
1370 ** and compiles it into the dictionary preceded by the code for "(literal)".
1372 **************************************************************************/
1374 static void literalIm(FICL_VM *pVM)
1376 FICL_DICT *dp = ficlGetDict();
1379 dictAppendCell(dp, LVALUEtoCELL(pLitParen));
1380 dictAppendCell(dp, stackPop(pVM->pStack));
1386 static void twoLiteralIm(FICL_VM *pVM)
1388 FICL_DICT *dp = ficlGetDict();
1389 assert(pTwoLitParen);
1391 dictAppendCell(dp, LVALUEtoCELL(pTwoLitParen));
1392 dictAppendCell(dp, stackPop(pVM->pStack));
1393 dictAppendCell(dp, stackPop(pVM->pStack));
1398 /**************************************************************************
1401 **************************************************************************/
1403 static void listWords(FICL_VM *pVM)
1405 FICL_DICT *dp = ficlGetDict();
1406 FICL_HASH *pHash = dp->pSearch[dp->nLists - 1];
1414 char *pPad = pVM->pad;
1416 for (i = 0; i < pHash->size; i++)
1418 for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
1420 if (wp->nName == 0) /* ignore :noname defs */
1424 nChars += sprintf(pPad + nChars, "%s", cp);
1428 pPad[nChars] = '\0';
1433 vmTextOut(pVM, "--- Press Enter to continue ---",0);
1435 vmTextOut(pVM,"\r",0);
1437 vmTextOut(pVM, pPad, 1);
1441 len = nCOLWIDTH - nChars % nCOLWIDTH;
1443 pPad[nChars++] = ' ';
1448 pPad[nChars] = '\0';
1453 vmTextOut(pVM, "--- Press Enter to continue ---",0);
1455 vmTextOut(pVM,"\r",0);
1457 vmTextOut(pVM, pPad, 1);
1464 pPad[nChars] = '\0';
1466 vmTextOut(pVM, pPad, 1);
1469 sprintf(pVM->pad, "Dictionary: %d words, %ld cells used of %u total",
1470 nWords, (long) (dp->here - dp->dict), dp->size);
1471 vmTextOut(pVM, pVM->pad, 1);
1476 static void listEnv(FICL_VM *pVM)
1478 FICL_DICT *dp = ficlGetEnv();
1479 FICL_HASH *pHash = dp->pForthWords;
1484 for (i = 0; i < pHash->size; i++)
1486 for (wp = pHash->table[i]; wp != NULL; wp = wp->link, nWords++)
1488 vmTextOut(pVM, wp->name, 1);
1492 sprintf(pVM->pad, "Environment: %d words, %ld cells used of %u total",
1493 nWords, (long) (dp->here - dp->dict), dp->size);
1494 vmTextOut(pVM, pVM->pad, 1);
1499 /**************************************************************************
1500 l o g i c a n d c o m p a r i s o n s
1502 **************************************************************************/
1504 static void zeroEquals(FICL_VM *pVM)
1508 vmCheckStack(pVM, 1, 1);
1510 c.i = FICL_BOOL(stackPopINT(pVM->pStack) == 0);
1511 stackPush(pVM->pStack, c);
1515 static void zeroLess(FICL_VM *pVM)
1519 vmCheckStack(pVM, 1, 1);
1521 c.i = FICL_BOOL(stackPopINT(pVM->pStack) < 0);
1522 stackPush(pVM->pStack, c);
1526 static void zeroGreater(FICL_VM *pVM)
1530 vmCheckStack(pVM, 1, 1);
1532 c.i = FICL_BOOL(stackPopINT(pVM->pStack) > 0);
1533 stackPush(pVM->pStack, c);
1537 static void isEqual(FICL_VM *pVM)
1542 vmCheckStack(pVM, 2, 1);
1544 x = stackPop(pVM->pStack);
1545 y = stackPop(pVM->pStack);
1546 stackPushINT(pVM->pStack, FICL_BOOL(x.i == y.i));
1550 static void isLess(FICL_VM *pVM)
1554 vmCheckStack(pVM, 2, 1);
1556 y = stackPop(pVM->pStack);
1557 x = stackPop(pVM->pStack);
1558 stackPushINT(pVM->pStack, FICL_BOOL(x.i < y.i));
1562 static void uIsLess(FICL_VM *pVM)
1566 vmCheckStack(pVM, 2, 1);
1568 u2 = stackPopUNS(pVM->pStack);
1569 u1 = stackPopUNS(pVM->pStack);
1570 stackPushINT(pVM->pStack, FICL_BOOL(u1 < u2));
1574 static void isGreater(FICL_VM *pVM)
1578 vmCheckStack(pVM, 2, 1);
1580 y = stackPop(pVM->pStack);
1581 x = stackPop(pVM->pStack);
1582 stackPushINT(pVM->pStack, FICL_BOOL(x.i > y.i));
1586 static void bitwiseAnd(FICL_VM *pVM)
1590 vmCheckStack(pVM, 2, 1);
1592 x = stackPop(pVM->pStack);
1593 y = stackPop(pVM->pStack);
1594 stackPushINT(pVM->pStack, x.i & y.i);
1598 static void bitwiseOr(FICL_VM *pVM)
1602 vmCheckStack(pVM, 2, 1);
1604 x = stackPop(pVM->pStack);
1605 y = stackPop(pVM->pStack);
1606 stackPushINT(pVM->pStack, x.i | y.i);
1610 static void bitwiseXor(FICL_VM *pVM)
1614 vmCheckStack(pVM, 2, 1);
1616 x = stackPop(pVM->pStack);
1617 y = stackPop(pVM->pStack);
1618 stackPushINT(pVM->pStack, x.i ^ y.i);
1622 static void bitwiseNot(FICL_VM *pVM)
1626 vmCheckStack(pVM, 1, 1);
1628 x = stackPop(pVM->pStack);
1629 stackPushINT(pVM->pStack, ~x.i);
1634 /**************************************************************************
1636 ** do -- IMMEDIATE COMPILE ONLY
1637 ** Compiles code to initialize a loop: compile (do),
1638 ** allot space to hold the "leave" address, push a branch
1639 ** target address for the loop.
1640 ** (do) -- runtime for "do"
1641 ** pops index and limit from the p stack and moves them
1642 ** to the r stack, then skips to the loop body.
1643 ** loop -- IMMEDIATE COMPILE ONLY
1645 ** Compiles code for the test part of a loop:
1646 ** compile (loop), resolve forward branch from "do", and
1647 ** copy "here" address to the "leave" address allotted by "do"
1648 ** i,j,k -- COMPILE ONLY
1649 ** Runtime: Push loop indices on param stack (i is innermost loop...)
1650 ** Note: each loop has three values on the return stack:
1651 ** ( R: leave limit index )
1652 ** "leave" is the absolute address of the next cell after the loop
1653 ** limit and index are the loop control variables.
1654 ** leave -- COMPILE ONLY
1655 ** Runtime: pop the loop control variables, then pop the
1656 ** "leave" address and jump (absolute) there.
1657 **************************************************************************/
1659 static void doCoIm(FICL_VM *pVM)
1661 FICL_DICT *dp = ficlGetDict();
1665 dictAppendCell(dp, LVALUEtoCELL(pDoParen));
1667 ** Allot space for a pointer to the end
1668 ** of the loop - "leave" uses this...
1670 markBranch(dp, pVM, leaveTag);
1671 dictAppendUNS(dp, 0);
1673 ** Mark location of head of loop...
1675 markBranch(dp, pVM, doTag);
1681 static void doParen(FICL_VM *pVM)
1685 vmCheckStack(pVM, 2, 0);
1687 index = stackPop(pVM->pStack);
1688 limit = stackPop(pVM->pStack);
1690 /* copy "leave" target addr to stack */
1691 stackPushPtr(pVM->rStack, *(pVM->ip++));
1692 stackPush(pVM->rStack, limit);
1693 stackPush(pVM->rStack, index);
1699 static void qDoCoIm(FICL_VM *pVM)
1701 FICL_DICT *dp = ficlGetDict();
1705 dictAppendCell(dp, LVALUEtoCELL(pQDoParen));
1707 ** Allot space for a pointer to the end
1708 ** of the loop - "leave" uses this...
1710 markBranch(dp, pVM, leaveTag);
1711 dictAppendUNS(dp, 0);
1713 ** Mark location of head of loop...
1715 markBranch(dp, pVM, doTag);
1721 static void qDoParen(FICL_VM *pVM)
1725 vmCheckStack(pVM, 2, 0);
1727 index = stackPop(pVM->pStack);
1728 limit = stackPop(pVM->pStack);
1730 /* copy "leave" target addr to stack */
1731 stackPushPtr(pVM->rStack, *(pVM->ip++));
1733 if (limit.u == index.u)
1739 stackPush(pVM->rStack, limit);
1740 stackPush(pVM->rStack, index);
1748 ** Runtime code to break out of a do..loop construct
1749 ** Drop the loop control variables; the branch address
1750 ** past "loop" is next on the return stack.
1752 static void leaveCo(FICL_VM *pVM)
1755 stackDrop(pVM->rStack, 2);
1762 static void unloopCo(FICL_VM *pVM)
1764 stackDrop(pVM->rStack, 3);
1769 static void loopCoIm(FICL_VM *pVM)
1771 FICL_DICT *dp = ficlGetDict();
1775 dictAppendCell(dp, LVALUEtoCELL(pLoopParen));
1776 resolveBackBranch(dp, pVM, doTag);
1777 resolveAbsBranch(dp, pVM, leaveTag);
1782 static void plusLoopCoIm(FICL_VM *pVM)
1784 FICL_DICT *dp = ficlGetDict();
1786 assert(pPLoopParen);
1788 dictAppendCell(dp, LVALUEtoCELL(pPLoopParen));
1789 resolveBackBranch(dp, pVM, doTag);
1790 resolveAbsBranch(dp, pVM, leaveTag);
1795 static void loopParen(FICL_VM *pVM)
1797 FICL_INT index = stackGetTop(pVM->rStack).i;
1798 FICL_INT limit = stackFetch(pVM->rStack, 1).i;
1804 stackDrop(pVM->rStack, 3); /* nuke the loop indices & "leave" addr */
1805 vmBranchRelative(pVM, 1); /* fall through the loop */
1808 { /* update index, branch to loop head */
1809 stackSetTop(pVM->rStack, LVALUEtoCELL(index));
1810 vmBranchRelative(pVM, *(int *)(pVM->ip));
1817 static void plusLoopParen(FICL_VM *pVM)
1819 FICL_INT index = stackGetTop(pVM->rStack).i;
1820 FICL_INT limit = stackFetch(pVM->rStack, 1).i;
1821 FICL_INT increment = stackPop(pVM->pStack).i;
1827 flag = (index < limit);
1829 flag = (index >= limit);
1833 stackDrop(pVM->rStack, 3); /* nuke the loop indices & "leave" addr */
1834 vmBranchRelative(pVM, 1); /* fall through the loop */
1837 { /* update index, branch to loop head */
1838 stackSetTop(pVM->rStack, LVALUEtoCELL(index));
1839 vmBranchRelative(pVM, *(int *)(pVM->ip));
1846 static void loopICo(FICL_VM *pVM)
1848 CELL index = stackGetTop(pVM->rStack);
1849 stackPush(pVM->pStack, index);
1855 static void loopJCo(FICL_VM *pVM)
1857 CELL index = stackFetch(pVM->rStack, 3);
1858 stackPush(pVM->pStack, index);
1864 static void loopKCo(FICL_VM *pVM)
1866 CELL index = stackFetch(pVM->rStack, 6);
1867 stackPush(pVM->pStack, index);
1873 /**************************************************************************
1874 r e t u r n s t a c k
1876 **************************************************************************/
1878 static void toRStack(FICL_VM *pVM)
1880 stackPush(pVM->rStack, stackPop(pVM->pStack));
1884 static void fromRStack(FICL_VM *pVM)
1886 stackPush(pVM->pStack, stackPop(pVM->rStack));
1890 static void fetchRStack(FICL_VM *pVM)
1892 stackPush(pVM->pStack, stackGetTop(pVM->rStack));
1897 /**************************************************************************
1900 **************************************************************************/
1902 static void variableParen(FICL_VM *pVM)
1904 FICL_WORD *fw = pVM->runningWord;
1905 stackPushPtr(pVM->pStack, fw->param);
1910 static void variable(FICL_VM *pVM)
1912 FICL_DICT *dp = ficlGetDict();
1913 STRINGINFO si = vmGetWord(pVM);
1915 dictAppendWord2(dp, si, variableParen, FW_DEFAULT);
1916 dictAllotCells(dp, 1);
1922 /**************************************************************************
1923 b a s e & f r i e n d s
1925 **************************************************************************/
1927 static void base(FICL_VM *pVM)
1929 CELL *pBase = (CELL *)(&pVM->base);
1930 stackPush(pVM->pStack, LVALUEtoCELL(pBase));
1935 static void decimal(FICL_VM *pVM)
1942 static void hex(FICL_VM *pVM)
1949 /**************************************************************************
1950 a l l o t & f r i e n d s
1952 **************************************************************************/
1954 static void allot(FICL_VM *pVM)
1956 FICL_DICT *dp = ficlGetDict();
1957 FICL_INT i = stackPopINT(pVM->pStack);
1959 dictCheck(dp, pVM, i);
1966 static void here(FICL_VM *pVM)
1968 FICL_DICT *dp = ficlGetDict();
1969 stackPushPtr(pVM->pStack, dp->here);
1974 static void comma(FICL_VM *pVM)
1976 FICL_DICT *dp = ficlGetDict();
1977 CELL c = stackPop(pVM->pStack);
1978 dictAppendCell(dp, c);
1983 static void cComma(FICL_VM *pVM)
1985 FICL_DICT *dp = ficlGetDict();
1986 char c = (char)stackPopINT(pVM->pStack);
1987 dictAppendChar(dp, c);
1992 static void cells(FICL_VM *pVM)
1994 FICL_INT i = stackPopINT(pVM->pStack);
1995 stackPushINT(pVM->pStack, i * (FICL_INT)sizeof (CELL));
2000 static void cellPlus(FICL_VM *pVM)
2002 char *cp = stackPopPtr(pVM->pStack);
2003 stackPushPtr(pVM->pStack, cp + sizeof (CELL));
2008 /**************************************************************************
2010 ** tick CORE ( "<spaces>name" -- xt )
2011 ** Skip leading space delimiters. Parse name delimited by a space. Find
2012 ** name and return xt, the execution token for name. An ambiguous condition
2013 ** exists if name is not found.
2014 **************************************************************************/
2015 static void tick(FICL_VM *pVM)
2017 FICL_WORD *pFW = NULL;
2018 STRINGINFO si = vmGetWord(pVM);
2020 pFW = dictLookup(ficlGetDict(), si);
2023 int i = SI_COUNT(si);
2024 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
2026 stackPushPtr(pVM->pStack, pFW);
2031 static void bracketTickCoIm(FICL_VM *pVM)
2040 /**************************************************************************
2042 ** Lookup the next word in the input stream and compile code to
2043 ** insert it into definitions created by the resulting word
2044 ** (defers compilation, even of immediate words)
2045 **************************************************************************/
2047 static void postponeCoIm(FICL_VM *pVM)
2049 FICL_DICT *dp = ficlGetDict();
2054 pFW = stackGetTop(pVM->pStack).p;
2055 if (wordIsImmediate(pFW))
2057 dictAppendCell(dp, stackPop(pVM->pStack));
2062 dictAppendCell(dp, LVALUEtoCELL(pComma));
2070 /**************************************************************************
2072 ** Pop an execution token (pointer to a word) off the stack and
2074 **************************************************************************/
2076 static void execute(FICL_VM *pVM)
2080 vmCheckStack(pVM, 1, 0);
2083 pFW = stackPopPtr(pVM->pStack);
2084 vmExecute(pVM, pFW);
2090 /**************************************************************************
2092 ** Make the most recently compiled word IMMEDIATE -- it executes even
2093 ** in compile state (most often used for control compiling words
2094 ** such as IF, THEN, etc)
2095 **************************************************************************/
2097 static void immediate(FICL_VM *pVM)
2100 dictSetImmediate(ficlGetDict());
2105 static void compileOnly(FICL_VM *pVM)
2108 dictSetFlags(ficlGetDict(), FW_COMPILE, 0);
2113 /**************************************************************************
2115 ** IMMEDIATE word that compiles a string literal for later display
2116 ** Compile stringLit, then copy the bytes of the string from the TIB
2117 ** to the dictionary. Backpatch the count byte and align the dictionary.
2119 ** stringlit: Fetch the count from the dictionary, then push the address
2120 ** and count on the stack. Finally, update ip to point to the first
2121 ** aligned address after the string text.
2122 **************************************************************************/
2124 static void stringLit(FICL_VM *pVM)
2126 FICL_STRING *sp = (FICL_STRING *)(pVM->ip);
2127 FICL_COUNT count = sp->count;
2128 char *cp = sp->text;
2129 stackPushPtr(pVM->pStack, cp);
2130 stackPushUNS(pVM->pStack, count);
2133 pVM->ip = (IPTYPE)(void *)cp;
2137 static void dotQuoteCoIm(FICL_VM *pVM)
2139 FICL_DICT *dp = ficlGetDict();
2140 dictAppendCell(dp, LVALUEtoCELL(pStringLit));
2141 dp->here = PTRtoCELL vmGetString(pVM, (FICL_STRING *)dp->here, '\"');
2143 dictAppendCell(dp, LVALUEtoCELL(pType));
2148 static void dotParen(FICL_VM *pVM)
2150 char *pSrc = vmGetInBuf(pVM);
2151 char *pEnd = vmGetInBufEnd(pVM);
2152 char *pDest = pVM->pad;
2155 for (ch = *pSrc; (pEnd != pSrc) && (ch != ')'); ch = *++pSrc)
2159 if ((pEnd != pSrc) && (ch == ')'))
2162 vmTextOut(pVM, pVM->pad, 0);
2163 vmUpdateTib(pVM, pSrc);
2169 /**************************************************************************
2172 ** Interpretation: Interpretation semantics for this word are undefined.
2173 ** Compilation: ( c-addr1 u -- )
2174 ** Append the run-time semantics given below to the current definition.
2175 ** Run-time: ( -- c-addr2 u )
2176 ** Return c-addr2 u describing a string consisting of the characters
2177 ** specified by c-addr1 u during compilation. A program shall not alter
2178 ** the returned string.
2179 **************************************************************************/
2180 static void sLiteralCoIm(FICL_VM *pVM)
2182 FICL_DICT *dp = ficlGetDict();
2185 u = stackPopUNS(pVM->pStack);
2186 cp = stackPopPtr(pVM->pStack);
2188 dictAppendCell(dp, LVALUEtoCELL(pStringLit));
2189 cpDest = (char *) dp->here;
2190 *cpDest++ = (char) u;
2198 dp->here = PTRtoCELL alignPtr(cpDest);
2203 /**************************************************************************
2205 ** Return the address of the VM's state member (must be sized the
2206 ** same as a CELL for this reason)
2207 **************************************************************************/
2208 static void state(FICL_VM *pVM)
2210 stackPushPtr(pVM->pStack, &pVM->state);
2215 /**************************************************************************
2216 c r e a t e . . . d o e s >
2217 ** Make a new word in the dictionary with the run-time effect of
2218 ** a variable (push my address), but with extra space allotted
2219 ** for use by does> .
2220 **************************************************************************/
2222 static void createParen(FICL_VM *pVM)
2224 CELL *pCell = pVM->runningWord->param;
2225 stackPushPtr(pVM->pStack, pCell+1);
2230 static void create(FICL_VM *pVM)
2232 FICL_DICT *dp = ficlGetDict();
2233 STRINGINFO si = vmGetWord(pVM);
2235 dictAppendWord2(dp, si, createParen, FW_DEFAULT);
2236 dictAllotCells(dp, 1);
2241 static void doDoes(FICL_VM *pVM)
2243 CELL *pCell = pVM->runningWord->param;
2244 IPTYPE tempIP = (IPTYPE)((*pCell).p);
2245 stackPushPtr(pVM->pStack, pCell+1);
2246 vmPushIP(pVM, tempIP);
2251 static void doesParen(FICL_VM *pVM)
2253 FICL_DICT *dp = ficlGetDict();
2254 dp->smudge->code = doDoes;
2255 dp->smudge->param[0] = LVALUEtoCELL(pVM->ip);
2261 static void doesCoIm(FICL_VM *pVM)
2263 FICL_DICT *dp = ficlGetDict();
2264 #if FICL_WANT_LOCALS
2265 assert(pUnLinkParen);
2268 FICL_DICT *pLoc = ficlGetLoc();
2269 dictEmpty(pLoc, pLoc->pForthWords->size);
2270 dictAppendCell(dp, LVALUEtoCELL(pUnLinkParen));
2277 dictAppendCell(dp, LVALUEtoCELL(pDoesParen));
2282 /**************************************************************************
2284 ** to-body CORE ( xt -- a-addr )
2285 ** a-addr is the data-field address corresponding to xt. An ambiguous
2286 ** condition exists if xt is not for a word defined via CREATE.
2287 **************************************************************************/
2288 static void toBody(FICL_VM *pVM)
2290 FICL_WORD *pFW = stackPopPtr(pVM->pStack);
2291 stackPushPtr(pVM->pStack, pFW->param + 1);
2297 ** from-body ficl ( a-addr -- xt )
2298 ** Reverse effect of >body
2300 static void fromBody(FICL_VM *pVM)
2302 char *ptr = (char *) stackPopPtr(pVM->pStack) - sizeof (FICL_WORD);
2303 stackPushPtr(pVM->pStack, ptr);
2309 ** >name ficl ( xt -- c-addr u )
2310 ** Push the address and length of a word's name given its address
2313 static void toName(FICL_VM *pVM)
2315 FICL_WORD *pFW = stackPopPtr(pVM->pStack);
2316 stackPushPtr(pVM->pStack, pFW->name);
2317 stackPushUNS(pVM->pStack, pFW->nName);
2322 /**************************************************************************
2323 l b r a c k e t e t c
2325 **************************************************************************/
2327 static void lbracketCoIm(FICL_VM *pVM)
2329 pVM->state = INTERPRET;
2334 static void rbracket(FICL_VM *pVM)
2336 pVM->state = COMPILE;
2341 /**************************************************************************
2342 p i c t u r e d n u m e r i c w o r d s
2344 ** less-number-sign CORE ( -- )
2345 ** Initialize the pictured numeric output conversion process.
2347 **************************************************************************/
2348 static void lessNumberSign(FICL_VM *pVM)
2350 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2356 ** number-sign CORE ( ud1 -- ud2 )
2357 ** Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
2358 ** n. (n is the least-significant digit of ud1.) Convert n to external form
2359 ** and add the resulting character to the beginning of the pictured numeric
2360 ** output string. An ambiguous condition exists if # executes outside of a
2361 ** <# #> delimited number conversion.
2363 static void numberSign(FICL_VM *pVM)
2365 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2369 u = u64Pop(pVM->pStack);
2370 rem = m64UMod(&u, (UNS16)(pVM->base));
2371 sp->text[sp->count++] = digit_to_char(rem);
2372 u64Push(pVM->pStack, u);
2377 ** number-sign-greater CORE ( xd -- c-addr u )
2378 ** Drop xd. Make the pictured numeric output string available as a character
2379 ** string. c-addr and u specify the resulting character string. A program
2380 ** may replace characters within the string.
2382 static void numberSignGreater(FICL_VM *pVM)
2384 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2385 sp->text[sp->count] = '\0';
2387 stackDrop(pVM->pStack, 2);
2388 stackPushPtr(pVM->pStack, sp->text);
2389 stackPushUNS(pVM->pStack, sp->count);
2394 ** number-sign-s CORE ( ud1 -- ud2 )
2395 ** Convert one digit of ud1 according to the rule for #. Continue conversion
2396 ** until the quotient is zero. ud2 is zero. An ambiguous condition exists if
2397 ** #S executes outside of a <# #> delimited number conversion.
2398 ** TO DO: presently does not use ud1 hi cell - use it!
2400 static void numberSignS(FICL_VM *pVM)
2402 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2406 u = u64Pop(pVM->pStack);
2410 rem = m64UMod(&u, (UNS16)(pVM->base));
2411 sp->text[sp->count++] = digit_to_char(rem);
2413 while (u.hi || u.lo);
2415 u64Push(pVM->pStack, u);
2420 ** HOLD CORE ( char -- )
2421 ** Add char to the beginning of the pictured numeric output string. An ambiguous
2422 ** condition exists if HOLD executes outside of a <# #> delimited number conversion.
2424 static void hold(FICL_VM *pVM)
2426 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2427 int i = stackPopINT(pVM->pStack);
2428 sp->text[sp->count++] = (char) i;
2433 ** SIGN CORE ( n -- )
2434 ** If n is negative, add a minus sign to the beginning of the pictured
2435 ** numeric output string. An ambiguous condition exists if SIGN
2436 ** executes outside of a <# #> delimited number conversion.
2438 static void sign(FICL_VM *pVM)
2440 FICL_STRING *sp = PTRtoSTRING pVM->pad;
2441 int i = stackPopINT(pVM->pStack);
2443 sp->text[sp->count++] = '-';
2448 /**************************************************************************
2450 ** to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
2451 ** ud2 is the unsigned result of converting the characters within the
2452 ** string specified by c-addr1 u1 into digits, using the number in BASE,
2453 ** and adding each into ud1 after multiplying ud1 by the number in BASE.
2454 ** Conversion continues left-to-right until a character that is not
2455 ** convertible, including any + or -, is encountered or the string is
2456 ** entirely converted. c-addr2 is the location of the first unconverted
2457 ** character or the first character past the end of the string if the string
2458 ** was entirely converted. u2 is the number of unconverted characters in the
2459 ** string. An ambiguous condition exists if ud2 overflows during the
2461 **************************************************************************/
2462 static void toNumber(FICL_VM *pVM)
2464 FICL_UNS count = stackPopUNS(pVM->pStack);
2465 char *cp = (char *)stackPopPtr(pVM->pStack);
2467 FICL_UNS base = pVM->base;
2471 accum = u64Pop(pVM->pStack);
2473 for (ch = *cp; count > 0; ch = *++cp, count--)
2481 digit = tolower(ch) - 'a' + 10;
2483 ** Note: following test also catches chars between 9 and a
2484 ** because 'digit' is unsigned!
2489 accum = m64Mac(accum, base, digit);
2492 u64Push(pVM->pStack, accum);
2493 stackPushPtr (pVM->pStack, cp);
2494 stackPushUNS(pVM->pStack, count);
2501 /**************************************************************************
2503 ** quit CORE ( -- ) ( R: i*x -- )
2504 ** Empty the return stack, store zero in SOURCE-ID if it is present, make
2505 ** the user input device the input source, and enter interpretation state.
2506 ** Do not display a message. Repeat the following:
2508 ** Accept a line from the input source into the input buffer, set >IN to
2509 ** zero, and interpret.
2510 ** Display the implementation-defined system prompt if in
2511 ** interpretation state, all processing has been completed, and no
2512 ** ambiguous condition exists.
2513 **************************************************************************/
2515 static void quit(FICL_VM *pVM)
2517 vmThrow(pVM, VM_QUIT);
2522 static void ficlAbort(FICL_VM *pVM)
2524 vmThrow(pVM, VM_ABORT);
2529 /**************************************************************************
2531 ** accept CORE ( c-addr +n1 -- +n2 )
2532 ** Receive a string of at most +n1 characters. An ambiguous condition
2533 ** exists if +n1 is zero or greater than 32,767. Display graphic characters
2534 ** as they are received. A program that depends on the presence or absence
2535 ** of non-graphic characters in the string has an environmental dependency.
2536 ** The editing functions, if any, that the system performs in order to
2537 ** construct the string are implementation-defined.
2539 ** (Although the standard text doesn't say so, I assume that the intent
2540 ** of 'accept' is to store the string at the address specified on
2542 ** Implementation: if there's more text in the TIB, use it. Otherwise
2543 ** throw out for more text. Copy characters up to the max count into the
2544 ** address given, and return the number of actual characters copied.
2546 ** Note (sobral) this may not be the behavior you'd expect if you're
2547 ** trying to get user input at load time!
2548 **************************************************************************/
2549 static void accept(FICL_VM *pVM)
2553 char *pBuf = vmGetInBuf(pVM);
2554 char *pEnd = vmGetInBufEnd(pVM);
2555 FICL_INT len = pEnd - pBuf;
2558 vmThrow(pVM, VM_RESTART);
2561 ** Now we have something in the text buffer - use it
2563 count = stackPopINT(pVM->pStack);
2564 cp = stackPopPtr(pVM->pStack);
2566 len = (count < len) ? count : len;
2567 strncpy(cp, vmGetInBuf(pVM), len);
2569 vmUpdateTib(pVM, pBuf);
2570 stackPushINT(pVM->pStack, len);
2576 /**************************************************************************
2578 ** 6.1.0705 ALIGN CORE ( -- )
2579 ** If the data-space pointer is not aligned, reserve enough space to
2581 **************************************************************************/
2582 static void align(FICL_VM *pVM)
2584 FICL_DICT *dp = ficlGetDict();
2591 /**************************************************************************
2594 **************************************************************************/
2595 static void aligned(FICL_VM *pVM)
2597 void *addr = stackPopPtr(pVM->pStack);
2598 stackPushPtr(pVM->pStack, alignPtr(addr));
2603 /**************************************************************************
2604 b e g i n & f r i e n d s
2605 ** Indefinite loop control structures
2608 ** : X ... BEGIN ... test UNTIL ;
2610 ** : X ... BEGIN ... test WHILE ... REPEAT ;
2611 **************************************************************************/
2612 static void beginCoIm(FICL_VM *pVM)
2614 FICL_DICT *dp = ficlGetDict();
2615 markBranch(dp, pVM, destTag);
2619 static void untilCoIm(FICL_VM *pVM)
2621 FICL_DICT *dp = ficlGetDict();
2625 dictAppendCell(dp, LVALUEtoCELL(pIfParen));
2626 resolveBackBranch(dp, pVM, destTag);
2630 static void whileCoIm(FICL_VM *pVM)
2632 FICL_DICT *dp = ficlGetDict();
2636 dictAppendCell(dp, LVALUEtoCELL(pIfParen));
2637 markBranch(dp, pVM, origTag);
2639 dictAppendUNS(dp, 1);
2643 static void repeatCoIm(FICL_VM *pVM)
2645 FICL_DICT *dp = ficlGetDict();
2647 assert(pBranchParen);
2648 dictAppendCell(dp, LVALUEtoCELL(pBranchParen));
2650 /* expect "begin" branch marker */
2651 resolveBackBranch(dp, pVM, destTag);
2652 /* expect "while" branch marker */
2653 resolveForwardBranch(dp, pVM, origTag);
2658 static void againCoIm(FICL_VM *pVM)
2660 FICL_DICT *dp = ficlGetDict();
2662 assert(pBranchParen);
2663 dictAppendCell(dp, LVALUEtoCELL(pBranchParen));
2665 /* expect "begin" branch marker */
2666 resolveBackBranch(dp, pVM, destTag);
2671 /**************************************************************************
2672 c h a r & f r i e n d s
2673 ** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
2674 ** Skip leading space delimiters. Parse name delimited by a space.
2675 ** Put the value of its first character onto the stack.
2677 ** bracket-char CORE
2678 ** Interpretation: Interpretation semantics for this word are undefined.
2679 ** Compilation: ( "<spaces>name" -- )
2680 ** Skip leading space delimiters. Parse name delimited by a space.
2681 ** Append the run-time semantics given below to the current definition.
2682 ** Run-time: ( -- char )
2683 ** Place char, the value of the first character of name, on the stack.
2684 **************************************************************************/
2685 static void ficlChar(FICL_VM *pVM)
2687 STRINGINFO si = vmGetWord(pVM);
2688 stackPushUNS(pVM->pStack, (FICL_UNS)(si.cp[0]));
2693 static void charCoIm(FICL_VM *pVM)
2700 /**************************************************************************
2702 ** char-plus CORE ( c-addr1 -- c-addr2 )
2703 ** Add the size in address units of a character to c-addr1, giving c-addr2.
2704 **************************************************************************/
2705 static void charPlus(FICL_VM *pVM)
2707 char *cp = stackPopPtr(pVM->pStack);
2708 stackPushPtr(pVM->pStack, cp + 1);
2712 /**************************************************************************
2714 ** chars CORE ( n1 -- n2 )
2715 ** n2 is the size in address units of n1 characters.
2716 ** For most processors, this function can be a no-op. To guarantee
2717 ** portability, we'll multiply by sizeof (char).
2718 **************************************************************************/
2719 #if defined (_M_IX86)
2720 #pragma warning(disable: 4127)
2722 static void ficlChars(FICL_VM *pVM)
2724 if (sizeof (char) > 1)
2726 FICL_INT i = stackPopINT(pVM->pStack);
2727 stackPushINT(pVM->pStack, i * sizeof (char));
2729 /* otherwise no-op! */
2732 #if defined (_M_IX86)
2733 #pragma warning(default: 4127)
2737 /**************************************************************************
2739 ** COUNT CORE ( c-addr1 -- c-addr2 u )
2740 ** Return the character string specification for the counted string stored
2741 ** at c-addr1. c-addr2 is the address of the first character after c-addr1.
2742 ** u is the contents of the character at c-addr1, which is the length in
2743 ** characters of the string at c-addr2.
2744 **************************************************************************/
2745 static void count(FICL_VM *pVM)
2747 FICL_STRING *sp = stackPopPtr(pVM->pStack);
2748 stackPushPtr(pVM->pStack, sp->text);
2749 stackPushUNS(pVM->pStack, sp->count);
2753 /**************************************************************************
2754 e n v i r o n m e n t ?
2755 ** environment-query CORE ( c-addr u -- false | i*x true )
2756 ** c-addr is the address of a character string and u is the string's
2757 ** character count. u may have a value in the range from zero to an
2758 ** implementation-defined maximum which shall not be less than 31. The
2759 ** character string should contain a keyword from 3.2.6 Environmental
2760 ** queries or the optional word sets to be checked for correspondence
2761 ** with an attribute of the present environment. If the system treats the
2762 ** attribute as unknown, the returned flag is false; otherwise, the flag
2763 ** is true and the i*x returned is of the type specified in the table for
2764 ** the attribute queried.
2765 **************************************************************************/
2766 static void environmentQ(FICL_VM *pVM)
2768 FICL_DICT *envp = ficlGetEnv();
2769 FICL_COUNT len = (FICL_COUNT)stackPopUNS(pVM->pStack);
2770 char *cp = stackPopPtr(pVM->pStack);
2775 &len; /* silence compiler warning... */
2777 pFW = dictLookup(envp, si);
2781 vmExecute(pVM, pFW);
2782 stackPushINT(pVM->pStack, FICL_TRUE);
2786 stackPushINT(pVM->pStack, FICL_FALSE);
2792 /**************************************************************************
2794 ** EVALUATE CORE ( i*x c-addr u -- j*x )
2795 ** Save the current input source specification. Store minus-one (-1) in
2796 ** SOURCE-ID if it is present. Make the string described by c-addr and u
2797 ** both the input source and input buffer, set >IN to zero, and interpret.
2798 ** When the parse area is empty, restore the prior input source
2799 ** specification. Other stack effects are due to the words EVALUATEd.
2801 **************************************************************************/
2802 static void evaluate(FICL_VM *pVM)
2804 FICL_INT count = stackPopINT(pVM->pStack);
2805 char *cp = stackPopPtr(pVM->pStack);
2810 pVM->sourceID.i = -1;
2811 result = ficlExecC(pVM, cp, count);
2813 if (result != VM_OUTOFTEXT)
2814 vmThrow(pVM, result);
2820 /**************************************************************************
2821 s t r i n g q u o t e
2822 ** Intrpreting: get string delimited by a quote from the input stream,
2823 ** copy to a scratch area, and put its count and address on the stack.
2824 ** Compiling: compile code to push the address and count of a string
2825 ** literal, compile the string from the input stream, and align the dict
2827 **************************************************************************/
2828 static void stringQuoteIm(FICL_VM *pVM)
2830 FICL_DICT *dp = ficlGetDict();
2832 if (pVM->state == INTERPRET)
2834 FICL_STRING *sp = (FICL_STRING *) dp->here;
2835 vmGetString(pVM, sp, '\"');
2836 stackPushPtr(pVM->pStack, sp->text);
2837 stackPushUNS(pVM->pStack, sp->count);
2839 else /* COMPILE state */
2841 dictAppendCell(dp, LVALUEtoCELL(pStringLit));
2842 dp->here = PTRtoCELL vmGetString(pVM, (FICL_STRING *)dp->here, '\"');
2850 /**************************************************************************
2852 ** Pop count and char address from stack and print the designated string.
2853 **************************************************************************/
2854 static void type(FICL_VM *pVM)
2856 FICL_UNS count = stackPopUNS(pVM->pStack);
2857 char *cp = stackPopPtr(pVM->pStack);
2858 char *pDest = (char *)ficlMalloc(count + 1);
2861 ** Since we don't have an output primitive for a counted string
2862 ** (oops), make sure the string is null terminated. If not, copy
2863 ** and terminate it.
2866 vmThrowErr(pVM, "Error: out of memory");
2868 strncpy(pDest, cp, count);
2869 pDest[count] = '\0';
2871 vmTextOut(pVM, pDest, 0);
2877 /**************************************************************************
2879 ** word CORE ( char "<chars>ccc<char>" -- c-addr )
2880 ** Skip leading delimiters. Parse characters ccc delimited by char. An
2881 ** ambiguous condition exists if the length of the parsed string is greater
2882 ** than the implementation-defined length of a counted string.
2884 ** c-addr is the address of a transient region containing the parsed word
2885 ** as a counted string. If the parse area was empty or contained no
2886 ** characters other than the delimiter, the resulting string has a zero
2887 ** length. A space, not included in the length, follows the string. A
2888 ** program may replace characters within the string.
2889 ** NOTE! Ficl also NULL-terminates the dest string.
2890 **************************************************************************/
2891 static void ficlWord(FICL_VM *pVM)
2893 FICL_STRING *sp = (FICL_STRING *)pVM->pad;
2894 char delim = (char)stackPopINT(pVM->pStack);
2897 si = vmParseStringEx(pVM, delim, 1);
2899 if (SI_COUNT(si) > nPAD-1)
2900 SI_SETLEN(si, nPAD-1);
2902 sp->count = (FICL_COUNT)SI_COUNT(si);
2903 strncpy(sp->text, SI_PTR(si), SI_COUNT(si));
2904 strcat(sp->text, " ");
2906 stackPushPtr(pVM->pStack, sp);
2911 /**************************************************************************
2913 ** ficl PARSE-WORD ( <spaces>name -- c-addr u )
2914 ** Skip leading spaces and parse name delimited by a space. c-addr is the
2915 ** address within the input buffer and u is the length of the selected
2916 ** string. If the parse area is empty, the resulting string has a zero length.
2917 **************************************************************************/
2918 static void parseNoCopy(FICL_VM *pVM)
2920 STRINGINFO si = vmGetWord0(pVM);
2921 stackPushPtr(pVM->pStack, SI_PTR(si));
2922 stackPushUNS(pVM->pStack, SI_COUNT(si));
2927 /**************************************************************************
2929 ** CORE EXT ( char "ccc<char>" -- c-addr u )
2930 ** Parse ccc delimited by the delimiter char.
2931 ** c-addr is the address (within the input buffer) and u is the length of
2932 ** the parsed string. If the parse area was empty, the resulting string has
2934 ** NOTE! PARSE differs from WORD: it does not skip leading delimiters.
2935 **************************************************************************/
2936 static void parse(FICL_VM *pVM)
2939 char delim = (char)stackPopINT(pVM->pStack);
2941 si = vmParseStringEx(pVM, delim, 0);
2942 stackPushPtr(pVM->pStack, SI_PTR(si));
2943 stackPushUNS(pVM->pStack, SI_COUNT(si));
2948 /**************************************************************************
2950 ** CORE ( c-addr u char -- )
2951 ** If u is greater than zero, store char in each of u consecutive
2952 ** characters of memory beginning at c-addr.
2953 **************************************************************************/
2954 static void fill(FICL_VM *pVM)
2956 char ch = (char)stackPopINT(pVM->pStack);
2957 FICL_UNS u = stackPopUNS(pVM->pStack);
2958 char *cp = (char *)stackPopPtr(pVM->pStack);
2970 /**************************************************************************
2972 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
2973 ** Find the definition named in the counted string at c-addr. If the
2974 ** definition is not found, return c-addr and zero. If the definition is
2975 ** found, return its execution token xt. If the definition is immediate,
2976 ** also return one (1), otherwise also return minus-one (-1). For a given
2977 ** string, the values returned by FIND while compiling may differ from
2978 ** those returned while not compiling.
2979 **************************************************************************/
2980 static void find(FICL_VM *pVM)
2982 FICL_STRING *sp = stackPopPtr(pVM->pStack);
2987 pFW = dictLookup(ficlGetDict(), si);
2990 stackPushPtr(pVM->pStack, pFW);
2991 stackPushINT(pVM->pStack, (wordIsImmediate(pFW) ? 1 : -1));
2995 stackPushPtr(pVM->pStack, sp);
2996 stackPushUNS(pVM->pStack, 0);
3003 /**************************************************************************
3005 ** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
3006 ** Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
3007 ** Input and output stack arguments are signed. An ambiguous condition
3008 ** exists if n1 is zero or if the quotient lies outside the range of a
3009 ** single-cell signed integer.
3010 **************************************************************************/
3011 static void fmSlashMod(FICL_VM *pVM)
3017 n1 = stackPopINT(pVM->pStack);
3018 d1 = i64Pop(pVM->pStack);
3019 qr = m64FlooredDivI(d1, n1);
3020 stackPushINT(pVM->pStack, qr.rem);
3021 stackPushINT(pVM->pStack, qr.quot);
3026 /**************************************************************************
3028 ** s-m-slash-rem CORE ( d1 n1 -- n2 n3 )
3029 ** Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
3030 ** Input and output stack arguments are signed. An ambiguous condition
3031 ** exists if n1 is zero or if the quotient lies outside the range of a
3032 ** single-cell signed integer.
3033 **************************************************************************/
3034 static void smSlashRem(FICL_VM *pVM)
3040 n1 = stackPopINT(pVM->pStack);
3041 d1 = i64Pop(pVM->pStack);
3042 qr = m64SymmetricDivI(d1, n1);
3043 stackPushINT(pVM->pStack, qr.rem);
3044 stackPushINT(pVM->pStack, qr.quot);
3049 static void ficlMod(FICL_VM *pVM)
3055 n1 = stackPopINT(pVM->pStack);
3056 d1.lo = stackPopINT(pVM->pStack);
3058 qr = m64SymmetricDivI(d1, n1);
3059 stackPushINT(pVM->pStack, qr.rem);
3064 /**************************************************************************
3066 ** u-m-slash-mod CORE ( ud u1 -- u2 u3 )
3067 ** Divide ud by u1, giving the quotient u3 and the remainder u2.
3068 ** All values and arithmetic are unsigned. An ambiguous condition
3069 ** exists if u1 is zero or if the quotient lies outside the range of a
3070 ** single-cell unsigned integer.
3071 *************************************************************************/
3072 static void umSlashMod(FICL_VM *pVM)
3078 u1 = stackPopUNS(pVM->pStack);
3079 ud = u64Pop(pVM->pStack);
3080 qr = ficlLongDiv(ud, u1);
3081 stackPushUNS(pVM->pStack, qr.rem);
3082 stackPushUNS(pVM->pStack, qr.quot);
3087 /**************************************************************************
3089 ** l-shift CORE ( x1 u -- x2 )
3090 ** Perform a logical left shift of u bit-places on x1, giving x2.
3091 ** Put zeroes into the least significant bits vacated by the shift.
3092 ** An ambiguous condition exists if u is greater than or equal to the
3093 ** number of bits in a cell.
3095 ** r-shift CORE ( x1 u -- x2 )
3096 ** Perform a logical right shift of u bit-places on x1, giving x2.
3097 ** Put zeroes into the most significant bits vacated by the shift. An
3098 ** ambiguous condition exists if u is greater than or equal to the
3099 ** number of bits in a cell.
3100 **************************************************************************/
3101 static void lshift(FICL_VM *pVM)
3103 FICL_UNS nBits = stackPopUNS(pVM->pStack);
3104 FICL_UNS x1 = stackPopUNS(pVM->pStack);
3106 stackPushUNS(pVM->pStack, x1 << nBits);
3111 static void rshift(FICL_VM *pVM)
3113 FICL_UNS nBits = stackPopUNS(pVM->pStack);
3114 FICL_UNS x1 = stackPopUNS(pVM->pStack);
3116 stackPushUNS(pVM->pStack, x1 >> nBits);
3121 /**************************************************************************
3123 ** m-star CORE ( n1 n2 -- d )
3124 ** d is the signed product of n1 times n2.
3125 **************************************************************************/
3126 static void mStar(FICL_VM *pVM)
3128 FICL_INT n2 = stackPopINT(pVM->pStack);
3129 FICL_INT n1 = stackPopINT(pVM->pStack);
3132 d = m64MulI(n1, n2);
3133 i64Push(pVM->pStack, d);
3138 static void umStar(FICL_VM *pVM)
3140 FICL_UNS u2 = stackPopUNS(pVM->pStack);
3141 FICL_UNS u1 = stackPopUNS(pVM->pStack);
3144 ud = ficlLongMul(u1, u2);
3145 u64Push(pVM->pStack, ud);
3150 /**************************************************************************
3153 **************************************************************************/
3154 static void ficlMax(FICL_VM *pVM)
3156 FICL_INT n2 = stackPopINT(pVM->pStack);
3157 FICL_INT n1 = stackPopINT(pVM->pStack);
3159 stackPushINT(pVM->pStack, (n1 > n2) ? n1 : n2);
3163 static void ficlMin(FICL_VM *pVM)
3165 FICL_INT n2 = stackPopINT(pVM->pStack);
3166 FICL_INT n1 = stackPopINT(pVM->pStack);
3168 stackPushINT(pVM->pStack, (n1 < n2) ? n1 : n2);
3173 /**************************************************************************
3175 ** CORE ( addr1 addr2 u -- )
3176 ** If u is greater than zero, copy the contents of u consecutive address
3177 ** units at addr1 to the u consecutive address units at addr2. After MOVE
3178 ** completes, the u consecutive address units at addr2 contain exactly
3179 ** what the u consecutive address units at addr1 contained before the move.
3180 ** NOTE! This implementation assumes that a char is the same size as
3182 **************************************************************************/
3183 static void move(FICL_VM *pVM)
3185 FICL_UNS u = stackPopUNS(pVM->pStack);
3186 char *addr2 = stackPopPtr(pVM->pStack);
3187 char *addr1 = stackPopPtr(pVM->pStack);
3192 ** Do the copy carefully, so as to be
3193 ** correct even if the two ranges overlap
3198 *addr2++ = *addr1++;
3205 *addr2-- = *addr1--;
3212 /**************************************************************************
3215 **************************************************************************/
3216 static void recurseCoIm(FICL_VM *pVM)
3218 FICL_DICT *pDict = ficlGetDict();
3221 dictAppendCell(pDict, LVALUEtoCELL(pDict->smudge));
3226 /**************************************************************************
3228 ** s-to-d CORE ( n -- d )
3229 ** Convert the number n to the double-cell number d with the same
3231 **************************************************************************/
3232 static void sToD(FICL_VM *pVM)
3234 FICL_INT s = stackPopINT(pVM->pStack);
3236 /* sign extend to 64 bits.. */
3237 stackPushINT(pVM->pStack, s);
3238 stackPushINT(pVM->pStack, (s < 0) ? -1 : 0);
3243 /**************************************************************************
3245 ** CORE ( -- c-addr u )
3246 ** c-addr is the address of, and u is the number of characters in, the
3248 **************************************************************************/
3249 static void source(FICL_VM *pVM)
3251 stackPushPtr(pVM->pStack, pVM->tib.cp);
3252 stackPushINT(pVM->pStack, vmGetInBufLen(pVM));
3257 /**************************************************************************
3260 **************************************************************************/
3261 static void ficlVersion(FICL_VM *pVM)
3263 vmTextOut(pVM, "ficl Version " FICL_VER, 1);
3268 /**************************************************************************
3271 **************************************************************************/
3272 static void toIn(FICL_VM *pVM)
3274 stackPushPtr(pVM->pStack, &pVM->tib.index);
3279 /**************************************************************************
3280 d e f i n i t i o n s
3282 ** Make the compilation word list the same as the first word list in the
3283 ** search order. Specifies that the names of subsequent definitions will
3284 ** be placed in the compilation word list. Subsequent changes in the search
3285 ** order will not affect the compilation word list.
3286 **************************************************************************/
3287 static void definitions(FICL_VM *pVM)
3289 FICL_DICT *pDict = ficlGetDict();
3292 if (pDict->nLists < 1)
3294 vmThrowErr(pVM, "DEFINITIONS error - empty search order");
3297 pDict->pCompile = pDict->pSearch[pDict->nLists-1];
3302 /**************************************************************************
3303 f o r t h - w o r d l i s t
3304 ** SEARCH ( -- wid )
3305 ** Return wid, the identifier of the word list that includes all standard
3306 ** words provided by the implementation. This word list is initially the
3307 ** compilation word list and is part of the initial search order.
3308 **************************************************************************/
3309 static void forthWordlist(FICL_VM *pVM)
3311 FICL_HASH *pHash = ficlGetDict()->pForthWords;
3312 stackPushPtr(pVM->pStack, pHash);
3317 /**************************************************************************
3318 g e t - c u r r e n t
3319 ** SEARCH ( -- wid )
3320 ** Return wid, the identifier of the compilation word list.
3321 **************************************************************************/
3322 static void getCurrent(FICL_VM *pVM)
3324 ficlLockDictionary(TRUE);
3325 stackPushPtr(pVM->pStack, ficlGetDict()->pCompile);
3326 ficlLockDictionary(FALSE);
3331 /**************************************************************************
3333 ** SEARCH ( -- widn ... wid1 n )
3334 ** Returns the number of word lists n in the search order and the word list
3335 ** identifiers widn ... wid1 identifying these word lists. wid1 identifies
3336 ** the word list that is searched first, and widn the word list that is
3337 ** searched last. The search order is unaffected.
3338 **************************************************************************/
3339 static void getOrder(FICL_VM *pVM)
3341 FICL_DICT *pDict = ficlGetDict();
3342 int nLists = pDict->nLists;
3345 ficlLockDictionary(TRUE);
3346 for (i = 0; i < nLists; i++)
3348 stackPushPtr(pVM->pStack, pDict->pSearch[i]);
3351 stackPushUNS(pVM->pStack, nLists);
3352 ficlLockDictionary(FALSE);
3357 /**************************************************************************
3358 s e a r c h - w o r d l i s t
3359 ** SEARCH ( c-addr u wid -- 0 | xt 1 | xt -1 )
3360 ** Find the definition identified by the string c-addr u in the word list
3361 ** identified by wid. If the definition is not found, return zero. If the
3362 ** definition is found, return its execution token xt and one (1) if the
3363 ** definition is immediate, minus-one (-1) otherwise.
3364 **************************************************************************/
3365 static void searchWordlist(FICL_VM *pVM)
3370 FICL_HASH *pHash = stackPopPtr(pVM->pStack);
3372 si.count = (FICL_COUNT)stackPopUNS(pVM->pStack);
3373 si.cp = stackPopPtr(pVM->pStack);
3374 hashCode = hashHashCode(si);
3376 ficlLockDictionary(TRUE);
3377 pFW = hashLookup(pHash, si, hashCode);
3378 ficlLockDictionary(FALSE);
3382 stackPushPtr(pVM->pStack, pFW);
3383 stackPushINT(pVM->pStack, (wordIsImmediate(pFW) ? 1 : -1));
3387 stackPushUNS(pVM->pStack, 0);
3394 /**************************************************************************
3395 s e t - c u r r e n t
3396 ** SEARCH ( wid -- )
3397 ** Set the compilation word list to the word list identified by wid.
3398 **************************************************************************/
3399 static void setCurrent(FICL_VM *pVM)
3401 FICL_HASH *pHash = stackPopPtr(pVM->pStack);
3402 FICL_DICT *pDict = ficlGetDict();
3403 ficlLockDictionary(TRUE);
3404 pDict->pCompile = pHash;
3405 ficlLockDictionary(FALSE);
3410 /**************************************************************************
3412 ** SEARCH ( widn ... wid1 n -- )
3413 ** Set the search order to the word lists identified by widn ... wid1.
3414 ** Subsequently, word list wid1 will be searched first, and word list
3415 ** widn searched last. If n is zero, empty the search order. If n is minus
3416 ** one, set the search order to the implementation-defined minimum
3417 ** search order. The minimum search order shall include the words
3418 ** FORTH-WORDLIST and SET-ORDER. A system shall allow n to
3419 ** be at least eight.
3420 **************************************************************************/
3421 static void setOrder(FICL_VM *pVM)
3424 int nLists = stackPopINT(pVM->pStack);
3425 FICL_DICT *dp = ficlGetDict();
3427 if (nLists > FICL_DEFAULT_VOCS)
3429 vmThrowErr(pVM, "set-order error: list would be too large");
3432 ficlLockDictionary(TRUE);
3436 dp->nLists = nLists;
3437 for (i = nLists-1; i >= 0; --i)
3439 dp->pSearch[i] = stackPopPtr(pVM->pStack);
3444 dictResetSearchOrder(dp);
3447 ficlLockDictionary(FALSE);
3452 /**************************************************************************
3454 ** SEARCH ( -- wid )
3455 ** Create a new empty word list, returning its word list identifier wid.
3456 ** The new word list may be returned from a pool of preallocated word
3457 ** lists or may be dynamically allocated in data space. A system shall
3458 ** allow the creation of at least 8 new word lists in addition to any
3459 ** provided as part of the system.
3461 ** 1. ficl creates a new single-list hash in the dictionary and returns
3463 ** 2. ficl-wordlist takes an arg off the stack indicating the number of
3464 ** hash entries in the wordlist. Ficl 2.02 and later define WORDLIST as
3465 ** : wordlist 1 ficl-wordlist ;
3466 **************************************************************************/
3467 static void wordlist(FICL_VM *pVM)
3469 FICL_DICT *dp = ficlGetDict();
3474 vmCheckStack(pVM, 1, 1);
3476 nBuckets = stackPopUNS(pVM->pStack);
3479 pHash = (FICL_HASH *)dp->here;
3480 dictAllot(dp, sizeof (FICL_HASH)
3481 + (nBuckets-1) * sizeof (FICL_WORD *));
3483 pHash->size = nBuckets;
3486 stackPushPtr(pVM->pStack, pHash);
3491 /**************************************************************************
3494 ** Pop wid off the search order. Error if the search order is empty
3495 **************************************************************************/
3496 static void searchPop(FICL_VM *pVM)
3498 FICL_DICT *dp = ficlGetDict();
3501 ficlLockDictionary(TRUE);
3502 nLists = dp->nLists;
3505 vmThrowErr(pVM, "search> error: empty search order");
3507 stackPushPtr(pVM->pStack, dp->pSearch[--dp->nLists]);
3508 ficlLockDictionary(FALSE);
3513 /**************************************************************************
3516 ** Push wid onto the search order. Error if the search order is full.
3517 **************************************************************************/
3518 static void searchPush(FICL_VM *pVM)
3520 FICL_DICT *dp = ficlGetDict();
3522 ficlLockDictionary(TRUE);
3523 if (dp->nLists > FICL_DEFAULT_VOCS)
3525 vmThrowErr(pVM, ">search error: search order overflow");
3527 dp->pSearch[dp->nLists++] = stackPopPtr(pVM->pStack);
3528 ficlLockDictionary(FALSE);
3533 /**************************************************************************
3534 c o l o n N o N a m e
3535 ** CORE EXT ( C: -- colon-sys ) ( S: -- xt )
3536 ** Create an unnamed colon definition and push its address.
3537 ** Change state to compile.
3538 **************************************************************************/
3539 static void colonNoName(FICL_VM *pVM)
3541 FICL_DICT *dp = ficlGetDict();
3546 SI_SETPTR(si, NULL);
3548 pVM->state = COMPILE;
3549 pFW = dictAppendWord2(dp, si, colonParen, FW_DEFAULT | FW_SMUDGE);
3550 stackPushPtr(pVM->pStack, pFW);
3551 markControlTag(pVM, colonTag);
3556 /**************************************************************************
3557 u s e r V a r i a b l e
3558 ** user ( u -- ) "<spaces>name"
3559 ** Get a name from the input stream and create a user variable
3560 ** with the name and the index supplied. The run-time effect
3561 ** of a user variable is to push the address of the indexed cell
3562 ** in the running vm's user array.
3564 ** User variables are vm local cells. Each vm has an array of
3565 ** FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
3566 ** Ficl's user facility is implemented with two primitives,
3567 ** "user" and "(user)", a variable ("nUser") (in softcore.c) that
3568 ** holds the index of the next free user cell, and a redefinition
3569 ** (also in softcore) of "user" that defines a user word and increments
3571 **************************************************************************/
3573 static void userParen(FICL_VM *pVM)
3575 FICL_INT i = pVM->runningWord->param[0].i;
3576 stackPushPtr(pVM->pStack, &pVM->user[i]);
3581 static void userVariable(FICL_VM *pVM)
3583 FICL_DICT *dp = ficlGetDict();
3584 STRINGINFO si = vmGetWord(pVM);
3587 c = stackPop(pVM->pStack);
3588 if (c.i >= FICL_USER_CELLS)
3590 vmThrowErr(pVM, "Error - out of user space");
3593 dictAppendWord2(dp, si, userParen, FW_DEFAULT);
3594 dictAppendCell(dp, c);
3600 /**************************************************************************
3603 ** Interpretation: ( x "<spaces>name" -- )
3604 ** Skip leading spaces and parse name delimited by a space. Store x in
3605 ** name. An ambiguous condition exists if name was not defined by VALUE.
3606 ** NOTE: In ficl, VALUE is an alias of CONSTANT
3607 **************************************************************************/
3608 static void toValue(FICL_VM *pVM)
3610 STRINGINFO si = vmGetWord(pVM);
3611 FICL_DICT *dp = ficlGetDict();
3614 #if FICL_WANT_LOCALS
3615 if ((nLocals > 0) && (pVM->state == COMPILE))
3617 FICL_DICT *pLoc = ficlGetLoc();
3618 pFW = dictLookup(pLoc, si);
3619 if (pFW && (pFW->code == doLocalIm))
3621 dictAppendCell(dp, LVALUEtoCELL(pToLocalParen));
3622 dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
3625 else if (pFW && pFW->code == do2LocalIm)
3627 dictAppendCell(dp, LVALUEtoCELL(pTo2LocalParen));
3628 dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
3636 pFW = dictLookup(dp, si);
3639 int i = SI_COUNT(si);
3640 vmThrowErr(pVM, "%.*s not found", i, SI_PTR(si));
3643 if (pVM->state == INTERPRET)
3644 pFW->param[0] = stackPop(pVM->pStack);
3645 else /* compile code to store to word's param */
3647 stackPushPtr(pVM->pStack, &pFW->param[0]);
3649 dictAppendCell(dp, LVALUEtoCELL(pStore));
3655 #if FICL_WANT_LOCALS
3656 /**************************************************************************
3659 ** Link a frame on the return stack, reserving nCells of space for
3660 ** locals - the value of nCells is the next cell in the instruction
3662 **************************************************************************/
3663 static void linkParen(FICL_VM *pVM)
3665 FICL_INT nLink = *(FICL_INT *)(pVM->ip);
3666 vmBranchRelative(pVM, 1);
3667 stackLink(pVM->rStack, nLink);
3672 static void unlinkParen(FICL_VM *pVM)
3674 stackUnlink(pVM->rStack);
3679 /**************************************************************************
3681 ** Immediate - cfa of a local while compiling - when executed, compiles
3682 ** code to fetch the value of a local given the local's index in the
3684 **************************************************************************/
3685 static void getLocalParen(FICL_VM *pVM)
3687 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
3688 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
3693 static void toLocalParen(FICL_VM *pVM)
3695 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
3696 pVM->rStack->pFrame[nLocal] = stackPop(pVM->pStack);
3701 static void getLocal0(FICL_VM *pVM)
3703 stackPush(pVM->pStack, pVM->rStack->pFrame[0]);
3708 static void toLocal0(FICL_VM *pVM)
3710 pVM->rStack->pFrame[0] = stackPop(pVM->pStack);
3715 static void getLocal1(FICL_VM *pVM)
3717 stackPush(pVM->pStack, pVM->rStack->pFrame[1]);
3722 static void toLocal1(FICL_VM *pVM)
3724 pVM->rStack->pFrame[1] = stackPop(pVM->pStack);
3730 ** Each local is recorded in a private locals dictionary as a
3731 ** word that does doLocalIm at runtime. DoLocalIm compiles code
3732 ** into the client definition to fetch the value of the
3733 ** corresponding local variable from the return stack.
3734 ** The private dictionary gets initialized at the end of each block
3735 ** that uses locals (in ; and does> for example).
3737 static void doLocalIm(FICL_VM *pVM)
3739 FICL_DICT *pDict = ficlGetDict();
3740 int nLocal = pVM->runningWord->param[0].i;
3742 if (pVM->state == INTERPRET)
3744 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
3751 dictAppendCell(pDict, LVALUEtoCELL(pGetLocal0));
3753 else if (nLocal == 1)
3755 dictAppendCell(pDict, LVALUEtoCELL(pGetLocal1));
3759 dictAppendCell(pDict, LVALUEtoCELL(pGetLocalParen));
3760 dictAppendCell(pDict, LVALUEtoCELL(nLocal));
3767 /**************************************************************************
3769 ** paren-local-paren LOCAL
3770 ** Interpretation: Interpretation semantics for this word are undefined.
3771 ** Execution: ( c-addr u -- )
3772 ** When executed during compilation, (LOCAL) passes a message to the
3773 ** system that has one of two meanings. If u is non-zero,
3774 ** the message identifies a new local whose definition name is given by
3775 ** the string of characters identified by c-addr u. If u is zero,
3776 ** the message is last local and c-addr has no significance.
3778 ** The result of executing (LOCAL) during compilation of a definition is
3779 ** to create a set of named local identifiers, each of which is
3780 ** a definition name, that only have execution semantics within the scope
3781 ** of that definition's source.
3783 ** local Execution: ( -- x )
3785 ** Push the local's value, x, onto the stack. The local's value is
3786 ** initialized as described in 13.3.3 Processing locals and may be
3787 ** changed by preceding the local's name with TO. An ambiguous condition
3788 ** exists when local is executed while in interpretation state.
3789 **************************************************************************/
3790 static void localParen(FICL_VM *pVM)
3792 FICL_DICT *pDict = ficlGetDict();
3794 SI_SETLEN(si, stackPopUNS(pVM->pStack));
3795 SI_SETPTR(si, (char *)stackPopPtr(pVM->pStack));
3797 if (SI_COUNT(si) > 0)
3798 { /* add a local to the **locals** dict and update nLocals */
3799 FICL_DICT *pLoc = ficlGetLoc();
3800 if (nLocals >= FICL_MAX_LOCALS)
3802 vmThrowErr(pVM, "Error: out of local space");
3805 dictAppendWord2(pLoc, si, doLocalIm, FW_COMPIMMED);
3806 dictAppendCell(pLoc, LVALUEtoCELL(nLocals));
3809 { /* compile code to create a local stack frame */
3810 dictAppendCell(pDict, LVALUEtoCELL(pLinkParen));
3811 /* save location in dictionary for #locals */
3812 pMarkLocals = pDict->here;
3813 dictAppendCell(pDict, LVALUEtoCELL(nLocals));
3814 /* compile code to initialize first local */
3815 dictAppendCell(pDict, LVALUEtoCELL(pToLocal0));
3817 else if (nLocals == 1)
3819 dictAppendCell(pDict, LVALUEtoCELL(pToLocal1));
3823 dictAppendCell(pDict, LVALUEtoCELL(pToLocalParen));
3824 dictAppendCell(pDict, LVALUEtoCELL(nLocals));
3829 else if (nLocals > 0)
3830 { /* write nLocals to (link) param area in dictionary */
3831 *(FICL_INT *)pMarkLocals = nLocals;
3838 static void get2LocalParen(FICL_VM *pVM)
3840 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
3841 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
3842 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
3847 static void do2LocalIm(FICL_VM *pVM)
3849 FICL_DICT *pDict = ficlGetDict();
3850 int nLocal = pVM->runningWord->param[0].i;
3852 if (pVM->state == INTERPRET)
3854 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
3855 stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
3859 dictAppendCell(pDict, LVALUEtoCELL(pGet2LocalParen));
3860 dictAppendCell(pDict, LVALUEtoCELL(nLocal));
3866 static void to2LocalParen(FICL_VM *pVM)
3868 FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
3869 pVM->rStack->pFrame[nLocal+1] = stackPop(pVM->pStack);
3870 pVM->rStack->pFrame[nLocal] = stackPop(pVM->pStack);
3875 static void twoLocalParen(FICL_VM *pVM)
3877 FICL_DICT *pDict = ficlGetDict();
3879 SI_SETLEN(si, stackPopUNS(pVM->pStack));
3880 SI_SETPTR(si, (char *)stackPopPtr(pVM->pStack));
3882 if (SI_COUNT(si) > 0)
3883 { /* add a local to the **locals** dict and update nLocals */
3884 FICL_DICT *pLoc = ficlGetLoc();
3885 if (nLocals >= FICL_MAX_LOCALS)
3887 vmThrowErr(pVM, "Error: out of local space");
3890 dictAppendWord2(pLoc, si, do2LocalIm, FW_COMPIMMED);
3891 dictAppendCell(pLoc, LVALUEtoCELL(nLocals));
3894 { /* compile code to create a local stack frame */
3895 dictAppendCell(pDict, LVALUEtoCELL(pLinkParen));
3896 /* save location in dictionary for #locals */
3897 pMarkLocals = pDict->here;
3898 dictAppendCell(pDict, LVALUEtoCELL(nLocals));
3901 dictAppendCell(pDict, LVALUEtoCELL(pTo2LocalParen));
3902 dictAppendCell(pDict, LVALUEtoCELL(nLocals));
3906 else if (nLocals > 0)
3907 { /* write nLocals to (link) param area in dictionary */
3908 *(FICL_INT *)pMarkLocals = nLocals;
3916 /**************************************************************************
3919 ** setparentwid ( parent-wid wid -- )
3920 ** Set WID's link field to the parent-wid. search-wordlist will
3921 ** iterate through all the links when finding words in the child wid.
3922 **************************************************************************/
3923 static void setParentWid(FICL_VM *pVM)
3925 FICL_HASH *parent, *child;
3927 vmCheckStack(pVM, 2, 0);
3929 child = (FICL_HASH *)stackPopPtr(pVM->pStack);
3930 parent = (FICL_HASH *)stackPopPtr(pVM->pStack);
3932 child->link = parent;
3937 /**************************************************************************
3939 ** TOOLS ( "<spaces>name" -- )
3940 ** Display a human-readable representation of the named word's definition.
3941 ** The source of the representation (object-code decompilation, source
3942 ** block, etc.) and the particular form of the display is implementation
3944 ** NOTE: these funcs come late in the file because they reference all
3945 ** of the word-builder funcs without declaring them again. Call me lazy.
3946 **************************************************************************/
3949 ** Vet a candidate pointer carefully to make sure
3950 ** it's not some chunk o' inline data...
3951 ** It has to have a name, and it has to look
3952 ** like it's in the dictionary address range.
3953 ** NOTE: this excludes :noname words!
3955 static int isAFiclWord(FICL_WORD *pFW)
3957 FICL_DICT *pd = ficlGetDict();
3959 if (!dictIncludes(pd, pFW))
3962 if (!dictIncludes(pd, pFW->name))
3965 return ((pFW->nName > 0) && (pFW->name[pFW->nName] == '\0'));
3969 ** seeColon (for proctologists only)
3970 ** Walks a colon definition, decompiling
3971 ** on the fly. Knows about primitive control structures.
3973 static void seeColon(FICL_VM *pVM, CELL *pc)
3975 for (; pc->p != pSemiParen; pc++)
3977 FICL_WORD *pFW = (FICL_WORD *)(pc->p);
3979 if (isAFiclWord(pFW))
3981 if (pFW->code == literalParen)
3984 if (isAFiclWord(v.p))
3986 FICL_WORD *pLit = (FICL_WORD *)v.p;
3987 sprintf(pVM->pad, " literal %.*s (%#lx)",
3988 pLit->nName, pLit->name, v.u);
3991 sprintf(pVM->pad, " literal %ld (%#lx)", v.i, v.u);
3993 else if (pFW->code == stringLit)
3995 FICL_STRING *sp = (FICL_STRING *)(void *)++pc;
3996 pc = (CELL *)alignPtr(sp->text + sp->count + 1) - 1;
3997 sprintf(pVM->pad, " s\" %.*s\"", sp->count, sp->text);
3999 else if (pFW->code == ifParen)
4003 sprintf(pVM->pad, " if / while (branch rel %ld)", c.i);
4005 sprintf(pVM->pad, " until (branch rel %ld)", c.i);
4007 else if (pFW->code == branchParen)
4011 sprintf(pVM->pad, " else (branch rel %ld)", c.i);
4013 sprintf(pVM->pad, " repeat (branch rel %ld)", c.i);
4015 else if (pFW->code == qDoParen)
4018 sprintf(pVM->pad, " ?do (leave abs %#lx)", c.u);
4020 else if (pFW->code == doParen)
4023 sprintf(pVM->pad, " do (leave abs %#lx)", c.u);
4025 else if (pFW->code == loopParen)
4028 sprintf(pVM->pad, " loop (branch rel %#ld)", c.i);
4030 else if (pFW->code == plusLoopParen)
4033 sprintf(pVM->pad, " +loop (branch rel %#ld)", c.i);
4035 else /* default: print word's name */
4037 sprintf(pVM->pad, " %.*s", pFW->nName, pFW->name);
4040 vmTextOut(pVM, pVM->pad, 1);
4042 else /* probably not a word - punt and print value */
4044 sprintf(pVM->pad, " %ld (%#lx)", pc->i, pc->u);
4045 vmTextOut(pVM, pVM->pad, 1);
4049 vmTextOut(pVM, ";", 1);
4053 ** Here's the outer part of the decompiler. It's
4054 ** just a big nested conditional that checks the
4055 ** CFA of the word to decompile for each kind of
4056 ** known word-builder code, and tries to do
4057 ** something appropriate. If the CFA is not recognized,
4058 ** just indicate that it is a primitive.
4060 static void see(FICL_VM *pVM)
4065 pFW = (FICL_WORD *)stackPopPtr(pVM->pStack);
4067 if (pFW->code == colonParen)
4069 sprintf(pVM->pad, ": %.*s", pFW->nName, pFW->name);
4070 vmTextOut(pVM, pVM->pad, 1);
4071 seeColon(pVM, pFW->param);
4073 else if (pFW->code == doDoes)
4075 vmTextOut(pVM, "does>", 1);
4076 seeColon(pVM, (CELL *)pFW->param->p);
4078 else if (pFW->code == createParen)
4080 vmTextOut(pVM, "create", 1);
4082 else if (pFW->code == variableParen)
4084 sprintf(pVM->pad, "variable = %ld (%#lx)",
4085 pFW->param->i, pFW->param->u);
4086 vmTextOut(pVM, pVM->pad, 1);
4088 else if (pFW->code == userParen)
4090 sprintf(pVM->pad, "user variable %ld (%#lx)",
4091 pFW->param->i, pFW->param->u);
4092 vmTextOut(pVM, pVM->pad, 1);
4094 else if (pFW->code == constantParen)
4096 sprintf(pVM->pad, "constant = %ld (%#lx)",
4097 pFW->param->i, pFW->param->u);
4098 vmTextOut(pVM, pVM->pad, 1);
4102 vmTextOut(pVM, "primitive", 1);
4105 if (pFW->flags & FW_IMMEDIATE)
4107 vmTextOut(pVM, "immediate", 1);
4114 /**************************************************************************
4116 ** STRING ( c-addr1 u1 c-addr2 u2 -- n )
4117 ** Compare the string specified by c-addr1 u1 to the string specified by
4118 ** c-addr2 u2. The strings are compared, beginning at the given addresses,
4119 ** character by character, up to the length of the shorter string or until a
4120 ** difference is found. If the two strings are identical, n is zero. If the two
4121 ** strings are identical up to the length of the shorter string, n is minus-one
4122 ** (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not
4123 ** identical up to the length of the shorter string, n is minus-one (-1) if the
4124 ** first non-matching character in the string specified by c-addr1 u1 has a
4125 ** lesser numeric value than the corresponding character in the string specified
4126 ** by c-addr2 u2 and one (1) otherwise.
4127 **************************************************************************/
4128 static void compareString(FICL_VM *pVM)
4131 FICL_UNS u1, u2, uMin;
4134 vmCheckStack(pVM, 4, 1);
4135 u2 = stackPopUNS(pVM->pStack);
4136 cp2 = (char *)stackPopPtr(pVM->pStack);
4137 u1 = stackPopUNS(pVM->pStack);
4138 cp1 = (char *)stackPopPtr(pVM->pStack);
4140 uMin = (u1 < u2)? u1 : u2;
4141 for ( ; (uMin > 0) && (n == 0); uMin--)
4143 n = (int)(*cp1++ - *cp2++);
4154 stackPushINT(pVM->pStack, n);
4159 /**************************************************************************
4161 ** CORE EXT, FILE ( -- 0 | -1 | fileid )
4162 ** Identifies the input source as follows:
4164 ** SOURCE-ID Input source
4165 ** --------- ------------
4166 ** fileid Text file fileid
4167 ** -1 String (via EVALUATE)
4168 ** 0 User input device
4169 **************************************************************************/
4170 static void sourceid(FICL_VM *pVM)
4172 stackPushINT(pVM->pStack, pVM->sourceID.i);
4177 /**************************************************************************
4179 ** CORE EXT ( -- flag )
4180 ** Attempt to fill the input buffer from the input source, returning a true
4181 ** flag if successful.
4182 ** When the input source is the user input device, attempt to receive input
4183 ** into the terminal input buffer. If successful, make the result the input
4184 ** buffer, set >IN to zero, and return true. Receipt of a line containing no
4185 ** characters is considered successful. If there is no input available from
4186 ** the current input source, return false.
4187 ** When the input source is a string from EVALUATE, return false and
4188 ** perform no other action.
4189 **************************************************************************/
4190 static void refill(FICL_VM *pVM)
4192 static int tries = 0;
4194 FICL_INT ret = (pVM->sourceID.i == -1) ? FICL_FALSE : FICL_TRUE;
4195 if (ret && tries == 0) {
4197 vmThrow(pVM, VM_RESTART);
4201 stackPushINT(pVM->pStack, ret);
4206 /**************************************************************************
4208 ** TOOLS EXT ( "<spaces>name" -- )
4209 ** Skip leading space delimiters. Parse name delimited by a space.
4210 ** Find name, then delete name from the dictionary along with all
4211 ** words added to the dictionary after name. An ambiguous
4212 ** condition exists if name cannot be found.
4214 ** If the Search-Order word set is present, FORGET searches the
4215 ** compilation word list. An ambiguous condition exists if the
4216 ** compilation word list is deleted.
4217 **************************************************************************/
4218 static void forgetWid(FICL_VM *pVM)
4220 FICL_DICT *pDict = ficlGetDict();
4223 pHash = (FICL_HASH *)stackPopPtr(pVM->pStack);
4224 hashForget(pHash, pDict->here);
4230 static void forget(FICL_VM *pVM)
4233 FICL_DICT *pDict = ficlGetDict();
4234 FICL_HASH *pHash = pDict->pCompile;
4237 where = ((FICL_WORD *)stackPopPtr(pVM->pStack))->name;
4238 hashForget(pHash, where);
4239 pDict->here = PTRtoCELL where;
4244 /************************* freebsd added I/O words **************************/
4246 /* fopen - open a file and return new fd on stack.
4248 * fopen ( count ptr -- fd )
4250 static void pfopen(FICL_VM *pVM)
4256 vmCheckStack(pVM, 2, 1);
4258 (void)stackPopINT(pVM->pStack); /* don't need count value */
4259 p = stackPopPtr(pVM->pStack);
4260 fd = open(p, O_RDWR);
4261 stackPushINT(pVM->pStack, fd);
4265 /* fclose - close a file who's fd is on stack.
4269 static void pfclose(FICL_VM *pVM)
4274 vmCheckStack(pVM, 1, 0);
4276 fd = stackPopINT(pVM->pStack); /* get fd */
4282 /* fread - read file contents
4284 * fread ( fd buf nbytes -- nread )
4286 static void pfread(FICL_VM *pVM)
4292 vmCheckStack(pVM, 3, 1);
4294 len = stackPopINT(pVM->pStack); /* get number of bytes to read */
4295 buf = stackPopPtr(pVM->pStack); /* get buffer */
4296 fd = stackPopINT(pVM->pStack); /* get fd */
4297 if (len > 0 && buf && fd != -1)
4298 stackPushINT(pVM->pStack, read(fd, buf, len));
4300 stackPushINT(pVM->pStack, -1);
4304 /* fwrite - write file contents
4306 * fwrite ( fd buf nbytes -- nwritten )
4308 static void pfwrite(FICL_VM *pVM)
4313 vmCheckStack(pVM, 3, 1);
4315 len = stackPopINT(pVM->pStack); /* get number of bytes to write */
4316 buf = stackPopPtr(pVM->pStack); /* get buffer */
4317 fd = stackPopINT(pVM->pStack); /* get fd */
4318 if (len > 0 && buf && fd != -1)
4319 stackPushINT(pVM->pStack, write(fd, buf, len));
4321 stackPushINT(pVM->pStack, -1);
4324 /* flseek - seek to file offset
4326 * flseek ( fd offset whence -- whence )
4328 static void pflseek(FICL_VM *pVM)
4330 int fd, whence, offset;
4332 vmCheckStack(pVM, 3, 1);
4334 whence = stackPopINT(pVM->pStack); /* get whence */
4335 offset = stackPopINT(pVM->pStack); /* get offset */
4336 fd = stackPopINT(pVM->pStack); /* get fd */
4337 if (whence >= 0 && whence <= 2 && offset >= 0 && fd != -1)
4338 stackPushINT(pVM->pStack, lseek(fd, offset, whence));
4340 stackPushINT(pVM->pStack, -1);
4343 /* fload - interpret file contents
4347 static void pfload(FICL_VM *pVM)
4352 vmCheckStack(pVM, 1, 0);
4354 fd = stackPopINT(pVM->pStack); /* get fd */
4356 ficlExecFD(pVM, fd);
4360 /* key - get a character from stdin
4364 static void key(FICL_VM *pVM)
4367 vmCheckStack(pVM, 0, 1);
4369 stackPushINT(pVM->pStack, getchar());
4373 /* key? - check for a character from stdin (FACILITY)
4377 static void keyQuestion(FICL_VM *pVM)
4380 vmCheckStack(pVM, 0, 1);
4383 /* XXX Since we don't fiddle with termios, let it always succeed... */
4384 stackPushINT(pVM->pStack, FICL_TRUE);
4386 /* But here do the right thing. */
4387 stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE);
4392 /* seconds - gives number of seconds since beginning of time
4394 * beginning of time is defined as:
4396 * BTX - number of seconds since midnight
4397 * FreeBSD - number of seconds since Jan 1 1970
4401 static void pseconds(FICL_VM *pVM)
4404 vmCheckStack(pVM,0,1);
4406 stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL));
4410 /* ms - wait at least that many milliseconds (FACILITY)
4415 static void ms(FICL_VM *pVM)
4418 vmCheckStack(pVM,1,0);
4421 usleep(stackPopUNS(pVM->pStack)*1000);
4423 delay(stackPopUNS(pVM->pStack)*1000);
4428 /* fkey - get a character from a file
4430 * fkey ( file -- char )
4432 static void fkey(FICL_VM *pVM)
4438 vmCheckStack(pVM, 1, 1);
4440 fd = stackPopINT(pVM->pStack);
4441 i = read(fd, &ch, 1);
4442 stackPushINT(pVM->pStack, i > 0 ? ch : -1);
4446 /**************************************************************************
4447 freebsd exception handling words
4448 ** Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
4449 ** the word in ToS. If an exception happens, restore the state to what
4450 ** it was before, and pushes the exception value on the stack. If not,
4453 ** Notice that Catch implements an inner interpreter. This is ugly,
4454 ** but given how ficl works, it cannot be helped. The problem is that
4455 ** colon definitions will be executed *after* the function returns,
4456 ** while "code" definitions will be executed immediately. I considered
4457 ** other solutions to this problem, but all of them shared the same
4458 ** basic problem (with added disadvantages): if ficl ever changes it's
4459 ** inner thread modus operandi, one would have to fix this word.
4461 ** More comments can be found throughout catch's code.
4463 ** Daniel C. Sobral Jan 09/1999
4464 ** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
4465 **************************************************************************/
4467 static void ficlCatch(FICL_VM *pVM)
4469 static FICL_WORD *pQuit = NULL;
4479 pQuit = ficlLookup("exit-inner");
4487 ** We need this *before* we save the stack pointer, or
4488 ** we'll have to pop one element out of the stack after
4489 ** an exception. I prefer to get done with it up front. :-)
4492 vmCheckStack(pVM, 1, 0);
4494 pFW = stackPopPtr(pVM->pStack);
4497 ** Save vm's state -- a catch will not back out environmental
4500 ** We are *not* saving dictionary state, since it is
4501 ** global instead of per vm, and we are not saving
4502 ** stack contents, since we are not required to (and,
4503 ** thus, it would be useless). We save pVM, and pVM
4504 ** "stacks" (a structure containing general information
4505 ** about it, including the current stack pointer).
4507 memcpy((void*)&VM, (void*)pVM, sizeof(FICL_VM));
4508 memcpy((void*)&pStack, (void*)pVM->pStack, sizeof(FICL_STACK));
4509 memcpy((void*)&rStack, (void*)pVM->rStack, sizeof(FICL_STACK));
4512 ** Give pVM a jmp_buf
4514 pVM->pState = &vmState;
4519 except = setjmp(vmState);
4524 ** Setup condition - push poison pill so that the VM throws
4525 ** VM_INNEREXIT if the XT terminates normally, then execute
4529 vmPushIP(pVM, &pQuit); /* Open mouth, insert emetic */
4530 vmExecute(pVM, pFW);
4535 ** Normal exit from XT - lose the poison pill,
4536 ** restore old setjmp vector and push a zero.
4539 vmPopIP(pVM); /* Gack - hurl poison pill */
4540 pVM->pState = VM.pState; /* Restore just the setjmp vector */
4541 stackPushINT(pVM->pStack, 0); /* Push 0 -- everything is ok */
4545 ** Some other exception got thrown - restore pre-existing VM state
4546 ** and push the exception code
4549 /* Restore vm's state */
4550 memcpy((void*)pVM, (void*)&VM, sizeof(FICL_VM));
4551 memcpy((void*)pVM->pStack, (void*)&pStack, sizeof(FICL_STACK));
4552 memcpy((void*)pVM->rStack, (void*)&rStack, sizeof(FICL_STACK));
4554 stackPushINT(pVM->pStack, except);/* Push error */
4560 * Throw -- From ANS Forth standard.
4562 * Throw takes the ToS and, if that's different from zero,
4563 * returns to the last executed catch context. Further throws will
4564 * unstack previously executed "catches", in LIFO mode.
4566 * Daniel C. Sobral Jan 09/1999
4569 static void ficlThrow(FICL_VM *pVM)
4573 except = stackPopINT(pVM->pStack);
4576 vmThrow(pVM, except);
4580 static void ansAllocate(FICL_VM *pVM)
4585 size = stackPopINT(pVM->pStack);
4586 p = ficlMalloc(size);
4587 stackPushPtr(pVM->pStack, p);
4589 stackPushINT(pVM->pStack, 0);
4591 stackPushINT(pVM->pStack, 1);
4595 static void ansFree(FICL_VM *pVM)
4599 p = stackPopPtr(pVM->pStack);
4601 stackPushINT(pVM->pStack, 0);
4605 static void ansResize(FICL_VM *pVM)
4610 size = stackPopINT(pVM->pStack);
4611 old = stackPopPtr(pVM->pStack);
4612 new = ficlRealloc(old, size);
4615 stackPushPtr(pVM->pStack, new);
4616 stackPushINT(pVM->pStack, 0);
4620 stackPushPtr(pVM->pStack, old);
4621 stackPushINT(pVM->pStack, 1);
4626 ** Retrieves free space remaining on the dictionary
4629 static void freeHeap(FICL_VM *pVM)
4631 stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict()));
4636 ** Signals execXT that an inner loop has completed
4638 static void ficlExitInner(FICL_VM *pVM)
4640 vmThrow(pVM, VM_INNEREXIT);
4644 /**************************************************************************
4646 ** DOUBLE ( d1 -- d2 )
4647 ** d2 is the negation of d1.
4648 **************************************************************************/
4649 static void dnegate(FICL_VM *pVM)
4651 DPINT i = i64Pop(pVM->pStack);
4653 i64Push(pVM->pStack, i);
4658 /******************* Increase dictionary size on-demand ******************/
4660 static void ficlDictThreshold(FICL_VM *pVM)
4662 stackPushPtr(pVM->pStack, &dictThreshold);
4665 static void ficlDictIncrease(FICL_VM *pVM)
4667 stackPushPtr(pVM->pStack, &dictIncrease);
4670 /************************* freebsd added trace ***************************/
4673 static void ficlTrace(FICL_VM *pVM)
4676 vmCheckStack(pVM, 1, 1);
4679 ficl_trace = stackPopINT(pVM->pStack);
4683 /**************************************************************************
4684 f i c l C o m p i l e C o r e
4685 ** Builds the primitive wordset and the environment-query namespace.
4686 **************************************************************************/
4688 void ficlCompileCore(FICL_DICT *dp)
4694 ** see softcore.c for definitions of: abs bl space spaces abort"
4697 dictAppendWord(dp, "!", store, FW_DEFAULT);
4698 dictAppendWord(dp, "#", numberSign, FW_DEFAULT);
4699 dictAppendWord(dp, "#>", numberSignGreater,FW_DEFAULT);
4700 dictAppendWord(dp, "#s", numberSignS, FW_DEFAULT);
4701 dictAppendWord(dp, "\'", tick, FW_DEFAULT);
4702 dictAppendWord(dp, "(", commentHang, FW_IMMEDIATE);
4703 dictAppendWord(dp, "*", mul, FW_DEFAULT);
4704 dictAppendWord(dp, "*/", mulDiv, FW_DEFAULT);
4705 dictAppendWord(dp, "*/mod", mulDivRem, FW_DEFAULT);
4706 dictAppendWord(dp, "+", add, FW_DEFAULT);
4707 dictAppendWord(dp, "+!", plusStore, FW_DEFAULT);
4708 dictAppendWord(dp, "+loop", plusLoopCoIm, FW_COMPIMMED);
4710 dictAppendWord(dp, ",", comma, FW_DEFAULT);
4711 dictAppendWord(dp, "-", sub, FW_DEFAULT);
4712 dictAppendWord(dp, ".", displayCell, FW_DEFAULT);
4713 dictAppendWord(dp, ".#", displayCellNoPad, FW_DEFAULT);
4714 dictAppendWord(dp, ".\"", dotQuoteCoIm, FW_COMPIMMED);
4715 dictAppendWord(dp, "/", ficlDiv, FW_DEFAULT);
4716 dictAppendWord(dp, "/mod", slashMod, FW_DEFAULT);
4717 dictAppendWord(dp, "0<", zeroLess, FW_DEFAULT);
4718 dictAppendWord(dp, "0=", zeroEquals, FW_DEFAULT);
4719 dictAppendWord(dp, "0>", zeroGreater, FW_DEFAULT);
4720 dictAppendWord(dp, "1+", onePlus, FW_DEFAULT);
4721 dictAppendWord(dp, "1-", oneMinus, FW_DEFAULT);
4722 dictAppendWord(dp, "2!", twoStore, FW_DEFAULT);
4723 dictAppendWord(dp, "2*", twoMul, FW_DEFAULT);
4724 dictAppendWord(dp, "2/", twoDiv, FW_DEFAULT);
4725 dictAppendWord(dp, "2@", twoFetch, FW_DEFAULT);
4726 dictAppendWord(dp, "2drop", twoDrop, FW_DEFAULT);
4727 dictAppendWord(dp, "2dup", twoDup, FW_DEFAULT);
4728 dictAppendWord(dp, "2over", twoOver, FW_DEFAULT);
4729 dictAppendWord(dp, "2swap", twoSwap, FW_DEFAULT);
4730 dictAppendWord(dp, ":", colon, FW_DEFAULT);
4731 dictAppendWord(dp, ";", semicolonCoIm, FW_COMPIMMED);
4732 dictAppendWord(dp, "<", isLess, FW_DEFAULT);
4733 dictAppendWord(dp, "<#", lessNumberSign, FW_DEFAULT);
4734 dictAppendWord(dp, "=", isEqual, FW_DEFAULT);
4735 dictAppendWord(dp, ">", isGreater, FW_DEFAULT);
4736 dictAppendWord(dp, ">body", toBody, FW_DEFAULT);
4737 dictAppendWord(dp, ">in", toIn, FW_DEFAULT);
4738 dictAppendWord(dp, ">number", toNumber, FW_DEFAULT);
4739 dictAppendWord(dp, ">r", toRStack, FW_DEFAULT);
4740 dictAppendWord(dp, "?dup", questionDup, FW_DEFAULT);
4741 dictAppendWord(dp, "@", fetch, FW_DEFAULT);
4742 dictAppendWord(dp, "abort", ficlAbort, FW_DEFAULT);
4743 dictAppendWord(dp, "accept", accept, FW_DEFAULT);
4744 dictAppendWord(dp, "align", align, FW_DEFAULT);
4745 dictAppendWord(dp, "aligned", aligned, FW_DEFAULT);
4746 dictAppendWord(dp, "allot", allot, FW_DEFAULT);
4747 dictAppendWord(dp, "and", bitwiseAnd, FW_DEFAULT);
4748 dictAppendWord(dp, "base", base, FW_DEFAULT);
4749 dictAppendWord(dp, "begin", beginCoIm, FW_COMPIMMED);
4750 dictAppendWord(dp, "c!", cStore, FW_DEFAULT);
4751 dictAppendWord(dp, "c,", cComma, FW_DEFAULT);
4752 dictAppendWord(dp, "c@", cFetch, FW_DEFAULT);
4753 dictAppendWord(dp, "cell+", cellPlus, FW_DEFAULT);
4754 dictAppendWord(dp, "cells", cells, FW_DEFAULT);
4755 dictAppendWord(dp, "char", ficlChar, FW_DEFAULT);
4756 dictAppendWord(dp, "char+", charPlus, FW_DEFAULT);
4757 dictAppendWord(dp, "chars", ficlChars, FW_DEFAULT);
4758 dictAppendWord(dp, "constant", constant, FW_DEFAULT);
4759 dictAppendWord(dp, "count", count, FW_DEFAULT);
4760 dictAppendWord(dp, "cr", cr, FW_DEFAULT);
4761 dictAppendWord(dp, "create", create, FW_DEFAULT);
4762 dictAppendWord(dp, "decimal", decimal, FW_DEFAULT);
4763 dictAppendWord(dp, "depth", depth, FW_DEFAULT);
4764 dictAppendWord(dp, "do", doCoIm, FW_COMPIMMED);
4765 dictAppendWord(dp, "does>", doesCoIm, FW_COMPIMMED);
4766 dictAppendWord(dp, "drop", drop, FW_DEFAULT);
4767 dictAppendWord(dp, "dup", dup, FW_DEFAULT);
4768 dictAppendWord(dp, "else", elseCoIm, FW_COMPIMMED);
4769 dictAppendWord(dp, "emit", emit, FW_DEFAULT);
4770 dictAppendWord(dp, "environment?", environmentQ,FW_DEFAULT);
4771 dictAppendWord(dp, "evaluate", evaluate, FW_DEFAULT);
4772 dictAppendWord(dp, "execute", execute, FW_DEFAULT);
4773 dictAppendWord(dp, "exit", exitCoIm, FW_COMPIMMED);
4774 dictAppendWord(dp, "fill", fill, FW_DEFAULT);
4775 dictAppendWord(dp, "find", find, FW_DEFAULT);
4776 dictAppendWord(dp, "fm/mod", fmSlashMod, FW_DEFAULT);
4777 dictAppendWord(dp, "here", here, FW_DEFAULT);
4778 dictAppendWord(dp, "hex", hex, FW_DEFAULT);
4779 dictAppendWord(dp, "hold", hold, FW_DEFAULT);
4780 dictAppendWord(dp, "i", loopICo, FW_COMPILE);
4781 dictAppendWord(dp, "if", ifCoIm, FW_COMPIMMED);
4782 dictAppendWord(dp, "immediate", immediate, FW_DEFAULT);
4783 dictAppendWord(dp, "invert", bitwiseNot, FW_DEFAULT);
4784 dictAppendWord(dp, "j", loopJCo, FW_COMPILE);
4785 dictAppendWord(dp, "k", loopKCo, FW_COMPILE);
4786 dictAppendWord(dp, "leave", leaveCo, FW_COMPILE);
4787 dictAppendWord(dp, "literal", literalIm, FW_IMMEDIATE);
4788 dictAppendWord(dp, "loop", loopCoIm, FW_COMPIMMED);
4789 dictAppendWord(dp, "lshift", lshift, FW_DEFAULT);
4790 dictAppendWord(dp, "m*", mStar, FW_DEFAULT);
4791 dictAppendWord(dp, "max", ficlMax, FW_DEFAULT);
4792 dictAppendWord(dp, "min", ficlMin, FW_DEFAULT);
4793 dictAppendWord(dp, "mod", ficlMod, FW_DEFAULT);
4794 dictAppendWord(dp, "move", move, FW_DEFAULT);
4795 dictAppendWord(dp, "negate", negate, FW_DEFAULT);
4796 dictAppendWord(dp, "or", bitwiseOr, FW_DEFAULT);
4797 dictAppendWord(dp, "over", over, FW_DEFAULT);
4798 dictAppendWord(dp, "postpone", postponeCoIm, FW_COMPIMMED);
4799 dictAppendWord(dp, "quit", quit, FW_DEFAULT);
4800 dictAppendWord(dp, "r>", fromRStack, FW_DEFAULT);
4801 dictAppendWord(dp, "r@", fetchRStack, FW_DEFAULT);
4802 dictAppendWord(dp, "recurse", recurseCoIm, FW_COMPIMMED);
4803 dictAppendWord(dp, "repeat", repeatCoIm, FW_COMPIMMED);
4804 dictAppendWord(dp, "rot", rot, FW_DEFAULT);
4805 dictAppendWord(dp, "rshift", rshift, FW_DEFAULT);
4806 dictAppendWord(dp, "s\"", stringQuoteIm, FW_IMMEDIATE);
4807 dictAppendWord(dp, "s>d", sToD, FW_DEFAULT);
4808 dictAppendWord(dp, "sign", sign, FW_DEFAULT);
4809 dictAppendWord(dp, "sm/rem", smSlashRem, FW_DEFAULT);
4810 dictAppendWord(dp, "source", source, FW_DEFAULT);
4811 dictAppendWord(dp, "state", state, FW_DEFAULT);
4812 dictAppendWord(dp, "swap", swap, FW_DEFAULT);
4813 dictAppendWord(dp, "then", endifCoIm, FW_COMPIMMED);
4815 dictAppendWord(dp, "type", type, FW_DEFAULT);
4816 dictAppendWord(dp, "u.", uDot, FW_DEFAULT);
4817 dictAppendWord(dp, "u<", uIsLess, FW_DEFAULT);
4818 dictAppendWord(dp, "um*", umStar, FW_DEFAULT);
4819 dictAppendWord(dp, "um/mod", umSlashMod, FW_DEFAULT);
4820 dictAppendWord(dp, "unloop", unloopCo, FW_COMPILE);
4821 dictAppendWord(dp, "until", untilCoIm, FW_COMPIMMED);
4822 dictAppendWord(dp, "variable", variable, FW_DEFAULT);
4823 dictAppendWord(dp, "while", whileCoIm, FW_COMPIMMED);
4824 dictAppendWord(dp, "word", ficlWord, FW_DEFAULT);
4825 dictAppendWord(dp, "xor", bitwiseXor, FW_DEFAULT);
4826 dictAppendWord(dp, "[", lbracketCoIm, FW_COMPIMMED);
4827 dictAppendWord(dp, "[\']", bracketTickCoIm,FW_COMPIMMED);
4828 dictAppendWord(dp, "[char]", charCoIm, FW_COMPIMMED);
4829 dictAppendWord(dp, "]", rbracket, FW_DEFAULT);
4831 ** CORE EXT word set...
4832 ** see softcore.c for other definitions
4834 dictAppendWord(dp, ".(", dotParen, FW_DEFAULT);
4835 dictAppendWord(dp, ":noname", colonNoName, FW_DEFAULT);
4836 dictAppendWord(dp, "?do", qDoCoIm, FW_COMPIMMED);
4837 dictAppendWord(dp, "again", againCoIm, FW_COMPIMMED);
4838 dictAppendWord(dp, "parse", parse, FW_DEFAULT);
4839 dictAppendWord(dp, "pick", pick, FW_DEFAULT);
4840 dictAppendWord(dp, "roll", roll, FW_DEFAULT);
4841 dictAppendWord(dp, "refill", refill, FW_DEFAULT);
4842 dictAppendWord(dp, "source-id", sourceid, FW_DEFAULT);
4843 dictAppendWord(dp, "to", toValue, FW_IMMEDIATE);
4844 dictAppendWord(dp, "value", constant, FW_DEFAULT);
4845 dictAppendWord(dp, "\\", commentLine, FW_IMMEDIATE);
4847 /* FreeBSD extension words */
4848 dictAppendWord(dp, "fopen", pfopen, FW_DEFAULT);
4849 dictAppendWord(dp, "fclose", pfclose, FW_DEFAULT);
4850 dictAppendWord(dp, "fread", pfread, FW_DEFAULT);
4851 dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT);
4852 dictAppendWord(dp, "flseek", pflseek, FW_DEFAULT);
4853 dictAppendWord(dp, "fload", pfload, FW_DEFAULT);
4854 dictAppendWord(dp, "fkey", fkey, FW_DEFAULT);
4855 dictAppendWord(dp, "key", key, FW_DEFAULT);
4856 dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT);
4857 dictAppendWord(dp, "ms", ms, FW_DEFAULT);
4858 dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT);
4859 dictAppendWord(dp, "heap?", freeHeap, FW_DEFAULT);
4860 dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT);
4861 dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT);
4863 dictAppendWord(dp, "trace!", ficlTrace, FW_DEFAULT);
4868 dictAppendWord(dp, "outb", ficlOutb, FW_DEFAULT);
4869 dictAppendWord(dp, "inb", ficlInb, FW_DEFAULT);
4871 dictAppendWord(dp, "setenv", ficlSetenv, FW_DEFAULT);
4872 dictAppendWord(dp, "setenv?", ficlSetenvq, FW_DEFAULT);
4873 dictAppendWord(dp, "getenv", ficlGetenv, FW_DEFAULT);
4874 dictAppendWord(dp, "unsetenv", ficlUnsetenv, FW_DEFAULT);
4875 dictAppendWord(dp, "copyin", ficlCopyin, FW_DEFAULT);
4876 dictAppendWord(dp, "copyout", ficlCopyout, FW_DEFAULT);
4879 #if defined(__i386__)
4880 ficlSetEnv("arch-i386", FICL_TRUE);
4881 ficlSetEnv("arch-alpha", FICL_FALSE);
4882 #elif defined(__alpha__)
4883 ficlSetEnv("arch-i386", FICL_FALSE);
4884 ficlSetEnv("arch-alpha", FICL_TRUE);
4888 ** Set CORE environment query values
4890 ficlSetEnv("/counted-string", FICL_STRING_MAX);
4891 ficlSetEnv("/hold", nPAD);
4892 ficlSetEnv("/pad", nPAD);
4893 ficlSetEnv("address-unit-bits", 8);
4894 ficlSetEnv("core", FICL_TRUE);
4895 ficlSetEnv("core-ext", FICL_FALSE);
4896 ficlSetEnv("floored", FICL_FALSE);
4897 ficlSetEnv("max-char", UCHAR_MAX);
4898 ficlSetEnvD("max-d", 0x7fffffff, 0xffffffff );
4899 ficlSetEnv("max-n", 0x7fffffff);
4900 ficlSetEnv("max-u", 0xffffffff);
4901 ficlSetEnvD("max-ud", 0xffffffff, 0xffffffff);
4902 ficlSetEnv("return-stack-cells",FICL_DEFAULT_STACK);
4903 ficlSetEnv("stack-cells", FICL_DEFAULT_STACK);
4906 ** DOUBLE word set (partial)
4908 dictAppendWord(dp, "2constant", twoConstant, FW_IMMEDIATE);
4909 dictAppendWord(dp, "2literal", twoLiteralIm, FW_IMMEDIATE);
4910 dictAppendWord(dp, "dnegate", dnegate, FW_DEFAULT);
4914 ** EXCEPTION word set
4916 dictAppendWord(dp, "catch", ficlCatch, FW_DEFAULT);
4917 dictAppendWord(dp, "throw", ficlThrow, FW_DEFAULT);
4919 ficlSetEnv("exception", FICL_TRUE);
4920 ficlSetEnv("exception-ext", FICL_TRUE);
4923 ** LOCAL and LOCAL EXT
4924 ** see softcore.c for implementation of locals|
4926 #if FICL_WANT_LOCALS
4928 dictAppendWord(dp, "(link)", linkParen, FW_COMPILE);
4930 dictAppendWord(dp, "(unlink)", unlinkParen, FW_COMPILE);
4931 dictAppendWord(dp, "doLocal", doLocalIm, FW_COMPIMMED);
4933 dictAppendWord(dp, "(@local)", getLocalParen, FW_COMPILE);
4935 dictAppendWord(dp, "(toLocal)", toLocalParen, FW_COMPILE);
4937 dictAppendWord(dp, "(@local0)", getLocal0, FW_COMPILE);
4939 dictAppendWord(dp, "(toLocal0)",toLocal0, FW_COMPILE);
4941 dictAppendWord(dp, "(@local1)", getLocal1, FW_COMPILE);
4943 dictAppendWord(dp, "(toLocal1)",toLocal1, FW_COMPILE);
4944 dictAppendWord(dp, "(local)", localParen, FW_COMPILE);
4947 dictAppendWord(dp, "(@2local)", get2LocalParen, FW_COMPILE);
4949 dictAppendWord(dp, "(to2Local)",to2LocalParen, FW_COMPILE);
4950 dictAppendWord(dp, "(2local)", twoLocalParen, FW_COMPILE);
4952 ficlSetEnv("locals", FICL_TRUE);
4953 ficlSetEnv("locals-ext", FICL_TRUE);
4954 ficlSetEnv("#locals", FICL_MAX_LOCALS);
4958 ** Optional MEMORY-ALLOC word set
4961 dictAppendWord(dp, "allocate", ansAllocate, FW_DEFAULT);
4962 dictAppendWord(dp, "free", ansFree, FW_DEFAULT);
4963 dictAppendWord(dp, "resize", ansResize, FW_DEFAULT);
4965 ficlSetEnv("memory-alloc", FICL_TRUE);
4966 ficlSetEnv("memory-alloc-ext", FICL_FALSE);
4969 ** optional SEARCH-ORDER word set
4971 dictAppendWord(dp, ">search", searchPush, FW_DEFAULT);
4972 dictAppendWord(dp, "search>", searchPop, FW_DEFAULT);
4973 dictAppendWord(dp, "definitions",
4974 definitions, FW_DEFAULT);
4975 dictAppendWord(dp, "forth-wordlist",
4976 forthWordlist, FW_DEFAULT);
4977 dictAppendWord(dp, "get-current",
4978 getCurrent, FW_DEFAULT);
4979 dictAppendWord(dp, "get-order", getOrder, FW_DEFAULT);
4980 dictAppendWord(dp, "search-wordlist",
4981 searchWordlist, FW_DEFAULT);
4982 dictAppendWord(dp, "set-current",
4983 setCurrent, FW_DEFAULT);
4984 dictAppendWord(dp, "set-order", setOrder, FW_DEFAULT);
4985 dictAppendWord(dp, "ficl-wordlist", wordlist, FW_DEFAULT);
4988 ** Set SEARCH environment query values
4990 ficlSetEnv("search-order", FICL_TRUE);
4991 ficlSetEnv("search-order-ext", FICL_TRUE);
4992 ficlSetEnv("wordlists", FICL_DEFAULT_VOCS);
4995 ** TOOLS and TOOLS EXT
4997 dictAppendWord(dp, ".s", displayStack, FW_DEFAULT);
4998 dictAppendWord(dp, "bye", bye, FW_DEFAULT);
4999 dictAppendWord(dp, "forget", forget, FW_DEFAULT);
5000 dictAppendWord(dp, "see", see, FW_DEFAULT);
5001 dictAppendWord(dp, "words", listWords, FW_DEFAULT);
5004 ** Set TOOLS environment query values
5006 ficlSetEnv("tools", FICL_TRUE);
5007 ficlSetEnv("tools-ext", FICL_FALSE);
5012 dictAppendWord(dp, ".env", listEnv, FW_DEFAULT);
5013 dictAppendWord(dp, ".ver", ficlVersion, FW_DEFAULT);
5014 dictAppendWord(dp, "-roll", minusRoll, FW_DEFAULT);
5015 dictAppendWord(dp, ">name", toName, FW_DEFAULT);
5016 dictAppendWord(dp, "body>", fromBody, FW_DEFAULT);
5017 dictAppendWord(dp, "compare", compareString, FW_DEFAULT); /* STRING */
5018 dictAppendWord(dp, "compile-only",
5019 compileOnly, FW_DEFAULT);
5020 dictAppendWord(dp, "endif", endifCoIm, FW_COMPIMMED);
5021 dictAppendWord(dp, "forget-wid",forgetWid, FW_DEFAULT);
5022 dictAppendWord(dp, "hash", hash, FW_DEFAULT);
5023 dictAppendWord(dp, "number?", ficlIsNum, FW_DEFAULT);
5024 dictAppendWord(dp, "parse-word",parseNoCopy, FW_DEFAULT);
5025 dictAppendWord(dp, "sliteral", sLiteralCoIm, FW_COMPIMMED); /* STRING */
5026 dictAppendWord(dp, "wid-set-super",
5027 setParentWid, FW_DEFAULT);
5028 dictAppendWord(dp, "i@", iFetch, FW_DEFAULT);
5029 dictAppendWord(dp, "i!", iStore, FW_DEFAULT);
5030 dictAppendWord(dp, "w@", wFetch, FW_DEFAULT);
5031 dictAppendWord(dp, "w!", wStore, FW_DEFAULT);
5032 dictAppendWord(dp, "x.", hexDot, FW_DEFAULT);
5034 dictAppendWord(dp, "(user)", userParen, FW_DEFAULT);
5035 dictAppendWord(dp, "user", userVariable, FW_DEFAULT);
5038 ** internal support words
5041 dictAppendWord(dp, "(exit)", exitParen, FW_COMPILE);
5043 dictAppendWord(dp, "(;)", semiParen, FW_COMPILE);
5045 dictAppendWord(dp, "(literal)", literalParen, FW_COMPILE);
5047 dictAppendWord(dp, "(2literal)",twoLitParen, FW_COMPILE);
5049 dictAppendWord(dp, "(.\")", stringLit, FW_COMPILE);
5051 dictAppendWord(dp, "(if)", ifParen, FW_COMPILE);
5053 dictAppendWord(dp, "(branch)", branchParen, FW_COMPILE);
5055 dictAppendWord(dp, "(do)", doParen, FW_COMPILE);
5057 dictAppendWord(dp, "(does>)", doesParen, FW_COMPILE);
5059 dictAppendWord(dp, "(?do)", qDoParen, FW_COMPILE);
5061 dictAppendWord(dp, "(loop)", loopParen, FW_COMPILE);
5063 dictAppendWord(dp, "(+loop)", plusLoopParen, FW_COMPILE);
5065 dictAppendWord(dp, "interpret", interpret, FW_DEFAULT);
5066 dictAppendWord(dp, "(variable)",variableParen, FW_COMPILE);
5067 dictAppendWord(dp, "(constant)",constantParen, FW_COMPILE);
5068 dictAppendWord(dp, "exit-inner",ficlExitInner, FW_DEFAULT);
5070 assert(dictCellsAvail(dp) > 0);