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
7 ** $Id: words.c,v 1.17 2001/12/05 07:21:34 jsadler Exp $
8 *******************************************************************/
10 ** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
11 ** All rights reserved.
13 ** Get the latest Ficl release at http://ficl.sourceforge.net
15 ** I am interested in hearing from anyone who uses ficl. If you have
16 ** a problem, a success story, a defect, an enhancement request, or
17 ** if you would like to contribute to the ficl release, please
18 ** contact me by email at the address above.
20 ** L I C E N S E and D I S C L A I M E R
22 ** Redistribution and use in source and binary forms, with or without
23 ** modification, are permitted provided that the following conditions
25 ** 1. Redistributions of source code must retain the above copyright
26 ** notice, this list of conditions and the following disclaimer.
27 ** 2. Redistributions in binary form must reproduce the above copyright
28 ** notice, this list of conditions and the following disclaimer in the
29 ** documentation and/or other materials provided with the distribution.
31 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
32 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
35 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * $FreeBSD: src/sys/boot/ficl/words.c,v 1.40 2007/03/23 22:26:01 jkim Exp $
46 * $DragonFly: src/sys/boot/ficl/words.c,v 1.4 2008/03/29 23:31:07 swildner Exp $
61 static void colonParen(FICL_VM
*pVM
);
62 static void literalIm(FICL_VM
*pVM
);
63 static int ficlParseWord(FICL_VM
*pVM
, STRINGINFO si
);
66 ** Control structure building words use these
67 ** strings' addresses as markers on the stack to
68 ** check for structure completion.
70 static char doTag
[] = "do";
71 static char colonTag
[] = "colon";
72 static char leaveTag
[] = "leave";
74 static char destTag
[] = "target";
75 static char origTag
[] = "origin";
77 static char caseTag
[] = "case";
78 static char ofTag
[] = "of";
79 static char fallthroughTag
[] = "fallthrough";
82 static void doLocalIm(FICL_VM
*pVM
);
83 static void do2LocalIm(FICL_VM
*pVM
);
88 ** C O N T R O L S T R U C T U R E B U I L D E R S
90 ** Push current dict location for later branch resolution.
91 ** The location may be either a branch target or a patch address...
93 static void markBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
100 static void markControlTag(FICL_VM
*pVM
, char *tag
)
106 static void matchControlTag(FICL_VM
*pVM
, char *tag
)
110 vmCheckStack(pVM
, 1, 0);
112 cp
= (char *)stackPopPtr(pVM
->pStack
);
114 ** Changed the code below to compare the pointers first (by popular demand)
116 if ( (cp
!= tag
) && strcmp(cp
, tag
) )
118 vmThrowErr(pVM
, "Error -- unmatched control structure \"%s\"", tag
);
125 ** Expect a branch target address on the param stack,
126 ** compile a literal offset from the current dict location
127 ** to the target address
129 static void resolveBackBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
134 matchControlTag(pVM
, tag
);
137 vmCheckStack(pVM
, 1, 0);
139 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
140 offset
= patchAddr
- dp
->here
;
141 dictAppendCell(dp
, LVALUEtoCELL(offset
));
148 ** Expect a branch patch address on the param stack,
149 ** compile a literal offset from the patch location
150 ** to the current dict location
152 static void resolveForwardBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
157 matchControlTag(pVM
, tag
);
160 vmCheckStack(pVM
, 1, 0);
162 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
163 offset
= dp
->here
- patchAddr
;
164 *patchAddr
= LVALUEtoCELL(offset
);
170 ** Match the tag to the top of the stack. If success,
171 ** sopy "here" address into the cell whose address is next
172 ** on the stack. Used by do..leave..loop.
174 static void resolveAbsBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
180 vmCheckStack(pVM
, 2, 0);
182 cp
= stackPopPtr(pVM
->pStack
);
184 ** Changed the comparison below to compare the pointers first (by popular demand)
186 if ((cp
!= tag
) && strcmp(cp
, tag
))
188 vmTextOut(pVM
, "Warning -- Unmatched control word: ", 0);
189 vmTextOut(pVM
, tag
, 1);
192 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
193 *patchAddr
= LVALUEtoCELL(dp
->here
);
199 /**************************************************************************
200 f i c l P a r s e N u m b e r
201 ** Attempts to convert the NULL terminated string in the VM's pad to
202 ** a number using the VM's current base. If successful, pushes the number
203 ** onto the param stack and returns TRUE. Otherwise, returns FALSE.
204 ** (jws 8/01) Trailing decimal point causes a zero cell to be pushed. (See
205 ** the standard for DOUBLE wordset.
206 **************************************************************************/
208 int ficlParseNumber(FICL_VM
*pVM
, STRINGINFO si
)
213 unsigned base
= pVM
->base
;
214 char *cp
= SI_PTR(si
);
215 FICL_COUNT count
= (FICL_COUNT
)SI_COUNT(si
);
238 if ((count
> 0) && (cp
[count
-1] == '.')) /* detect & remove trailing decimal */
244 if (count
== 0) /* detect "+", "-", ".", "+." etc */
247 while ((count
--) && ((ch
= *cp
++) != '\0'))
255 digit
= tolower(ch
) - 'a' + 10;
260 accum
= accum
* base
+ digit
;
263 if (hasDP
) /* simple (required) DOUBLE support */
270 if (pVM
->state
== COMPILE
)
277 /**************************************************************************
278 a d d & f r i e n d s
280 **************************************************************************/
282 static void add(FICL_VM
*pVM
)
286 vmCheckStack(pVM
, 2, 1);
288 i
= stackPopINT(pVM
->pStack
);
289 i
+= stackGetTop(pVM
->pStack
).i
;
290 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
294 static void sub(FICL_VM
*pVM
)
298 vmCheckStack(pVM
, 2, 1);
300 i
= stackPopINT(pVM
->pStack
);
301 i
= stackGetTop(pVM
->pStack
).i
- i
;
302 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
306 static void mul(FICL_VM
*pVM
)
310 vmCheckStack(pVM
, 2, 1);
312 i
= stackPopINT(pVM
->pStack
);
313 i
*= stackGetTop(pVM
->pStack
).i
;
314 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
318 static void negate(FICL_VM
*pVM
)
322 vmCheckStack(pVM
, 1, 1);
324 i
= -stackPopINT(pVM
->pStack
);
329 static void ficlDiv(FICL_VM
*pVM
)
333 vmCheckStack(pVM
, 2, 1);
335 i
= stackPopINT(pVM
->pStack
);
336 i
= stackGetTop(pVM
->pStack
).i
/ i
;
337 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
342 ** slash-mod CORE ( n1 n2 -- n3 n4 )
343 ** Divide n1 by n2, giving the single-cell remainder n3 and the single-cell
344 ** quotient n4. An ambiguous condition exists if n2 is zero. If n1 and n2
345 ** differ in sign, the implementation-defined result returned will be the
346 ** same as that returned by either the phrase
347 ** >R S>D R> FM/MOD or the phrase >R S>D R> SM/REM .
348 ** NOTE: Ficl complies with the second phrase (symmetric division)
350 static void slashMod(FICL_VM
*pVM
)
357 vmCheckStack(pVM
, 2, 2);
359 n2
= stackPopINT(pVM
->pStack
);
360 n1
.lo
= stackPopINT(pVM
->pStack
);
363 qr
= m64SymmetricDivI(n1
, n2
);
369 static void onePlus(FICL_VM
*pVM
)
373 vmCheckStack(pVM
, 1, 1);
375 i
= stackGetTop(pVM
->pStack
).i
;
377 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
381 static void oneMinus(FICL_VM
*pVM
)
385 vmCheckStack(pVM
, 1, 1);
387 i
= stackGetTop(pVM
->pStack
).i
;
389 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
393 static void twoMul(FICL_VM
*pVM
)
397 vmCheckStack(pVM
, 1, 1);
399 i
= stackGetTop(pVM
->pStack
).i
;
401 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
405 static void twoDiv(FICL_VM
*pVM
)
409 vmCheckStack(pVM
, 1, 1);
411 i
= stackGetTop(pVM
->pStack
).i
;
413 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
417 static void mulDiv(FICL_VM
*pVM
)
422 vmCheckStack(pVM
, 3, 1);
424 z
= stackPopINT(pVM
->pStack
);
425 y
= stackPopINT(pVM
->pStack
);
426 x
= stackPopINT(pVM
->pStack
);
429 x
= m64SymmetricDivI(prod
, z
).quot
;
436 static void mulDivRem(FICL_VM
*pVM
)
442 vmCheckStack(pVM
, 3, 2);
444 z
= stackPopINT(pVM
->pStack
);
445 y
= stackPopINT(pVM
->pStack
);
446 x
= stackPopINT(pVM
->pStack
);
449 qr
= m64SymmetricDivI(prod
, z
);
457 /**************************************************************************
458 c o l o n d e f i n i t i o n s
459 ** Code to begin compiling a colon definition
460 ** This function sets the state to COMPILE, then creates a
461 ** new word whose name is the next word in the input stream
462 ** and whose code is colonParen.
463 **************************************************************************/
465 static void colon(FICL_VM
*pVM
)
467 FICL_DICT
*dp
= vmGetDict(pVM
);
468 STRINGINFO si
= vmGetWord(pVM
);
470 dictCheckThreshold(dp
);
472 pVM
->state
= COMPILE
;
473 markControlTag(pVM
, colonTag
);
474 dictAppendWord2(dp
, si
, colonParen
, FW_DEFAULT
| FW_SMUDGE
);
476 pVM
->pSys
->nLocals
= 0;
482 /**************************************************************************
484 ** This is the code that executes a colon definition. It assumes that the
485 ** virtual machine is running a "next" loop (See the vm.c
486 ** for its implementation of member function vmExecute()). The colon
487 ** code simply copies the address of the first word in the list of words
488 ** to interpret into IP after saving its old value. When we return to the
489 ** "next" loop, the virtual machine will call the code for each word in
492 **************************************************************************/
494 static void colonParen(FICL_VM
*pVM
)
496 IPTYPE tempIP
= (IPTYPE
) (pVM
->runningWord
->param
);
497 vmPushIP(pVM
, tempIP
);
503 /**************************************************************************
504 s e m i c o l o n C o I m
506 ** IMMEDIATE code for ";". This function sets the state to INTERPRET and
507 ** terminates a word under compilation by appending code for "(;)" to
508 ** the definition. TO DO: checks for leftover branch target tags on the
509 ** return stack and complains if any are found.
510 **************************************************************************/
511 static void semiParen(FICL_VM
*pVM
)
518 static void semicolonCoIm(FICL_VM
*pVM
)
520 FICL_DICT
*dp
= vmGetDict(pVM
);
522 assert(pVM
->pSys
->pSemiParen
);
523 matchControlTag(pVM
, colonTag
);
526 assert(pVM
->pSys
->pUnLinkParen
);
527 if (pVM
->pSys
->nLocals
> 0)
529 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
530 dictEmpty(pLoc
, pLoc
->pForthWords
->size
);
531 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
533 pVM
->pSys
->nLocals
= 0;
536 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pSemiParen
));
537 pVM
->state
= INTERPRET
;
543 /**************************************************************************
546 ** This function simply pops the previous instruction
547 ** pointer and returns to the "next" loop. Used for exiting from within
548 ** a definition. Note that exitParen is identical to semiParen - they
549 ** are in two different functions so that "see" can correctly identify
550 ** the end of a colon definition, even if it uses "exit".
551 **************************************************************************/
552 static void exitParen(FICL_VM
*pVM
)
558 static void exitCoIm(FICL_VM
*pVM
)
560 FICL_DICT
*dp
= vmGetDict(pVM
);
561 assert(pVM
->pSys
->pExitParen
);
565 if (pVM
->pSys
->nLocals
> 0)
567 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
570 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pExitParen
));
575 /**************************************************************************
576 c o n s t a n t P a r e n
577 ** This is the run-time code for "constant". It simply returns the
578 ** contents of its word's first data cell.
580 **************************************************************************/
582 void constantParen(FICL_VM
*pVM
)
584 FICL_WORD
*pFW
= pVM
->runningWord
;
586 vmCheckStack(pVM
, 0, 1);
588 stackPush(pVM
->pStack
, pFW
->param
[0]);
592 void twoConstParen(FICL_VM
*pVM
)
594 FICL_WORD
*pFW
= pVM
->runningWord
;
596 vmCheckStack(pVM
, 0, 2);
598 stackPush(pVM
->pStack
, pFW
->param
[0]); /* lo */
599 stackPush(pVM
->pStack
, pFW
->param
[1]); /* hi */
604 /**************************************************************************
607 ** Compiles a constant into the dictionary. Constants return their
608 ** value when invoked. Expects a value on top of the parm stack.
609 **************************************************************************/
611 static void constant(FICL_VM
*pVM
)
613 FICL_DICT
*dp
= vmGetDict(pVM
);
614 STRINGINFO si
= vmGetWord(pVM
);
617 vmCheckStack(pVM
, 1, 0);
619 dictAppendWord2(dp
, si
, constantParen
, FW_DEFAULT
);
620 dictAppendCell(dp
, stackPop(pVM
->pStack
));
625 static void twoConstant(FICL_VM
*pVM
)
627 FICL_DICT
*dp
= vmGetDict(pVM
);
628 STRINGINFO si
= vmGetWord(pVM
);
632 vmCheckStack(pVM
, 2, 0);
634 c
= stackPop(pVM
->pStack
);
635 dictAppendWord2(dp
, si
, twoConstParen
, FW_DEFAULT
);
636 dictAppendCell(dp
, stackPop(pVM
->pStack
));
637 dictAppendCell(dp
, c
);
642 /**************************************************************************
643 d i s p l a y C e l l
644 ** Drop and print the contents of the cell at the top of the param
646 **************************************************************************/
648 static void displayCell(FICL_VM
*pVM
)
652 vmCheckStack(pVM
, 1, 0);
654 c
= stackPop(pVM
->pStack
);
655 ltoa((c
).i
, pVM
->pad
, pVM
->base
);
656 strcat(pVM
->pad
, " ");
657 vmTextOut(pVM
, pVM
->pad
, 0);
661 static void uDot(FICL_VM
*pVM
)
665 vmCheckStack(pVM
, 1, 0);
667 u
= stackPopUNS(pVM
->pStack
);
668 ultoa(u
, pVM
->pad
, pVM
->base
);
669 strcat(pVM
->pad
, " ");
670 vmTextOut(pVM
, pVM
->pad
, 0);
675 static void hexDot(FICL_VM
*pVM
)
679 vmCheckStack(pVM
, 1, 0);
681 u
= stackPopUNS(pVM
->pStack
);
682 ultoa(u
, pVM
->pad
, 16);
683 strcat(pVM
->pad
, " ");
684 vmTextOut(pVM
, pVM
->pad
, 0);
689 /**************************************************************************
691 ** FICL ( c-string -- length )
693 ** Returns the length of a C-style (zero-terminated) string.
697 static void ficlStrlen(FICL_VM
*ficlVM
)
699 char *address
= (char *)stackPopPtr(ficlVM
->pStack
);
700 stackPushINT(ficlVM
->pStack
, strlen(address
));
704 /**************************************************************************
706 ** FICL ( i*x c-addr-fmt u-fmt c-addr-buffer u-buffer -- c-addr-buffer u-written success-flag )
707 ** Similar to the C sprintf() function. It formats into a buffer based on
708 ** a "format" string. Each character in the format string is copied verbatim
709 ** to the output buffer, until SPRINTF encounters a percent sign ("%").
710 ** SPRINTF then skips the percent sign, and examines the next character
711 ** (the "format character"). Here are the valid format characters:
712 ** s - read a C-ADDR U-LENGTH string from the stack and copy it to
714 ** d - read a cell from the stack, format it as a string (base-10,
715 ** signed), and copy it to the buffer
716 ** x - same as d, except in base-16
717 ** u - same as d, but unsigned
718 ** % - output a literal percent-sign to the buffer
719 ** SPRINTF returns the c-addr-buffer argument unchanged, the number of bytes
720 ** written, and a flag indicating whether or not it ran out of space while
721 ** writing to the output buffer (TRUE if it ran out of space).
723 ** If SPRINTF runs out of space in the buffer to store the formatted string,
724 ** it still continues parsing, in an effort to preserve your stack (otherwise
725 ** it might leave uneaten arguments behind).
728 **************************************************************************/
729 static void ficlSprintf(FICL_VM
*pVM
) /* */
731 int bufferLength
= stackPopINT(pVM
->pStack
);
732 char *buffer
= (char *)stackPopPtr(pVM
->pStack
);
733 char *bufferStart
= buffer
;
735 int formatLength
= stackPopINT(pVM
->pStack
);
736 char *format
= (char *)stackPopPtr(pVM
->pStack
);
737 char *formatStop
= format
+ formatLength
;
740 int unsignedInteger
= FALSE
;
742 FICL_INT append
= FICL_TRUE
;
744 while (format
< formatStop
)
756 actualLength
= desiredLength
= 1;
762 if (format
== formatStop
)
765 leadingZeroes
= (*format
== '0');
769 if (format
== formatStop
)
773 desiredLength
= isdigit(*format
);
776 desiredLength
= strtol(format
, &format
, 10);
777 if (format
== formatStop
)
780 else if (*format
== '*')
782 desiredLength
= stackPopINT(pVM
->pStack
);
784 if (format
== formatStop
)
794 actualLength
= stackPopINT(pVM
->pStack
);
795 source
= (char *)stackPopPtr(pVM
->pStack
);
803 unsignedInteger
= TRUE
;
807 int integer
= stackPopINT(pVM
->pStack
);
809 ultoa(integer
, scratch
, base
);
811 ltoa(integer
, scratch
, base
);
813 unsignedInteger
= FALSE
;
815 actualLength
= strlen(scratch
);
826 if (append
!= FICL_FALSE
)
829 desiredLength
= actualLength
;
830 if (desiredLength
> bufferLength
)
833 desiredLength
= bufferLength
;
835 while (desiredLength
> actualLength
)
837 *buffer
++ = (char)((leadingZeroes
) ? '0' : ' ');
841 memcpy(buffer
, source
, actualLength
);
842 buffer
+= actualLength
;
843 bufferLength
-= actualLength
;
849 stackPushPtr(pVM
->pStack
, bufferStart
);
850 stackPushINT(pVM
->pStack
, buffer
- bufferStart
);
851 stackPushINT(pVM
->pStack
, append
);
855 /**************************************************************************
856 d u p & f r i e n d s
858 **************************************************************************/
860 static void depth(FICL_VM
*pVM
)
864 vmCheckStack(pVM
, 0, 1);
866 i
= stackDepth(pVM
->pStack
);
872 static void drop(FICL_VM
*pVM
)
875 vmCheckStack(pVM
, 1, 0);
877 stackDrop(pVM
->pStack
, 1);
882 static void twoDrop(FICL_VM
*pVM
)
885 vmCheckStack(pVM
, 2, 0);
887 stackDrop(pVM
->pStack
, 2);
892 static void dup(FICL_VM
*pVM
)
895 vmCheckStack(pVM
, 1, 2);
897 stackPick(pVM
->pStack
, 0);
902 static void twoDup(FICL_VM
*pVM
)
905 vmCheckStack(pVM
, 2, 4);
907 stackPick(pVM
->pStack
, 1);
908 stackPick(pVM
->pStack
, 1);
913 static void over(FICL_VM
*pVM
)
916 vmCheckStack(pVM
, 2, 3);
918 stackPick(pVM
->pStack
, 1);
922 static void twoOver(FICL_VM
*pVM
)
925 vmCheckStack(pVM
, 4, 6);
927 stackPick(pVM
->pStack
, 3);
928 stackPick(pVM
->pStack
, 3);
933 static void pick(FICL_VM
*pVM
)
935 CELL c
= stackPop(pVM
->pStack
);
937 vmCheckStack(pVM
, c
.i
+1, c
.i
+2);
939 stackPick(pVM
->pStack
, c
.i
);
944 static void questionDup(FICL_VM
*pVM
)
948 vmCheckStack(pVM
, 1, 2);
950 c
= stackGetTop(pVM
->pStack
);
953 stackPick(pVM
->pStack
, 0);
959 static void roll(FICL_VM
*pVM
)
961 int i
= stackPop(pVM
->pStack
).i
;
964 vmCheckStack(pVM
, i
+1, i
+1);
966 stackRoll(pVM
->pStack
, i
);
971 static void minusRoll(FICL_VM
*pVM
)
973 int i
= stackPop(pVM
->pStack
).i
;
976 vmCheckStack(pVM
, i
+1, i
+1);
978 stackRoll(pVM
->pStack
, -i
);
983 static void rot(FICL_VM
*pVM
)
986 vmCheckStack(pVM
, 3, 3);
988 stackRoll(pVM
->pStack
, 2);
993 static void swap(FICL_VM
*pVM
)
996 vmCheckStack(pVM
, 2, 2);
998 stackRoll(pVM
->pStack
, 1);
1003 static void twoSwap(FICL_VM
*pVM
)
1006 vmCheckStack(pVM
, 4, 4);
1008 stackRoll(pVM
->pStack
, 3);
1009 stackRoll(pVM
->pStack
, 3);
1014 /**************************************************************************
1015 e m i t & f r i e n d s
1017 **************************************************************************/
1019 static void emit(FICL_VM
*pVM
)
1021 char *cp
= pVM
->pad
;
1025 vmCheckStack(pVM
, 1, 0);
1027 i
= stackPopINT(pVM
->pStack
);
1030 vmTextOut(pVM
, cp
, 0);
1035 static void cr(FICL_VM
*pVM
)
1037 vmTextOut(pVM
, "", 1);
1042 static void commentLine(FICL_VM
*pVM
)
1044 char *cp
= vmGetInBuf(pVM
);
1045 char *pEnd
= vmGetInBufEnd(pVM
);
1048 while ((cp
!= pEnd
) && (ch
!= '\r') && (ch
!= '\n'))
1054 ** Cope with DOS or UNIX-style EOLs -
1055 ** Check for /r, /n, /r/n, or /n/r end-of-line sequences,
1056 ** and point cp to next char. If EOL is \0, we're done.
1062 if ( (cp
!= pEnd
) && (ch
!= *cp
)
1063 && ((*cp
== '\r') || (*cp
== '\n')) )
1067 vmUpdateTib(pVM
, cp
);
1074 ** Compilation: Perform the execution semantics given below.
1075 ** Execution: ( "ccc<paren>" -- )
1076 ** Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
1077 ** The number of characters in ccc may be zero to the number of characters
1078 ** in the parse area.
1081 static void commentHang(FICL_VM
*pVM
)
1083 vmParseStringEx(pVM
, ')', 0);
1088 /**************************************************************************
1089 F E T C H & S T O R E
1091 **************************************************************************/
1093 static void fetch(FICL_VM
*pVM
)
1097 vmCheckStack(pVM
, 1, 1);
1099 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1100 stackPush(pVM
->pStack
, *pCell
);
1105 ** two-fetch CORE ( a-addr -- x1 x2 )
1106 ** Fetch the cell pair x1 x2 stored at a-addr. x2 is stored at a-addr and
1107 ** x1 at the next consecutive cell. It is equivalent to the sequence
1108 ** DUP CELL+ @ SWAP @ .
1110 static void twoFetch(FICL_VM
*pVM
)
1114 vmCheckStack(pVM
, 1, 2);
1116 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1117 stackPush(pVM
->pStack
, *pCell
++);
1118 stackPush(pVM
->pStack
, *pCell
);
1124 ** store CORE ( x a-addr -- )
1125 ** Store x at a-addr.
1127 static void store(FICL_VM
*pVM
)
1131 vmCheckStack(pVM
, 2, 0);
1133 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1134 *pCell
= stackPop(pVM
->pStack
);
1138 ** two-store CORE ( x1 x2 a-addr -- )
1139 ** Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
1140 ** next consecutive cell. It is equivalent to the sequence
1141 ** SWAP OVER ! CELL+ ! .
1143 static void twoStore(FICL_VM
*pVM
)
1147 vmCheckStack(pVM
, 3, 0);
1149 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1150 *pCell
++ = stackPop(pVM
->pStack
);
1151 *pCell
= stackPop(pVM
->pStack
);
1154 static void plusStore(FICL_VM
*pVM
)
1158 vmCheckStack(pVM
, 2, 0);
1160 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1161 pCell
->i
+= stackPop(pVM
->pStack
).i
;
1165 static void quadFetch(FICL_VM
*pVM
)
1169 vmCheckStack(pVM
, 1, 1);
1171 pw
= (UNS32
*)stackPopPtr(pVM
->pStack
);
1172 PUSHUNS((FICL_UNS
)*pw
);
1176 static void quadStore(FICL_VM
*pVM
)
1180 vmCheckStack(pVM
, 2, 0);
1182 pw
= (UNS32
*)stackPopPtr(pVM
->pStack
);
1183 *pw
= (UNS32
)(stackPop(pVM
->pStack
).u
);
1186 static void wFetch(FICL_VM
*pVM
)
1190 vmCheckStack(pVM
, 1, 1);
1192 pw
= (UNS16
*)stackPopPtr(pVM
->pStack
);
1193 PUSHUNS((FICL_UNS
)*pw
);
1197 static void wStore(FICL_VM
*pVM
)
1201 vmCheckStack(pVM
, 2, 0);
1203 pw
= (UNS16
*)stackPopPtr(pVM
->pStack
);
1204 *pw
= (UNS16
)(stackPop(pVM
->pStack
).u
);
1207 static void cFetch(FICL_VM
*pVM
)
1211 vmCheckStack(pVM
, 1, 1);
1213 pc
= (UNS8
*)stackPopPtr(pVM
->pStack
);
1214 PUSHUNS((FICL_UNS
)*pc
);
1218 static void cStore(FICL_VM
*pVM
)
1222 vmCheckStack(pVM
, 2, 0);
1224 pc
= (UNS8
*)stackPopPtr(pVM
->pStack
);
1225 *pc
= (UNS8
)(stackPop(pVM
->pStack
).u
);
1229 /**************************************************************************
1230 b r a n c h P a r e n
1232 ** Runtime for "(branch)" -- expects a literal offset in the next
1233 ** compilation address, and branches to that location.
1234 **************************************************************************/
1236 static void branchParen(FICL_VM
*pVM
)
1238 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1243 /**************************************************************************
1245 ** Runtime code for "(branch0)"; pop a flag from the stack,
1246 ** branch if 0. fall through otherwise. The heart of "if" and "until".
1247 **************************************************************************/
1249 static void branch0(FICL_VM
*pVM
)
1254 vmCheckStack(pVM
, 1, 0);
1256 flag
= stackPopUNS(pVM
->pStack
);
1259 { /* fall through */
1260 vmBranchRelative(pVM
, 1);
1263 { /* take branch (to else/endif/begin) */
1264 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1271 /**************************************************************************
1273 ** IMMEDIATE COMPILE-ONLY
1274 ** Compiles code for a conditional branch into the dictionary
1275 ** and pushes the branch patch address on the stack for later
1276 ** patching by ELSE or THEN/ENDIF.
1277 **************************************************************************/
1279 static void ifCoIm(FICL_VM
*pVM
)
1281 FICL_DICT
*dp
= vmGetDict(pVM
);
1283 assert(pVM
->pSys
->pBranch0
);
1285 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
1286 markBranch(dp
, pVM
, origTag
);
1287 dictAppendUNS(dp
, 1);
1292 /**************************************************************************
1295 ** IMMEDIATE COMPILE-ONLY
1296 ** compiles an "else"...
1297 ** 1) Compile a branch and a patch address; the address gets patched
1298 ** by "endif" to point past the "else" code.
1299 ** 2) Pop the the "if" patch address
1300 ** 3) Patch the "if" branch to point to the current compile address.
1301 ** 4) Push the "else" patch address. ("endif" patches this to jump past
1303 **************************************************************************/
1305 static void elseCoIm(FICL_VM
*pVM
)
1309 FICL_DICT
*dp
= vmGetDict(pVM
);
1311 assert(pVM
->pSys
->pBranchParen
);
1312 /* (1) compile branch runtime */
1313 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1314 matchControlTag(pVM
, origTag
);
1316 (CELL
*)stackPopPtr(pVM
->pStack
); /* (2) pop "if" patch addr */
1317 markBranch(dp
, pVM
, origTag
); /* (4) push "else" patch addr */
1318 dictAppendUNS(dp
, 1); /* (1) compile patch placeholder */
1319 offset
= dp
->here
- patchAddr
;
1320 *patchAddr
= LVALUEtoCELL(offset
); /* (3) Patch "if" */
1326 /**************************************************************************
1328 ** IMMEDIATE COMPILE-ONLY
1329 **************************************************************************/
1331 static void endifCoIm(FICL_VM
*pVM
)
1333 FICL_DICT
*dp
= vmGetDict(pVM
);
1334 resolveForwardBranch(dp
, pVM
, origTag
);
1339 /**************************************************************************
1341 ** IMMEDIATE COMPILE-ONLY
1344 ** At compile-time, a CASE-SYS (see DPANS94 6.2.0873) looks like this:
1346 ** and an OF-SYS (see DPANS94 6.2.1950) looks like this:
1347 ** i*addr i caseTag addr ofTag
1348 ** The integer under caseTag is the count of fixup addresses that branch
1350 **************************************************************************/
1352 static void caseCoIm(FICL_VM
*pVM
)
1355 vmCheckStack(pVM
, 0, 2);
1359 markControlTag(pVM
, caseTag
);
1364 /**************************************************************************
1365 e n d c a s eC o I m
1366 ** IMMEDIATE COMPILE-ONLY
1367 **************************************************************************/
1369 static void endcaseCoIm(FICL_VM
*pVM
)
1371 FICL_UNS fixupCount
;
1376 assert(pVM
->pSys
->pDrop
);
1379 ** if the last OF ended with FALLTHROUGH,
1380 ** just add the FALLTHROUGH fixup to the
1383 if (stackGetTop(pVM
->pStack
).p
== fallthroughTag
)
1385 matchControlTag(pVM
, fallthroughTag
);
1386 patchAddr
= POPPTR();
1387 matchControlTag(pVM
, caseTag
);
1388 fixupCount
= POPUNS();
1390 PUSHUNS(fixupCount
+ 1);
1391 markControlTag(pVM
, caseTag
);
1394 matchControlTag(pVM
, caseTag
);
1397 vmCheckStack(pVM
, 1, 0);
1399 fixupCount
= POPUNS();
1401 vmCheckStack(pVM
, fixupCount
, 0);
1404 dp
= vmGetDict(pVM
);
1406 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDrop
));
1408 while (fixupCount
--)
1410 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1411 offset
= dp
->here
- patchAddr
;
1412 *patchAddr
= LVALUEtoCELL(offset
);
1418 static void ofParen(FICL_VM
*pVM
)
1423 vmCheckStack(pVM
, 2, 1);
1427 b
= stackGetTop(pVM
->pStack
).u
;
1430 { /* fall through */
1431 stackDrop(pVM
->pStack
, 1);
1432 vmBranchRelative(pVM
, 1);
1435 { /* take branch to next of or endswitch */
1436 vmBranchRelative(pVM
, *(int *)(pVM
->ip
));
1443 /**************************************************************************
1445 ** IMMEDIATE COMPILE-ONLY
1446 **************************************************************************/
1448 static void ofCoIm(FICL_VM
*pVM
)
1450 FICL_DICT
*dp
= vmGetDict(pVM
);
1451 CELL
*fallthroughFixup
= NULL
;
1453 assert(pVM
->pSys
->pBranch0
);
1456 vmCheckStack(pVM
, 1, 3);
1459 if (stackGetTop(pVM
->pStack
).p
== fallthroughTag
)
1461 matchControlTag(pVM
, fallthroughTag
);
1462 fallthroughFixup
= POPPTR();
1465 matchControlTag(pVM
, caseTag
);
1467 markControlTag(pVM
, caseTag
);
1469 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pOfParen
));
1470 markBranch(dp
, pVM
, ofTag
);
1471 dictAppendUNS(dp
, 2);
1473 if (fallthroughFixup
!= NULL
)
1475 FICL_INT offset
= dp
->here
- fallthroughFixup
;
1476 *fallthroughFixup
= LVALUEtoCELL(offset
);
1483 /**************************************************************************
1485 ** IMMEDIATE COMPILE-ONLY
1486 **************************************************************************/
1488 static void endofCoIm(FICL_VM
*pVM
)
1491 FICL_UNS fixupCount
;
1493 FICL_DICT
*dp
= vmGetDict(pVM
);
1496 vmCheckStack(pVM
, 4, 3);
1499 assert(pVM
->pSys
->pBranchParen
);
1501 /* ensure we're in an OF, */
1502 matchControlTag(pVM
, ofTag
);
1503 /* grab the address of the branch location after the OF */
1504 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1505 /* ensure we're also in a "case" */
1506 matchControlTag(pVM
, caseTag
);
1507 /* grab the current number of ENDOF fixups */
1508 fixupCount
= POPUNS();
1510 /* compile branch runtime */
1511 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1513 /* push a new ENDOF fixup, the updated count of ENDOF fixups, and the caseTag */
1515 PUSHUNS(fixupCount
+ 1);
1516 markControlTag(pVM
, caseTag
);
1518 /* reserve space for the ENDOF fixup */
1519 dictAppendUNS(dp
, 2);
1521 /* and patch the original OF */
1522 offset
= dp
->here
- patchAddr
;
1523 *patchAddr
= LVALUEtoCELL(offset
);
1527 /**************************************************************************
1528 f a l l t h r o u g h C o I m
1529 ** IMMEDIATE COMPILE-ONLY
1530 **************************************************************************/
1532 static void fallthroughCoIm(FICL_VM
*pVM
)
1536 FICL_DICT
*dp
= vmGetDict(pVM
);
1539 vmCheckStack(pVM
, 4, 3);
1542 /* ensure we're in an OF, */
1543 matchControlTag(pVM
, ofTag
);
1544 /* grab the address of the branch location after the OF */
1545 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1546 /* ensure we're also in a "case" */
1547 matchControlTag(pVM
, caseTag
);
1549 /* okay, here we go. put the case tag back. */
1550 markControlTag(pVM
, caseTag
);
1552 /* compile branch runtime */
1553 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1555 /* push a new FALLTHROUGH fixup and the fallthroughTag */
1557 markControlTag(pVM
, fallthroughTag
);
1559 /* reserve space for the FALLTHROUGH fixup */
1560 dictAppendUNS(dp
, 2);
1562 /* and patch the original OF */
1563 offset
= dp
->here
- patchAddr
;
1564 *patchAddr
= LVALUEtoCELL(offset
);
1567 /**************************************************************************
1569 ** hash ( c-addr u -- code)
1570 ** calculates hashcode of specified string and leaves it on the stack
1571 **************************************************************************/
1573 static void hash(FICL_VM
*pVM
)
1576 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1577 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1578 PUSHUNS(hashHashCode(si
));
1583 /**************************************************************************
1585 ** This is the "user interface" of a Forth. It does the following:
1586 ** while there are words in the VM's Text Input Buffer
1587 ** Copy next word into the pad (vmGetWord)
1588 ** Attempt to find the word in the dictionary (dictLookup)
1589 ** If successful, execute the word.
1590 ** Otherwise, attempt to convert the word to a number (isNumber)
1591 ** If successful, push the number onto the parameter stack.
1592 ** Otherwise, print an error message and exit loop...
1595 ** From the standard, section 3.4
1596 ** Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
1597 ** repeat the following steps until either the parse area is empty or an
1598 ** ambiguous condition exists:
1599 ** a) Skip leading spaces and parse a name (see 3.4.1);
1600 **************************************************************************/
1602 static void interpret(FICL_VM
*pVM
)
1611 si
= vmGetWord0(pVM
);
1614 ** Get next word...if out of text, we're done.
1618 vmThrow(pVM
, VM_OUTOFTEXT
);
1622 ** Attempt to find the incoming token in the dictionary. If that fails...
1623 ** run the parse chain against the incoming token until somebody eats it.
1624 ** Otherwise emit an error message and give up.
1625 ** Although ficlParseWord could be part of the parse list, I've hard coded it
1626 ** in for robustness. ficlInitSystem adds the other default steps to the list.
1628 if (ficlParseWord(pVM
, si
))
1631 for (i
=0; i
< FICL_MAX_PARSE_STEPS
; i
++)
1633 FICL_WORD
*pFW
= pSys
->parseList
[i
];
1638 if (pFW
->code
== parseStepParen
)
1640 FICL_PARSE_STEP pStep
;
1641 pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1642 if ((*pStep
)(pVM
, si
))
1647 stackPushPtr(pVM
->pStack
, SI_PTR(si
));
1648 stackPushUNS(pVM
->pStack
, SI_COUNT(si
));
1649 ficlExecXT(pVM
, pFW
);
1650 if (stackPopINT(pVM
->pStack
))
1656 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
1658 return; /* back to inner interpreter */
1662 /**************************************************************************
1663 f i c l P a r s e W o r d
1664 ** From the standard, section 3.4
1665 ** b) Search the dictionary name space (see 3.4.2). If a definition name
1666 ** matching the string is found:
1667 ** 1.if interpreting, perform the interpretation semantics of the definition
1668 ** (see 3.4.3.2), and continue at a);
1669 ** 2.if compiling, perform the compilation semantics of the definition
1670 ** (see 3.4.3.3), and continue at a).
1672 ** c) If a definition name matching the string is not found, attempt to
1673 ** convert the string to a number (see 3.4.1.3). If successful:
1674 ** 1.if interpreting, place the number on the data stack, and continue at a);
1675 ** 2.if compiling, compile code that when executed will place the number on
1676 ** the stack (see 6.1.1780 LITERAL), and continue at a);
1678 ** d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
1680 ** (jws 4/01) Modified to be a FICL_PARSE_STEP
1681 **************************************************************************/
1682 static int ficlParseWord(FICL_VM
*pVM
, STRINGINFO si
)
1684 FICL_DICT
*dp
= vmGetDict(pVM
);
1688 dictCheck(dp
, pVM
, 0);
1689 vmCheckStack(pVM
, 0, 0);
1692 #if FICL_WANT_LOCALS
1693 if (pVM
->pSys
->nLocals
> 0)
1695 tempFW
= ficlLookupLoc(pVM
->pSys
, si
);
1699 tempFW
= dictLookup(dp
, si
);
1701 if (pVM
->state
== INTERPRET
)
1705 if (wordIsCompileOnly(tempFW
))
1707 vmThrowErr(pVM
, "Error: Compile only!");
1710 vmExecute(pVM
, tempFW
);
1711 return (int)FICL_TRUE
;
1715 else /* (pVM->state == COMPILE) */
1719 if (wordIsImmediate(tempFW
))
1721 vmExecute(pVM
, tempFW
);
1725 dictAppendCell(dp
, LVALUEtoCELL(tempFW
));
1727 return (int)FICL_TRUE
;
1736 ** Surrogate precompiled parse step for ficlParseWord (this step is hard coded in
1739 static void lookup(FICL_VM
*pVM
)
1742 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1743 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1744 stackPushINT(pVM
->pStack
, ficlParseWord(pVM
, si
));
1749 /**************************************************************************
1750 p a r e n P a r s e S t e p
1751 ** (parse-step) ( c-addr u -- flag )
1752 ** runtime for a precompiled parse step - pop a counted string off the
1753 ** stack, run the parse step against it, and push the result flag (FICL_TRUE
1754 ** if success, FICL_FALSE otherwise).
1755 **************************************************************************/
1757 void parseStepParen(FICL_VM
*pVM
)
1760 FICL_WORD
*pFW
= pVM
->runningWord
;
1761 FICL_PARSE_STEP pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1763 SI_SETLEN(si
, stackPopINT(pVM
->pStack
));
1764 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1766 PUSHINT((*pStep
)(pVM
, si
));
1772 static void addParseStep(FICL_VM
*pVM
)
1775 FICL_DICT
*pd
= vmGetDict(pVM
);
1777 vmCheckStack(pVM
, 1, 0);
1779 pStep
= (FICL_WORD
*)(stackPop(pVM
->pStack
).p
);
1780 if ((pStep
!= NULL
) && isAFiclWord(pd
, pStep
))
1781 ficlAddParseStep(pVM
->pSys
, pStep
);
1786 /**************************************************************************
1787 l i t e r a l P a r e n
1789 ** This is the runtime for (literal). It assumes that it is part of a colon
1790 ** definition, and that the next CELL contains a value to be pushed on the
1791 ** parameter stack at runtime. This code is compiled by "literal".
1793 **************************************************************************/
1795 static void literalParen(FICL_VM
*pVM
)
1798 vmCheckStack(pVM
, 0, 1);
1800 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1801 vmBranchRelative(pVM
, 1);
1805 static void twoLitParen(FICL_VM
*pVM
)
1808 vmCheckStack(pVM
, 0, 2);
1810 PUSHINT(*((FICL_INT
*)(pVM
->ip
)+1));
1811 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1812 vmBranchRelative(pVM
, 2);
1817 /**************************************************************************
1820 ** IMMEDIATE code for "literal". This function gets a value from the stack
1821 ** and compiles it into the dictionary preceded by the code for "(literal)".
1823 **************************************************************************/
1825 static void literalIm(FICL_VM
*pVM
)
1827 FICL_DICT
*dp
= vmGetDict(pVM
);
1828 assert(pVM
->pSys
->pLitParen
);
1830 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLitParen
));
1831 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1837 static void twoLiteralIm(FICL_VM
*pVM
)
1839 FICL_DICT
*dp
= vmGetDict(pVM
);
1840 assert(pVM
->pSys
->pTwoLitParen
);
1842 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTwoLitParen
));
1843 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1844 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1849 /**************************************************************************
1850 l o g i c a n d c o m p a r i s o n s
1852 **************************************************************************/
1854 static void zeroEquals(FICL_VM
*pVM
)
1858 vmCheckStack(pVM
, 1, 1);
1860 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) == 0);
1861 stackPush(pVM
->pStack
, c
);
1865 static void zeroLess(FICL_VM
*pVM
)
1869 vmCheckStack(pVM
, 1, 1);
1871 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) < 0);
1872 stackPush(pVM
->pStack
, c
);
1876 static void zeroGreater(FICL_VM
*pVM
)
1880 vmCheckStack(pVM
, 1, 1);
1882 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) > 0);
1883 stackPush(pVM
->pStack
, c
);
1887 static void isEqual(FICL_VM
*pVM
)
1892 vmCheckStack(pVM
, 2, 1);
1894 x
= stackPop(pVM
->pStack
);
1895 y
= stackPop(pVM
->pStack
);
1896 PUSHINT(FICL_BOOL(x
.i
== y
.i
));
1900 static void isLess(FICL_VM
*pVM
)
1904 vmCheckStack(pVM
, 2, 1);
1906 y
= stackPop(pVM
->pStack
);
1907 x
= stackPop(pVM
->pStack
);
1908 PUSHINT(FICL_BOOL(x
.i
< y
.i
));
1912 static void uIsLess(FICL_VM
*pVM
)
1916 vmCheckStack(pVM
, 2, 1);
1918 u2
= stackPopUNS(pVM
->pStack
);
1919 u1
= stackPopUNS(pVM
->pStack
);
1920 PUSHINT(FICL_BOOL(u1
< u2
));
1924 static void isGreater(FICL_VM
*pVM
)
1928 vmCheckStack(pVM
, 2, 1);
1930 y
= stackPop(pVM
->pStack
);
1931 x
= stackPop(pVM
->pStack
);
1932 PUSHINT(FICL_BOOL(x
.i
> y
.i
));
1936 static void bitwiseAnd(FICL_VM
*pVM
)
1940 vmCheckStack(pVM
, 2, 1);
1942 x
= stackPop(pVM
->pStack
);
1943 y
= stackPop(pVM
->pStack
);
1948 static void bitwiseOr(FICL_VM
*pVM
)
1952 vmCheckStack(pVM
, 2, 1);
1954 x
= stackPop(pVM
->pStack
);
1955 y
= stackPop(pVM
->pStack
);
1960 static void bitwiseXor(FICL_VM
*pVM
)
1964 vmCheckStack(pVM
, 2, 1);
1966 x
= stackPop(pVM
->pStack
);
1967 y
= stackPop(pVM
->pStack
);
1972 static void bitwiseNot(FICL_VM
*pVM
)
1976 vmCheckStack(pVM
, 1, 1);
1978 x
= stackPop(pVM
->pStack
);
1984 /**************************************************************************
1986 ** do -- IMMEDIATE COMPILE ONLY
1987 ** Compiles code to initialize a loop: compile (do),
1988 ** allot space to hold the "leave" address, push a branch
1989 ** target address for the loop.
1990 ** (do) -- runtime for "do"
1991 ** pops index and limit from the p stack and moves them
1992 ** to the r stack, then skips to the loop body.
1993 ** loop -- IMMEDIATE COMPILE ONLY
1995 ** Compiles code for the test part of a loop:
1996 ** compile (loop), resolve forward branch from "do", and
1997 ** copy "here" address to the "leave" address allotted by "do"
1998 ** i,j,k -- COMPILE ONLY
1999 ** Runtime: Push loop indices on param stack (i is innermost loop...)
2000 ** Note: each loop has three values on the return stack:
2001 ** ( R: leave limit index )
2002 ** "leave" is the absolute address of the next cell after the loop
2003 ** limit and index are the loop control variables.
2004 ** leave -- COMPILE ONLY
2005 ** Runtime: pop the loop control variables, then pop the
2006 ** "leave" address and jump (absolute) there.
2007 **************************************************************************/
2009 static void doCoIm(FICL_VM
*pVM
)
2011 FICL_DICT
*dp
= vmGetDict(pVM
);
2013 assert(pVM
->pSys
->pDoParen
);
2015 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoParen
));
2017 ** Allot space for a pointer to the end
2018 ** of the loop - "leave" uses this...
2020 markBranch(dp
, pVM
, leaveTag
);
2021 dictAppendUNS(dp
, 0);
2023 ** Mark location of head of loop...
2025 markBranch(dp
, pVM
, doTag
);
2031 static void doParen(FICL_VM
*pVM
)
2035 vmCheckStack(pVM
, 2, 0);
2037 index
= stackPop(pVM
->pStack
);
2038 limit
= stackPop(pVM
->pStack
);
2040 /* copy "leave" target addr to stack */
2041 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
2042 stackPush(pVM
->rStack
, limit
);
2043 stackPush(pVM
->rStack
, index
);
2049 static void qDoCoIm(FICL_VM
*pVM
)
2051 FICL_DICT
*dp
= vmGetDict(pVM
);
2053 assert(pVM
->pSys
->pQDoParen
);
2055 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pQDoParen
));
2057 ** Allot space for a pointer to the end
2058 ** of the loop - "leave" uses this...
2060 markBranch(dp
, pVM
, leaveTag
);
2061 dictAppendUNS(dp
, 0);
2063 ** Mark location of head of loop...
2065 markBranch(dp
, pVM
, doTag
);
2071 static void qDoParen(FICL_VM
*pVM
)
2075 vmCheckStack(pVM
, 2, 0);
2077 index
= stackPop(pVM
->pStack
);
2078 limit
= stackPop(pVM
->pStack
);
2080 /* copy "leave" target addr to stack */
2081 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
2083 if (limit
.u
== index
.u
)
2089 stackPush(pVM
->rStack
, limit
);
2090 stackPush(pVM
->rStack
, index
);
2098 ** Runtime code to break out of a do..loop construct
2099 ** Drop the loop control variables; the branch address
2100 ** past "loop" is next on the return stack.
2102 static void leaveCo(FICL_VM
*pVM
)
2105 stackDrop(pVM
->rStack
, 2);
2112 static void unloopCo(FICL_VM
*pVM
)
2114 stackDrop(pVM
->rStack
, 3);
2119 static void loopCoIm(FICL_VM
*pVM
)
2121 FICL_DICT
*dp
= vmGetDict(pVM
);
2123 assert(pVM
->pSys
->pLoopParen
);
2125 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLoopParen
));
2126 resolveBackBranch(dp
, pVM
, doTag
);
2127 resolveAbsBranch(dp
, pVM
, leaveTag
);
2132 static void plusLoopCoIm(FICL_VM
*pVM
)
2134 FICL_DICT
*dp
= vmGetDict(pVM
);
2136 assert(pVM
->pSys
->pPLoopParen
);
2138 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pPLoopParen
));
2139 resolveBackBranch(dp
, pVM
, doTag
);
2140 resolveAbsBranch(dp
, pVM
, leaveTag
);
2145 static void loopParen(FICL_VM
*pVM
)
2147 FICL_INT index
= stackGetTop(pVM
->rStack
).i
;
2148 FICL_INT limit
= stackFetch(pVM
->rStack
, 1).i
;
2154 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
2155 vmBranchRelative(pVM
, 1); /* fall through the loop */
2158 { /* update index, branch to loop head */
2159 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
2160 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
2167 static void plusLoopParen(FICL_VM
*pVM
)
2169 FICL_INT index
,limit
,increment
;
2173 vmCheckStack(pVM
, 1, 0);
2176 index
= stackGetTop(pVM
->rStack
).i
;
2177 limit
= stackFetch(pVM
->rStack
, 1).i
;
2178 increment
= POP().i
;
2183 flag
= (index
< limit
);
2185 flag
= (index
>= limit
);
2189 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
2190 vmBranchRelative(pVM
, 1); /* fall through the loop */
2193 { /* update index, branch to loop head */
2194 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
2195 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
2202 static void loopICo(FICL_VM
*pVM
)
2204 CELL index
= stackGetTop(pVM
->rStack
);
2205 stackPush(pVM
->pStack
, index
);
2211 static void loopJCo(FICL_VM
*pVM
)
2213 CELL index
= stackFetch(pVM
->rStack
, 3);
2214 stackPush(pVM
->pStack
, index
);
2220 static void loopKCo(FICL_VM
*pVM
)
2222 CELL index
= stackFetch(pVM
->rStack
, 6);
2223 stackPush(pVM
->pStack
, index
);
2229 /**************************************************************************
2230 r e t u r n s t a c k
2232 **************************************************************************/
2233 static void toRStack(FICL_VM
*pVM
)
2236 vmCheckStack(pVM
, 1, 0);
2239 stackPush(pVM
->rStack
, POP());
2242 static void fromRStack(FICL_VM
*pVM
)
2245 vmCheckStack(pVM
, 0, 1);
2248 PUSH(stackPop(pVM
->rStack
));
2251 static void fetchRStack(FICL_VM
*pVM
)
2254 vmCheckStack(pVM
, 0, 1);
2257 PUSH(stackGetTop(pVM
->rStack
));
2260 static void twoToR(FICL_VM
*pVM
)
2263 vmCheckStack(pVM
, 2, 0);
2265 stackRoll(pVM
->pStack
, 1);
2266 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2267 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2271 static void twoRFrom(FICL_VM
*pVM
)
2274 vmCheckStack(pVM
, 0, 2);
2276 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2277 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2278 stackRoll(pVM
->pStack
, 1);
2282 static void twoRFetch(FICL_VM
*pVM
)
2285 vmCheckStack(pVM
, 0, 2);
2287 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 1));
2288 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 0));
2293 /**************************************************************************
2296 **************************************************************************/
2298 static void variableParen(FICL_VM
*pVM
)
2302 vmCheckStack(pVM
, 0, 1);
2305 fw
= pVM
->runningWord
;
2310 static void variable(FICL_VM
*pVM
)
2312 FICL_DICT
*dp
= vmGetDict(pVM
);
2313 STRINGINFO si
= vmGetWord(pVM
);
2315 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2316 dictAllotCells(dp
, 1);
2321 static void twoVariable(FICL_VM
*pVM
)
2323 FICL_DICT
*dp
= vmGetDict(pVM
);
2324 STRINGINFO si
= vmGetWord(pVM
);
2326 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2327 dictAllotCells(dp
, 2);
2332 /**************************************************************************
2333 b a s e & f r i e n d s
2335 **************************************************************************/
2337 static void base(FICL_VM
*pVM
)
2341 vmCheckStack(pVM
, 0, 1);
2344 pBase
= (CELL
*)(&pVM
->base
);
2345 stackPush(pVM
->pStack
, LVALUEtoCELL(pBase
));
2350 static void decimal(FICL_VM
*pVM
)
2357 static void hex(FICL_VM
*pVM
)
2364 /**************************************************************************
2365 a l l o t & f r i e n d s
2367 **************************************************************************/
2369 static void allot(FICL_VM
*pVM
)
2374 vmCheckStack(pVM
, 1, 0);
2377 dp
= vmGetDict(pVM
);
2381 dictCheck(dp
, pVM
, i
);
2389 static void here(FICL_VM
*pVM
)
2393 vmCheckStack(pVM
, 0, 1);
2396 dp
= vmGetDict(pVM
);
2401 static void comma(FICL_VM
*pVM
)
2406 vmCheckStack(pVM
, 1, 0);
2409 dp
= vmGetDict(pVM
);
2411 dictAppendCell(dp
, c
);
2415 static void cComma(FICL_VM
*pVM
)
2420 vmCheckStack(pVM
, 1, 0);
2423 dp
= vmGetDict(pVM
);
2425 dictAppendChar(dp
, c
);
2429 static void cells(FICL_VM
*pVM
)
2433 vmCheckStack(pVM
, 1, 1);
2437 PUSHINT(i
* (FICL_INT
)sizeof (CELL
));
2441 static void cellPlus(FICL_VM
*pVM
)
2445 vmCheckStack(pVM
, 1, 1);
2449 PUSHPTR(cp
+ sizeof (CELL
));
2455 /**************************************************************************
2457 ** tick CORE ( "<spaces>name" -- xt )
2458 ** Skip leading space delimiters. Parse name delimited by a space. Find
2459 ** name and return xt, the execution token for name. An ambiguous condition
2460 ** exists if name is not found.
2461 **************************************************************************/
2462 void ficlTick(FICL_VM
*pVM
)
2464 FICL_WORD
*pFW
= NULL
;
2465 STRINGINFO si
= vmGetWord(pVM
);
2467 vmCheckStack(pVM
, 0, 1);
2470 pFW
= dictLookup(vmGetDict(pVM
), si
);
2473 int i
= SI_COUNT(si
);
2474 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
2481 static void bracketTickCoIm(FICL_VM
*pVM
)
2490 /**************************************************************************
2492 ** Lookup the next word in the input stream and compile code to
2493 ** insert it into definitions created by the resulting word
2494 ** (defers compilation, even of immediate words)
2495 **************************************************************************/
2497 static void postponeCoIm(FICL_VM
*pVM
)
2499 FICL_DICT
*dp
= vmGetDict(pVM
);
2501 FICL_WORD
*pComma
= ficlLookup(pVM
->pSys
, ",");
2505 pFW
= stackGetTop(pVM
->pStack
).p
;
2506 if (wordIsImmediate(pFW
))
2508 dictAppendCell(dp
, stackPop(pVM
->pStack
));
2513 dictAppendCell(dp
, LVALUEtoCELL(pComma
));
2521 /**************************************************************************
2523 ** Pop an execution token (pointer to a word) off the stack and
2525 **************************************************************************/
2527 static void execute(FICL_VM
*pVM
)
2531 vmCheckStack(pVM
, 1, 0);
2534 pFW
= stackPopPtr(pVM
->pStack
);
2535 vmExecute(pVM
, pFW
);
2541 /**************************************************************************
2543 ** Make the most recently compiled word IMMEDIATE -- it executes even
2544 ** in compile state (most often used for control compiling words
2545 ** such as IF, THEN, etc)
2546 **************************************************************************/
2548 static void immediate(FICL_VM
*pVM
)
2551 dictSetImmediate(vmGetDict(pVM
));
2556 static void compileOnly(FICL_VM
*pVM
)
2559 dictSetFlags(vmGetDict(pVM
), FW_COMPILE
, 0);
2564 static void setObjectFlag(FICL_VM
*pVM
)
2567 dictSetFlags(vmGetDict(pVM
), FW_ISOBJECT
, 0);
2571 static void isObject(FICL_VM
*pVM
)
2574 FICL_WORD
*pFW
= (FICL_WORD
*)stackPopPtr(pVM
->pStack
);
2576 flag
= ((pFW
!= NULL
) && (pFW
->flags
& FW_ISOBJECT
)) ? FICL_TRUE
: FICL_FALSE
;
2577 stackPushINT(pVM
->pStack
, flag
);
2581 static void cstringLit(FICL_VM
*pVM
)
2583 FICL_STRING
*sp
= (FICL_STRING
*)(pVM
->ip
);
2585 char *cp
= sp
->text
;
2586 cp
+= sp
->count
+ 1;
2588 pVM
->ip
= (IPTYPE
)(void *)cp
;
2590 stackPushPtr(pVM
->pStack
, sp
);
2595 static void cstringQuoteIm(FICL_VM
*pVM
)
2597 FICL_DICT
*dp
= vmGetDict(pVM
);
2599 if (pVM
->state
== INTERPRET
)
2601 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
2602 vmGetString(pVM
, sp
, '\"');
2603 stackPushPtr(pVM
->pStack
, sp
);
2604 /* move HERE past string so it doesn't get overwritten. --lch */
2605 dictAllot(dp
, sp
->count
+ sizeof(FICL_COUNT
));
2607 else /* COMPILE state */
2609 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pCStringLit
));
2610 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2617 /**************************************************************************
2619 ** IMMEDIATE word that compiles a string literal for later display
2620 ** Compile stringLit, then copy the bytes of the string from the TIB
2621 ** to the dictionary. Backpatch the count byte and align the dictionary.
2623 ** stringlit: Fetch the count from the dictionary, then push the address
2624 ** and count on the stack. Finally, update ip to point to the first
2625 ** aligned address after the string text.
2626 **************************************************************************/
2628 static void stringLit(FICL_VM
*pVM
)
2634 vmCheckStack(pVM
, 0, 2);
2637 sp
= (FICL_STRING
*)(pVM
->ip
);
2644 pVM
->ip
= (IPTYPE
)(void *)cp
;
2647 static void dotQuoteCoIm(FICL_VM
*pVM
)
2649 FICL_DICT
*dp
= vmGetDict(pVM
);
2650 FICL_WORD
*pType
= ficlLookup(pVM
->pSys
, "type");
2652 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2653 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2655 dictAppendCell(dp
, LVALUEtoCELL(pType
));
2660 static void dotParen(FICL_VM
*pVM
)
2662 char *pSrc
= vmGetInBuf(pVM
);
2663 char *pEnd
= vmGetInBufEnd(pVM
);
2664 char *pDest
= pVM
->pad
;
2668 ** Note: the standard does not want leading spaces skipped (apparently)
2670 for (ch
= *pSrc
; (pEnd
!= pSrc
) && (ch
!= ')'); ch
= *++pSrc
)
2674 if ((pEnd
!= pSrc
) && (ch
== ')'))
2677 vmTextOut(pVM
, pVM
->pad
, 0);
2678 vmUpdateTib(pVM
, pSrc
);
2684 /**************************************************************************
2687 ** Interpretation: Interpretation semantics for this word are undefined.
2688 ** Compilation: ( c-addr1 u -- )
2689 ** Append the run-time semantics given below to the current definition.
2690 ** Run-time: ( -- c-addr2 u )
2691 ** Return c-addr2 u describing a string consisting of the characters
2692 ** specified by c-addr1 u during compilation. A program shall not alter
2693 ** the returned string.
2694 **************************************************************************/
2695 static void sLiteralCoIm(FICL_VM
*pVM
)
2702 vmCheckStack(pVM
, 2, 0);
2705 dp
= vmGetDict(pVM
);
2709 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2710 cpDest
= (char *) dp
->here
;
2711 *cpDest
++ = (char) u
;
2719 dp
->here
= PTRtoCELL
alignPtr(cpDest
);
2724 /**************************************************************************
2726 ** Return the address of the VM's state member (must be sized the
2727 ** same as a CELL for this reason)
2728 **************************************************************************/
2729 static void state(FICL_VM
*pVM
)
2732 vmCheckStack(pVM
, 0, 1);
2734 PUSHPTR(&pVM
->state
);
2739 /**************************************************************************
2740 c r e a t e . . . d o e s >
2741 ** Make a new word in the dictionary with the run-time effect of
2742 ** a variable (push my address), but with extra space allotted
2743 ** for use by does> .
2744 **************************************************************************/
2746 static void createParen(FICL_VM
*pVM
)
2751 vmCheckStack(pVM
, 0, 1);
2754 pCell
= pVM
->runningWord
->param
;
2760 static void create(FICL_VM
*pVM
)
2762 FICL_DICT
*dp
= vmGetDict(pVM
);
2763 STRINGINFO si
= vmGetWord(pVM
);
2765 dictCheckThreshold(dp
);
2767 dictAppendWord2(dp
, si
, createParen
, FW_DEFAULT
);
2768 dictAllotCells(dp
, 1);
2773 static void doDoes(FICL_VM
*pVM
)
2778 vmCheckStack(pVM
, 0, 1);
2781 pCell
= pVM
->runningWord
->param
;
2782 tempIP
= (IPTYPE
)((*pCell
).p
);
2784 vmPushIP(pVM
, tempIP
);
2789 static void doesParen(FICL_VM
*pVM
)
2791 FICL_DICT
*dp
= vmGetDict(pVM
);
2792 dp
->smudge
->code
= doDoes
;
2793 dp
->smudge
->param
[0] = LVALUEtoCELL(pVM
->ip
);
2799 static void doesCoIm(FICL_VM
*pVM
)
2801 FICL_DICT
*dp
= vmGetDict(pVM
);
2802 #if FICL_WANT_LOCALS
2803 assert(pVM
->pSys
->pUnLinkParen
);
2804 if (pVM
->pSys
->nLocals
> 0)
2806 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
2807 dictEmpty(pLoc
, pLoc
->pForthWords
->size
);
2808 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
2811 pVM
->pSys
->nLocals
= 0;
2815 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoesParen
));
2820 /**************************************************************************
2822 ** to-body CORE ( xt -- a-addr )
2823 ** a-addr is the data-field address corresponding to xt. An ambiguous
2824 ** condition exists if xt is not for a word defined via CREATE.
2825 **************************************************************************/
2826 static void toBody(FICL_VM
*pVM
)
2829 /*#$-GUY CHANGE: Added robustness.-$#*/
2831 vmCheckStack(pVM
, 1, 1);
2835 PUSHPTR(pFW
->param
+ 1);
2841 ** from-body ficl ( a-addr -- xt )
2842 ** Reverse effect of >body
2844 static void fromBody(FICL_VM
*pVM
)
2848 vmCheckStack(pVM
, 1, 1);
2851 ptr
= (char *)POPPTR() - sizeof (FICL_WORD
);
2858 ** >name ficl ( xt -- c-addr u )
2859 ** Push the address and length of a word's name given its address
2862 static void toName(FICL_VM
*pVM
)
2866 vmCheckStack(pVM
, 1, 2);
2871 PUSHUNS(pFW
->nName
);
2876 static void getLastWord(FICL_VM
*pVM
)
2878 FICL_DICT
*pDict
= vmGetDict(pVM
);
2879 FICL_WORD
*wp
= pDict
->smudge
;
2881 vmPush(pVM
, LVALUEtoCELL(wp
));
2886 /**************************************************************************
2887 l b r a c k e t e t c
2889 **************************************************************************/
2891 static void lbracketCoIm(FICL_VM
*pVM
)
2893 pVM
->state
= INTERPRET
;
2898 static void rbracket(FICL_VM
*pVM
)
2900 pVM
->state
= COMPILE
;
2905 /**************************************************************************
2906 p i c t u r e d n u m e r i c w o r d s
2908 ** less-number-sign CORE ( -- )
2909 ** Initialize the pictured numeric output conversion process.
2911 **************************************************************************/
2912 static void lessNumberSign(FICL_VM
*pVM
)
2914 FICL_STRING
*sp
= PTRtoSTRING pVM
->pad
;
2920 ** number-sign CORE ( ud1 -- ud2 )
2921 ** Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
2922 ** n. (n is the least-significant digit of ud1.) Convert n to external form
2923 ** and add the resulting character to the beginning of the pictured numeric
2924 ** output string. An ambiguous condition exists if # executes outside of a
2925 ** <# #> delimited number conversion.
2927 static void numberSign(FICL_VM
*pVM
)
2933 vmCheckStack(pVM
, 2, 2);
2936 sp
= PTRtoSTRING pVM
->pad
;
2937 u
= u64Pop(pVM
->pStack
);
2938 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2939 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2940 u64Push(pVM
->pStack
, u
);
2945 ** number-sign-greater CORE ( xd -- c-addr u )
2946 ** Drop xd. Make the pictured numeric output string available as a character
2947 ** string. c-addr and u specify the resulting character string. A program
2948 ** may replace characters within the string.
2950 static void numberSignGreater(FICL_VM
*pVM
)
2954 vmCheckStack(pVM
, 2, 2);
2957 sp
= PTRtoSTRING pVM
->pad
;
2958 sp
->text
[sp
->count
] = 0;
2967 ** number-sign-s CORE ( ud1 -- ud2 )
2968 ** Convert one digit of ud1 according to the rule for #. Continue conversion
2969 ** until the quotient is zero. ud2 is zero. An ambiguous condition exists if
2970 ** #S executes outside of a <# #> delimited number conversion.
2971 ** TO DO: presently does not use ud1 hi cell - use it!
2973 static void numberSignS(FICL_VM
*pVM
)
2979 vmCheckStack(pVM
, 2, 2);
2982 sp
= PTRtoSTRING pVM
->pad
;
2983 u
= u64Pop(pVM
->pStack
);
2987 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2988 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2990 while (u
.hi
|| u
.lo
);
2992 u64Push(pVM
->pStack
, u
);
2997 ** HOLD CORE ( char -- )
2998 ** Add char to the beginning of the pictured numeric output string. An ambiguous
2999 ** condition exists if HOLD executes outside of a <# #> delimited number conversion.
3001 static void hold(FICL_VM
*pVM
)
3006 vmCheckStack(pVM
, 1, 0);
3009 sp
= PTRtoSTRING pVM
->pad
;
3011 sp
->text
[sp
->count
++] = (char) i
;
3016 ** SIGN CORE ( n -- )
3017 ** If n is negative, add a minus sign to the beginning of the pictured
3018 ** numeric output string. An ambiguous condition exists if SIGN
3019 ** executes outside of a <# #> delimited number conversion.
3021 static void sign(FICL_VM
*pVM
)
3026 vmCheckStack(pVM
, 1, 0);
3029 sp
= PTRtoSTRING pVM
->pad
;
3032 sp
->text
[sp
->count
++] = '-';
3037 /**************************************************************************
3039 ** to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
3040 ** ud2 is the unsigned result of converting the characters within the
3041 ** string specified by c-addr1 u1 into digits, using the number in BASE,
3042 ** and adding each into ud1 after multiplying ud1 by the number in BASE.
3043 ** Conversion continues left-to-right until a character that is not
3044 ** convertible, including any + or -, is encountered or the string is
3045 ** entirely converted. c-addr2 is the location of the first unconverted
3046 ** character or the first character past the end of the string if the string
3047 ** was entirely converted. u2 is the number of unconverted characters in the
3048 ** string. An ambiguous condition exists if ud2 overflows during the
3050 **************************************************************************/
3051 static void toNumber(FICL_VM
*pVM
)
3056 FICL_UNS base
= pVM
->base
;
3061 vmCheckStack(pVM
,4,4);
3065 cp
= (char *)POPPTR();
3066 accum
= u64Pop(pVM
->pStack
);
3068 for (ch
= *cp
; count
> 0; ch
= *++cp
, count
--)
3076 digit
= tolower(ch
) - 'a' + 10;
3078 ** Note: following test also catches chars between 9 and a
3079 ** because 'digit' is unsigned!
3084 accum
= m64Mac(accum
, base
, digit
);
3087 u64Push(pVM
->pStack
, accum
);
3096 /**************************************************************************
3098 ** quit CORE ( -- ) ( R: i*x -- )
3099 ** Empty the return stack, store zero in SOURCE-ID if it is present, make
3100 ** the user input device the input source, and enter interpretation state.
3101 ** Do not display a message. Repeat the following:
3103 ** Accept a line from the input source into the input buffer, set >IN to
3104 ** zero, and interpret.
3105 ** Display the implementation-defined system prompt if in
3106 ** interpretation state, all processing has been completed, and no
3107 ** ambiguous condition exists.
3108 **************************************************************************/
3110 static void quit(FICL_VM
*pVM
)
3112 vmThrow(pVM
, VM_QUIT
);
3117 static void ficlAbort(FICL_VM
*pVM
)
3119 vmThrow(pVM
, VM_ABORT
);
3124 /**************************************************************************
3126 ** accept CORE ( c-addr +n1 -- +n2 )
3127 ** Receive a string of at most +n1 characters. An ambiguous condition
3128 ** exists if +n1 is zero or greater than 32,767. Display graphic characters
3129 ** as they are received. A program that depends on the presence or absence
3130 ** of non-graphic characters in the string has an environmental dependency.
3131 ** The editing functions, if any, that the system performs in order to
3132 ** construct the string are implementation-defined.
3134 ** (Although the standard text doesn't say so, I assume that the intent
3135 ** of 'accept' is to store the string at the address specified on
3137 ** Implementation: if there's more text in the TIB, use it. Otherwise
3138 ** throw out for more text. Copy characters up to the max count into the
3139 ** address given, and return the number of actual characters copied.
3141 ** Note (sobral) this may not be the behavior you'd expect if you're
3142 ** trying to get user input at load time!
3143 **************************************************************************/
3144 static void accept(FICL_VM
*pVM
)
3146 FICL_UNS count
, len
;
3151 vmCheckStack(pVM
,2,1);
3154 pBuf
= vmGetInBuf(pVM
);
3155 pEnd
= vmGetInBufEnd(pVM
);
3158 vmThrow(pVM
, VM_RESTART
);
3161 ** Now we have something in the text buffer - use it
3163 count
= stackPopINT(pVM
->pStack
);
3164 cp
= stackPopPtr(pVM
->pStack
);
3166 len
= (count
< len
) ? count
: len
;
3167 strncpy(cp
, vmGetInBuf(pVM
), len
);
3169 vmUpdateTib(pVM
, pBuf
);
3176 /**************************************************************************
3178 ** 6.1.0705 ALIGN CORE ( -- )
3179 ** If the data-space pointer is not aligned, reserve enough space to
3181 **************************************************************************/
3182 static void align(FICL_VM
*pVM
)
3184 FICL_DICT
*dp
= vmGetDict(pVM
);
3191 /**************************************************************************
3194 **************************************************************************/
3195 static void aligned(FICL_VM
*pVM
)
3199 vmCheckStack(pVM
,1,1);
3203 PUSHPTR(alignPtr(addr
));
3208 /**************************************************************************
3209 b e g i n & f r i e n d s
3210 ** Indefinite loop control structures
3213 ** : X ... BEGIN ... test UNTIL ;
3215 ** : X ... BEGIN ... test WHILE ... REPEAT ;
3216 **************************************************************************/
3217 static void beginCoIm(FICL_VM
*pVM
)
3219 FICL_DICT
*dp
= vmGetDict(pVM
);
3220 markBranch(dp
, pVM
, destTag
);
3224 static void untilCoIm(FICL_VM
*pVM
)
3226 FICL_DICT
*dp
= vmGetDict(pVM
);
3228 assert(pVM
->pSys
->pBranch0
);
3230 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
3231 resolveBackBranch(dp
, pVM
, destTag
);
3235 static void whileCoIm(FICL_VM
*pVM
)
3237 FICL_DICT
*dp
= vmGetDict(pVM
);
3239 assert(pVM
->pSys
->pBranch0
);
3241 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
3242 markBranch(dp
, pVM
, origTag
);
3244 dictAppendUNS(dp
, 1);
3248 static void repeatCoIm(FICL_VM
*pVM
)
3250 FICL_DICT
*dp
= vmGetDict(pVM
);
3252 assert(pVM
->pSys
->pBranchParen
);
3253 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3255 /* expect "begin" branch marker */
3256 resolveBackBranch(dp
, pVM
, destTag
);
3257 /* expect "while" branch marker */
3258 resolveForwardBranch(dp
, pVM
, origTag
);
3263 static void againCoIm(FICL_VM
*pVM
)
3265 FICL_DICT
*dp
= vmGetDict(pVM
);
3267 assert(pVM
->pSys
->pBranchParen
);
3268 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3270 /* expect "begin" branch marker */
3271 resolveBackBranch(dp
, pVM
, destTag
);
3276 /**************************************************************************
3277 c h a r & f r i e n d s
3278 ** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
3279 ** Skip leading space delimiters. Parse name delimited by a space.
3280 ** Put the value of its first character onto the stack.
3282 ** bracket-char CORE
3283 ** Interpretation: Interpretation semantics for this word are undefined.
3284 ** Compilation: ( "<spaces>name" -- )
3285 ** Skip leading space delimiters. Parse name delimited by a space.
3286 ** Append the run-time semantics given below to the current definition.
3287 ** Run-time: ( -- char )
3288 ** Place char, the value of the first character of name, on the stack.
3289 **************************************************************************/
3290 static void ficlChar(FICL_VM
*pVM
)
3294 vmCheckStack(pVM
,0,1);
3297 si
= vmGetWord(pVM
);
3298 PUSHUNS((FICL_UNS
)(si
.cp
[0]));
3302 static void charCoIm(FICL_VM
*pVM
)
3309 /**************************************************************************
3311 ** char-plus CORE ( c-addr1 -- c-addr2 )
3312 ** Add the size in address units of a character to c-addr1, giving c-addr2.
3313 **************************************************************************/
3314 static void charPlus(FICL_VM
*pVM
)
3318 vmCheckStack(pVM
,1,1);
3326 /**************************************************************************
3328 ** chars CORE ( n1 -- n2 )
3329 ** n2 is the size in address units of n1 characters.
3330 ** For most processors, this function can be a no-op. To guarantee
3331 ** portability, we'll multiply by sizeof (char).
3332 **************************************************************************/
3333 #if defined (_M_IX86)
3334 #pragma warning(disable: 4127)
3336 static void ficlChars(FICL_VM
*pVM
)
3338 if (sizeof (char) > 1)
3342 vmCheckStack(pVM
,1,1);
3345 PUSHINT(i
* sizeof (char));
3347 /* otherwise no-op! */
3350 #if defined (_M_IX86)
3351 #pragma warning(default: 4127)
3355 /**************************************************************************
3357 ** COUNT CORE ( c-addr1 -- c-addr2 u )
3358 ** Return the character string specification for the counted string stored
3359 ** at c-addr1. c-addr2 is the address of the first character after c-addr1.
3360 ** u is the contents of the character at c-addr1, which is the length in
3361 ** characters of the string at c-addr2.
3362 **************************************************************************/
3363 static void count(FICL_VM
*pVM
)
3367 vmCheckStack(pVM
,1,2);
3376 /**************************************************************************
3377 e n v i r o n m e n t ?
3378 ** environment-query CORE ( c-addr u -- false | i*x true )
3379 ** c-addr is the address of a character string and u is the string's
3380 ** character count. u may have a value in the range from zero to an
3381 ** implementation-defined maximum which shall not be less than 31. The
3382 ** character string should contain a keyword from 3.2.6 Environmental
3383 ** queries or the optional word sets to be checked for correspondence
3384 ** with an attribute of the present environment. If the system treats the
3385 ** attribute as unknown, the returned flag is false; otherwise, the flag
3386 ** is true and the i*x returned is of the type specified in the table for
3387 ** the attribute queried.
3388 **************************************************************************/
3389 static void environmentQ(FICL_VM
*pVM
)
3395 vmCheckStack(pVM
,2,1);
3398 envp
= pVM
->pSys
->envp
;
3399 si
.count
= (FICL_COUNT
)stackPopUNS(pVM
->pStack
);
3400 si
.cp
= stackPopPtr(pVM
->pStack
);
3402 pFW
= dictLookup(envp
, si
);
3406 vmExecute(pVM
, pFW
);
3411 PUSHINT(FICL_FALSE
);
3416 /**************************************************************************
3418 ** EVALUATE CORE ( i*x c-addr u -- j*x )
3419 ** Save the current input source specification. Store minus-one (-1) in
3420 ** SOURCE-ID if it is present. Make the string described by c-addr and u
3421 ** both the input source and input buffer, set >IN to zero, and interpret.
3422 ** When the parse area is empty, restore the prior input source
3423 ** specification. Other stack effects are due to the words EVALUATEd.
3425 **************************************************************************/
3426 static void evaluate(FICL_VM
*pVM
)
3433 vmCheckStack(pVM
,2,0);
3441 pVM
->sourceID
.i
= -1;
3442 result
= ficlExecC(pVM
, cp
, count
);
3444 if (result
!= VM_OUTOFTEXT
)
3445 vmThrow(pVM
, result
);
3451 /**************************************************************************
3452 s t r i n g q u o t e
3453 ** Interpreting: get string delimited by a quote from the input stream,
3454 ** copy to a scratch area, and put its count and address on the stack.
3455 ** Compiling: compile code to push the address and count of a string
3456 ** literal, compile the string from the input stream, and align the dict
3458 **************************************************************************/
3459 static void stringQuoteIm(FICL_VM
*pVM
)
3461 FICL_DICT
*dp
= vmGetDict(pVM
);
3463 if (pVM
->state
== INTERPRET
)
3465 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
3466 vmGetString(pVM
, sp
, '\"');
3470 else /* COMPILE state */
3472 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
3473 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
3481 /**************************************************************************
3483 ** Pop count and char address from stack and print the designated string.
3484 **************************************************************************/
3485 static void type(FICL_VM
*pVM
)
3487 FICL_UNS count
= stackPopUNS(pVM
->pStack
);
3488 char *cp
= stackPopPtr(pVM
->pStack
);
3489 char *pDest
= (char *)ficlMalloc(count
+ 1);
3492 ** Since we don't have an output primitive for a counted string
3493 ** (oops), make sure the string is null terminated. If not, copy
3494 ** and terminate it.
3497 vmThrowErr(pVM
, "Error: out of memory");
3499 strncpy(pDest
, cp
, count
);
3500 pDest
[count
] = '\0';
3502 vmTextOut(pVM
, pDest
, 0);
3508 /**************************************************************************
3510 ** word CORE ( char "<chars>ccc<char>" -- c-addr )
3511 ** Skip leading delimiters. Parse characters ccc delimited by char. An
3512 ** ambiguous condition exists if the length of the parsed string is greater
3513 ** than the implementation-defined length of a counted string.
3515 ** c-addr is the address of a transient region containing the parsed word
3516 ** as a counted string. If the parse area was empty or contained no
3517 ** characters other than the delimiter, the resulting string has a zero
3518 ** length. A space, not included in the length, follows the string. A
3519 ** program may replace characters within the string.
3520 ** NOTE! Ficl also NULL-terminates the dest string.
3521 **************************************************************************/
3522 static void ficlWord(FICL_VM
*pVM
)
3528 vmCheckStack(pVM
,1,1);
3531 sp
= (FICL_STRING
*)pVM
->pad
;
3532 delim
= (char)POPINT();
3533 si
= vmParseStringEx(pVM
, delim
, 1);
3535 if (SI_COUNT(si
) > nPAD
-1)
3536 SI_SETLEN(si
, nPAD
-1);
3538 sp
->count
= (FICL_COUNT
)SI_COUNT(si
);
3539 strncpy(sp
->text
, SI_PTR(si
), SI_COUNT(si
));
3540 /*#$-GUY CHANGE: I added this.-$#*/
3541 sp
->text
[sp
->count
] = 0;
3542 strcat(sp
->text
, " ");
3549 /**************************************************************************
3551 ** ficl PARSE-WORD ( <spaces>name -- c-addr u )
3552 ** Skip leading spaces and parse name delimited by a space. c-addr is the
3553 ** address within the input buffer and u is the length of the selected
3554 ** string. If the parse area is empty, the resulting string has a zero length.
3555 **************************************************************************/
3556 static void parseNoCopy(FICL_VM
*pVM
)
3560 vmCheckStack(pVM
,0,2);
3563 si
= vmGetWord0(pVM
);
3564 PUSHPTR(SI_PTR(si
));
3565 PUSHUNS(SI_COUNT(si
));
3570 /**************************************************************************
3572 ** CORE EXT ( char "ccc<char>" -- c-addr u )
3573 ** Parse ccc delimited by the delimiter char.
3574 ** c-addr is the address (within the input buffer) and u is the length of
3575 ** the parsed string. If the parse area was empty, the resulting string has
3577 ** NOTE! PARSE differs from WORD: it does not skip leading delimiters.
3578 **************************************************************************/
3579 static void parse(FICL_VM
*pVM
)
3585 vmCheckStack(pVM
,1,2);
3588 delim
= (char)POPINT();
3590 si
= vmParseStringEx(pVM
, delim
, 0);
3591 PUSHPTR(SI_PTR(si
));
3592 PUSHUNS(SI_COUNT(si
));
3597 /**************************************************************************
3599 ** CORE ( c-addr u char -- )
3600 ** If u is greater than zero, store char in each of u consecutive
3601 ** characters of memory beginning at c-addr.
3602 **************************************************************************/
3603 static void fill(FICL_VM
*pVM
)
3609 vmCheckStack(pVM
,3,0);
3611 ch
= (char)POPINT();
3613 cp
= (char *)POPPTR();
3624 /**************************************************************************
3626 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3627 ** Find the definition named in the counted string at c-addr. If the
3628 ** definition is not found, return c-addr and zero. If the definition is
3629 ** found, return its execution token xt. If the definition is immediate,
3630 ** also return one (1), otherwise also return minus-one (-1). For a given
3631 ** string, the values returned by FIND while compiling may differ from
3632 ** those returned while not compiling.
3633 **************************************************************************/
3634 static void do_find(FICL_VM
*pVM
, STRINGINFO si
, void *returnForFailure
)
3638 pFW
= dictLookup(vmGetDict(pVM
), si
);
3642 PUSHINT((wordIsImmediate(pFW
) ? 1 : -1));
3646 PUSHPTR(returnForFailure
);
3654 /**************************************************************************
3656 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3657 ** Find the definition named in the counted string at c-addr. If the
3658 ** definition is not found, return c-addr and zero. If the definition is
3659 ** found, return its execution token xt. If the definition is immediate,
3660 ** also return one (1), otherwise also return minus-one (-1). For a given
3661 ** string, the values returned by FIND while compiling may differ from
3662 ** those returned while not compiling.
3663 **************************************************************************/
3664 static void cFind(FICL_VM
*pVM
)
3670 vmCheckStack(pVM
,1,2);
3674 do_find(pVM
, si
, sp
);
3679 /**************************************************************************
3681 ** FICL ( c-addr u -- 0 0 | xt 1 | xt -1 )
3682 ** Like FIND, but takes "c-addr u" for the string.
3683 **************************************************************************/
3684 static void sFind(FICL_VM
*pVM
)
3689 vmCheckStack(pVM
,2,2);
3692 si
.count
= stackPopINT(pVM
->pStack
);
3693 si
.cp
= stackPopPtr(pVM
->pStack
);
3695 do_find(pVM
, si
, NULL
);
3700 /**************************************************************************
3702 ** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
3703 ** Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
3704 ** Input and output stack arguments are signed. An ambiguous condition
3705 ** exists if n1 is zero or if the quotient lies outside the range of a
3706 ** single-cell signed integer.
3707 **************************************************************************/
3708 static void fmSlashMod(FICL_VM
*pVM
)
3714 vmCheckStack(pVM
,3,2);
3718 d1
= i64Pop(pVM
->pStack
);
3719 qr
= m64FlooredDivI(d1
, n1
);
3726 /**************************************************************************
3728 ** s-m-slash-rem CORE ( d1 n1 -- n2 n3 )
3729 ** Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
3730 ** Input and output stack arguments are signed. An ambiguous condition
3731 ** exists if n1 is zero or if the quotient lies outside the range of a
3732 ** single-cell signed integer.
3733 **************************************************************************/
3734 static void smSlashRem(FICL_VM
*pVM
)
3740 vmCheckStack(pVM
,3,2);
3744 d1
= i64Pop(pVM
->pStack
);
3745 qr
= m64SymmetricDivI(d1
, n1
);
3752 static void ficlMod(FICL_VM
*pVM
)
3758 vmCheckStack(pVM
,2,1);
3764 qr
= m64SymmetricDivI(d1
, n1
);
3770 /**************************************************************************
3772 ** u-m-slash-mod CORE ( ud u1 -- u2 u3 )
3773 ** Divide ud by u1, giving the quotient u3 and the remainder u2.
3774 ** All values and arithmetic are unsigned. An ambiguous condition
3775 ** exists if u1 is zero or if the quotient lies outside the range of a
3776 ** single-cell unsigned integer.
3777 *************************************************************************/
3778 static void umSlashMod(FICL_VM
*pVM
)
3784 u1
= stackPopUNS(pVM
->pStack
);
3785 ud
= u64Pop(pVM
->pStack
);
3786 qr
= ficlLongDiv(ud
, u1
);
3793 /**************************************************************************
3795 ** l-shift CORE ( x1 u -- x2 )
3796 ** Perform a logical left shift of u bit-places on x1, giving x2.
3797 ** Put zeroes into the least significant bits vacated by the shift.
3798 ** An ambiguous condition exists if u is greater than or equal to the
3799 ** number of bits in a cell.
3801 ** r-shift CORE ( x1 u -- x2 )
3802 ** Perform a logical right shift of u bit-places on x1, giving x2.
3803 ** Put zeroes into the most significant bits vacated by the shift. An
3804 ** ambiguous condition exists if u is greater than or equal to the
3805 ** number of bits in a cell.
3806 **************************************************************************/
3807 static void lshift(FICL_VM
*pVM
)
3812 vmCheckStack(pVM
,2,1);
3817 PUSHUNS(x1
<< nBits
);
3822 static void rshift(FICL_VM
*pVM
)
3827 vmCheckStack(pVM
,2,1);
3833 PUSHUNS(x1
>> nBits
);
3838 /**************************************************************************
3840 ** m-star CORE ( n1 n2 -- d )
3841 ** d is the signed product of n1 times n2.
3842 **************************************************************************/
3843 static void mStar(FICL_VM
*pVM
)
3849 vmCheckStack(pVM
,2,2);
3855 d
= m64MulI(n1
, n2
);
3856 i64Push(pVM
->pStack
, d
);
3861 static void umStar(FICL_VM
*pVM
)
3867 vmCheckStack(pVM
,2,2);
3873 ud
= ficlLongMul(u1
, u2
);
3874 u64Push(pVM
->pStack
, ud
);
3879 /**************************************************************************
3882 **************************************************************************/
3883 static void ficlMax(FICL_VM
*pVM
)
3888 vmCheckStack(pVM
,2,1);
3894 PUSHINT((n1
> n2
) ? n1
: n2
);
3898 static void ficlMin(FICL_VM
*pVM
)
3903 vmCheckStack(pVM
,2,1);
3909 PUSHINT((n1
< n2
) ? n1
: n2
);
3914 /**************************************************************************
3916 ** CORE ( addr1 addr2 u -- )
3917 ** If u is greater than zero, copy the contents of u consecutive address
3918 ** units at addr1 to the u consecutive address units at addr2. After MOVE
3919 ** completes, the u consecutive address units at addr2 contain exactly
3920 ** what the u consecutive address units at addr1 contained before the move.
3921 ** NOTE! This implementation assumes that a char is the same size as
3923 **************************************************************************/
3924 static void move(FICL_VM
*pVM
)
3930 vmCheckStack(pVM
,3,0);
3940 ** Do the copy carefully, so as to be
3941 ** correct even if the two ranges overlap
3946 *addr2
++ = *addr1
++;
3953 *addr2
-- = *addr1
--;
3960 /**************************************************************************
3963 **************************************************************************/
3964 static void recurseCoIm(FICL_VM
*pVM
)
3966 FICL_DICT
*pDict
= vmGetDict(pVM
);
3969 dictAppendCell(pDict
, LVALUEtoCELL(pDict
->smudge
));
3974 /**************************************************************************
3976 ** s-to-d CORE ( n -- d )
3977 ** Convert the number n to the double-cell number d with the same
3979 **************************************************************************/
3980 static void sToD(FICL_VM
*pVM
)
3984 vmCheckStack(pVM
,1,2);
3989 /* sign extend to 64 bits.. */
3991 PUSHINT((s
< 0) ? -1 : 0);
3996 /**************************************************************************
3998 ** CORE ( -- c-addr u )
3999 ** c-addr is the address of, and u is the number of characters in, the
4001 **************************************************************************/
4002 static void source(FICL_VM
*pVM
)
4005 vmCheckStack(pVM
,0,2);
4007 PUSHPTR(pVM
->tib
.cp
);
4008 PUSHINT(vmGetInBufLen(pVM
));
4013 /**************************************************************************
4016 **************************************************************************/
4017 static void ficlVersion(FICL_VM
*pVM
)
4019 vmTextOut(pVM
, "ficl Version " FICL_VER
, 1);
4024 /**************************************************************************
4027 **************************************************************************/
4028 static void toIn(FICL_VM
*pVM
)
4031 vmCheckStack(pVM
,0,1);
4033 PUSHPTR(&pVM
->tib
.index
);
4038 /**************************************************************************
4039 c o l o n N o N a m e
4040 ** CORE EXT ( C: -- colon-sys ) ( S: -- xt )
4041 ** Create an unnamed colon definition and push its address.
4042 ** Change state to compile.
4043 **************************************************************************/
4044 static void colonNoName(FICL_VM
*pVM
)
4046 FICL_DICT
*dp
= vmGetDict(pVM
);
4051 SI_SETPTR(si
, NULL
);
4053 pVM
->state
= COMPILE
;
4054 pFW
= dictAppendWord2(dp
, si
, colonParen
, FW_DEFAULT
| FW_SMUDGE
);
4056 markControlTag(pVM
, colonTag
);
4061 /**************************************************************************
4062 u s e r V a r i a b l e
4063 ** user ( u -- ) "<spaces>name"
4064 ** Get a name from the input stream and create a user variable
4065 ** with the name and the index supplied. The run-time effect
4066 ** of a user variable is to push the address of the indexed cell
4067 ** in the running vm's user array.
4069 ** User variables are vm local cells. Each vm has an array of
4070 ** FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
4071 ** Ficl's user facility is implemented with two primitives,
4072 ** "user" and "(user)", a variable ("nUser") (in softcore.c) that
4073 ** holds the index of the next free user cell, and a redefinition
4074 ** (also in softcore) of "user" that defines a user word and increments
4076 **************************************************************************/
4078 static void userParen(FICL_VM
*pVM
)
4080 FICL_INT i
= pVM
->runningWord
->param
[0].i
;
4081 PUSHPTR(&pVM
->user
[i
]);
4086 static void userVariable(FICL_VM
*pVM
)
4088 FICL_DICT
*dp
= vmGetDict(pVM
);
4089 STRINGINFO si
= vmGetWord(pVM
);
4092 c
= stackPop(pVM
->pStack
);
4093 if (c
.i
>= FICL_USER_CELLS
)
4095 vmThrowErr(pVM
, "Error - out of user space");
4098 dictAppendWord2(dp
, si
, userParen
, FW_DEFAULT
);
4099 dictAppendCell(dp
, c
);
4105 /**************************************************************************
4108 ** Interpretation: ( x "<spaces>name" -- )
4109 ** Skip leading spaces and parse name delimited by a space. Store x in
4110 ** name. An ambiguous condition exists if name was not defined by VALUE.
4111 ** NOTE: In ficl, VALUE is an alias of CONSTANT
4112 **************************************************************************/
4113 static void toValue(FICL_VM
*pVM
)
4115 STRINGINFO si
= vmGetWord(pVM
);
4116 FICL_DICT
*dp
= vmGetDict(pVM
);
4119 #if FICL_WANT_LOCALS
4120 if ((pVM
->pSys
->nLocals
> 0) && (pVM
->state
== COMPILE
))
4122 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4123 pFW
= dictLookup(pLoc
, si
);
4124 if (pFW
&& (pFW
->code
== doLocalIm
))
4126 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
4127 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
4130 else if (pFW
&& pFW
->code
== do2LocalIm
)
4132 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
4133 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
4139 assert(pVM
->pSys
->pStore
);
4141 pFW
= dictLookup(dp
, si
);
4144 int i
= SI_COUNT(si
);
4145 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
4148 if (pVM
->state
== INTERPRET
)
4149 pFW
->param
[0] = stackPop(pVM
->pStack
);
4150 else /* compile code to store to word's param */
4152 PUSHPTR(&pFW
->param
[0]);
4154 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStore
));
4160 #if FICL_WANT_LOCALS
4161 /**************************************************************************
4164 ** Link a frame on the return stack, reserving nCells of space for
4165 ** locals - the value of nCells is the next cell in the instruction
4167 **************************************************************************/
4168 static void linkParen(FICL_VM
*pVM
)
4170 FICL_INT nLink
= *(FICL_INT
*)(pVM
->ip
);
4171 vmBranchRelative(pVM
, 1);
4172 stackLink(pVM
->rStack
, nLink
);
4177 static void unlinkParen(FICL_VM
*pVM
)
4179 stackUnlink(pVM
->rStack
);
4184 /**************************************************************************
4186 ** Immediate - cfa of a local while compiling - when executed, compiles
4187 ** code to fetch the value of a local given the local's index in the
4189 **************************************************************************/
4190 static void getLocalParen(FICL_VM
*pVM
)
4192 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4193 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4198 static void toLocalParen(FICL_VM
*pVM
)
4200 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4201 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
4206 static void getLocal0(FICL_VM
*pVM
)
4208 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[0]);
4213 static void toLocal0(FICL_VM
*pVM
)
4215 pVM
->rStack
->pFrame
[0] = stackPop(pVM
->pStack
);
4220 static void getLocal1(FICL_VM
*pVM
)
4222 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[1]);
4227 static void toLocal1(FICL_VM
*pVM
)
4229 pVM
->rStack
->pFrame
[1] = stackPop(pVM
->pStack
);
4235 ** Each local is recorded in a private locals dictionary as a
4236 ** word that does doLocalIm at runtime. DoLocalIm compiles code
4237 ** into the client definition to fetch the value of the
4238 ** corresponding local variable from the return stack.
4239 ** The private dictionary gets initialized at the end of each block
4240 ** that uses locals (in ; and does> for example).
4242 static void doLocalIm(FICL_VM
*pVM
)
4244 FICL_DICT
*pDict
= vmGetDict(pVM
);
4245 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4247 if (pVM
->state
== INTERPRET
)
4249 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4256 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal0
));
4258 else if (nLocal
== 1)
4260 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal1
));
4264 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocalParen
));
4265 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4272 /**************************************************************************
4274 ** paren-local-paren LOCAL
4275 ** Interpretation: Interpretation semantics for this word are undefined.
4276 ** Execution: ( c-addr u -- )
4277 ** When executed during compilation, (LOCAL) passes a message to the
4278 ** system that has one of two meanings. If u is non-zero,
4279 ** the message identifies a new local whose definition name is given by
4280 ** the string of characters identified by c-addr u. If u is zero,
4281 ** the message is last local and c-addr has no significance.
4283 ** The result of executing (LOCAL) during compilation of a definition is
4284 ** to create a set of named local identifiers, each of which is
4285 ** a definition name, that only have execution semantics within the scope
4286 ** of that definition's source.
4288 ** local Execution: ( -- x )
4290 ** Push the local's value, x, onto the stack. The local's value is
4291 ** initialized as described in 13.3.3 Processing locals and may be
4292 ** changed by preceding the local's name with TO. An ambiguous condition
4293 ** exists when local is executed while in interpretation state.
4294 **************************************************************************/
4295 static void localParen(FICL_VM
*pVM
)
4300 vmCheckStack(pVM
,2,0);
4303 pDict
= vmGetDict(pVM
);
4304 SI_SETLEN(si
, POPUNS());
4305 SI_SETPTR(si
, (char *)POPPTR());
4307 if (SI_COUNT(si
) > 0)
4308 { /* add a local to the **locals** dict and update nLocals */
4309 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4310 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4312 vmThrowErr(pVM
, "Error: out of local space");
4315 dictAppendWord2(pLoc
, si
, doLocalIm
, FW_COMPIMMED
);
4316 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4318 if (pVM
->pSys
->nLocals
== 0)
4319 { /* compile code to create a local stack frame */
4320 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4321 /* save location in dictionary for #locals */
4322 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4323 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4324 /* compile code to initialize first local */
4325 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal0
));
4327 else if (pVM
->pSys
->nLocals
== 1)
4329 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal1
));
4333 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
4334 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4337 (pVM
->pSys
->nLocals
)++;
4339 else if (pVM
->pSys
->nLocals
> 0)
4340 { /* write nLocals to (link) param area in dictionary */
4341 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4348 static void get2LocalParen(FICL_VM
*pVM
)
4350 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4351 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4352 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4357 static void do2LocalIm(FICL_VM
*pVM
)
4359 FICL_DICT
*pDict
= vmGetDict(pVM
);
4360 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4362 if (pVM
->state
== INTERPRET
)
4364 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4365 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4369 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGet2LocalParen
));
4370 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4376 static void to2LocalParen(FICL_VM
*pVM
)
4378 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4379 pVM
->rStack
->pFrame
[nLocal
+1] = stackPop(pVM
->pStack
);
4380 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
4385 static void twoLocalParen(FICL_VM
*pVM
)
4387 FICL_DICT
*pDict
= vmGetDict(pVM
);
4389 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
4390 SI_SETPTR(si
, (char *)stackPopPtr(pVM
->pStack
));
4392 if (SI_COUNT(si
) > 0)
4393 { /* add a local to the **locals** dict and update nLocals */
4394 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4395 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4397 vmThrowErr(pVM
, "Error: out of local space");
4400 dictAppendWord2(pLoc
, si
, do2LocalIm
, FW_COMPIMMED
);
4401 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4403 if (pVM
->pSys
->nLocals
== 0)
4404 { /* compile code to create a local stack frame */
4405 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4406 /* save location in dictionary for #locals */
4407 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4408 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4411 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
4412 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4414 pVM
->pSys
->nLocals
+= 2;
4416 else if (pVM
->pSys
->nLocals
> 0)
4417 { /* write nLocals to (link) param area in dictionary */
4418 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4426 /**************************************************************************
4428 ** STRING ( c-addr1 u1 c-addr2 u2 -- n )
4429 ** Compare the string specified by c-addr1 u1 to the string specified by
4430 ** c-addr2 u2. The strings are compared, beginning at the given addresses,
4431 ** character by character, up to the length of the shorter string or until a
4432 ** difference is found. If the two strings are identical, n is zero. If the two
4433 ** strings are identical up to the length of the shorter string, n is minus-one
4434 ** (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not
4435 ** identical up to the length of the shorter string, n is minus-one (-1) if the
4436 ** first non-matching character in the string specified by c-addr1 u1 has a
4437 ** lesser numeric value than the corresponding character in the string specified
4438 ** by c-addr2 u2 and one (1) otherwise.
4439 **************************************************************************/
4440 static void compareInternal(FICL_VM
*pVM
, int caseInsensitive
)
4443 FICL_UNS u1
, u2
, uMin
;
4446 vmCheckStack(pVM
, 4, 1);
4447 u2
= stackPopUNS(pVM
->pStack
);
4448 cp2
= (char *)stackPopPtr(pVM
->pStack
);
4449 u1
= stackPopUNS(pVM
->pStack
);
4450 cp1
= (char *)stackPopPtr(pVM
->pStack
);
4452 uMin
= (u1
< u2
)? u1
: u2
;
4453 for ( ; (uMin
> 0) && (n
== 0); uMin
--)
4457 if (caseInsensitive
)
4459 c1
= (char)tolower(c1
);
4460 c2
= (char)tolower(c2
);
4478 static void compareString(FICL_VM
*pVM
)
4480 compareInternal(pVM
, FALSE
);
4484 static void compareStringInsensitive(FICL_VM
*pVM
)
4486 compareInternal(pVM
, TRUE
);
4490 /**************************************************************************
4492 ** CORE EXT ( -- c-addr )
4493 ** c-addr is the address of a transient region that can be used to hold
4494 ** data for intermediate processing.
4495 **************************************************************************/
4496 static void pad(FICL_VM
*pVM
)
4498 stackPushPtr(pVM
->pStack
, pVM
->pad
);
4502 /**************************************************************************
4504 ** CORE EXT, FILE ( -- 0 | -1 | fileid )
4505 ** Identifies the input source as follows:
4507 ** SOURCE-ID Input source
4508 ** --------- ------------
4509 ** fileid Text file fileid
4510 ** -1 String (via EVALUATE)
4511 ** 0 User input device
4512 **************************************************************************/
4513 static void sourceid(FICL_VM
*pVM
)
4515 PUSHINT(pVM
->sourceID
.i
);
4520 /**************************************************************************
4522 ** CORE EXT ( -- flag )
4523 ** Attempt to fill the input buffer from the input source, returning a true
4524 ** flag if successful.
4525 ** When the input source is the user input device, attempt to receive input
4526 ** into the terminal input buffer. If successful, make the result the input
4527 ** buffer, set >IN to zero, and return true. Receipt of a line containing no
4528 ** characters is considered successful. If there is no input available from
4529 ** the current input source, return false.
4530 ** When the input source is a string from EVALUATE, return false and
4531 ** perform no other action.
4532 **************************************************************************/
4533 static void refill(FICL_VM
*pVM
)
4535 FICL_INT ret
= (pVM
->sourceID
.i
== -1) ? FICL_FALSE
: FICL_TRUE
;
4536 if (ret
&& (pVM
->fRestart
== 0))
4537 vmThrow(pVM
, VM_RESTART
);
4544 /**************************************************************************
4545 freebsd exception handling words
4546 ** Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
4547 ** the word in ToS. If an exception happens, restore the state to what
4548 ** it was before, and pushes the exception value on the stack. If not,
4551 ** Notice that Catch implements an inner interpreter. This is ugly,
4552 ** but given how ficl works, it cannot be helped. The problem is that
4553 ** colon definitions will be executed *after* the function returns,
4554 ** while "code" definitions will be executed immediately. I considered
4555 ** other solutions to this problem, but all of them shared the same
4556 ** basic problem (with added disadvantages): if ficl ever changes it's
4557 ** inner thread modus operandi, one would have to fix this word.
4559 ** More comments can be found throughout catch's code.
4561 ** Daniel C. Sobral Jan 09/1999
4562 ** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
4563 **************************************************************************/
4565 static void ficlCatch(FICL_VM
*pVM
)
4575 assert(pVM
->pSys
->pExitInner
);
4580 ** We need this *before* we save the stack pointer, or
4581 ** we'll have to pop one element out of the stack after
4582 ** an exception. I prefer to get done with it up front. :-)
4585 vmCheckStack(pVM
, 1, 0);
4587 pFW
= stackPopPtr(pVM
->pStack
);
4590 ** Save vm's state -- a catch will not back out environmental
4593 ** We are *not* saving dictionary state, since it is
4594 ** global instead of per vm, and we are not saving
4595 ** stack contents, since we are not required to (and,
4596 ** thus, it would be useless). We save pVM, and pVM
4597 ** "stacks" (a structure containing general information
4598 ** about it, including the current stack pointer).
4600 memcpy((void*)&VM
, (void*)pVM
, sizeof(FICL_VM
));
4601 memcpy((void*)&pStack
, (void*)pVM
->pStack
, sizeof(FICL_STACK
));
4602 memcpy((void*)&rStack
, (void*)pVM
->rStack
, sizeof(FICL_STACK
));
4605 ** Give pVM a jmp_buf
4607 pVM
->pState
= &vmState
;
4612 except
= setjmp(vmState
);
4617 ** Setup condition - push poison pill so that the VM throws
4618 ** VM_INNEREXIT if the XT terminates normally, then execute
4622 vmPushIP(pVM
, &(pVM
->pSys
->pExitInner
)); /* Open mouth, insert emetic */
4623 vmExecute(pVM
, pFW
);
4628 ** Normal exit from XT - lose the poison pill,
4629 ** restore old setjmp vector and push a zero.
4632 vmPopIP(pVM
); /* Gack - hurl poison pill */
4633 pVM
->pState
= VM
.pState
; /* Restore just the setjmp vector */
4634 PUSHINT(0); /* Push 0 -- everything is ok */
4638 ** Some other exception got thrown - restore pre-existing VM state
4639 ** and push the exception code
4642 /* Restore vm's state */
4643 memcpy((void*)pVM
, (void*)&VM
, sizeof(FICL_VM
));
4644 memcpy((void*)pVM
->pStack
, (void*)&pStack
, sizeof(FICL_STACK
));
4645 memcpy((void*)pVM
->rStack
, (void*)&rStack
, sizeof(FICL_STACK
));
4647 PUSHINT(except
);/* Push error */
4652 /**************************************************************************
4655 ** Throw -- From ANS Forth standard.
4657 ** Throw takes the ToS and, if that's different from zero,
4658 ** returns to the last executed catch context. Further throws will
4659 ** unstack previously executed "catches", in LIFO mode.
4661 ** Daniel C. Sobral Jan 09/1999
4662 **************************************************************************/
4663 static void ficlThrow(FICL_VM
*pVM
)
4667 except
= stackPopINT(pVM
->pStack
);
4670 vmThrow(pVM
, except
);
4674 /**************************************************************************
4677 **************************************************************************/
4678 static void ansAllocate(FICL_VM
*pVM
)
4683 size
= stackPopINT(pVM
->pStack
);
4684 p
= ficlMalloc(size
);
4693 /**************************************************************************
4696 **************************************************************************/
4697 static void ansFree(FICL_VM
*pVM
)
4701 p
= stackPopPtr(pVM
->pStack
);
4707 /**************************************************************************
4710 **************************************************************************/
4711 static void ansResize(FICL_VM
*pVM
)
4716 size
= stackPopINT(pVM
->pStack
);
4717 old
= stackPopPtr(pVM
->pStack
);
4718 new = ficlRealloc(old
, size
);
4732 /**************************************************************************
4733 ** e x i t - i n n e r
4734 ** Signals execXT that an inner loop has completed
4735 **************************************************************************/
4736 static void ficlExitInner(FICL_VM
*pVM
)
4738 vmThrow(pVM
, VM_INNEREXIT
);
4742 /**************************************************************************
4744 ** DOUBLE ( d1 -- d2 )
4745 ** d2 is the negation of d1.
4746 **************************************************************************/
4747 static void dnegate(FICL_VM
*pVM
)
4749 DPINT i
= i64Pop(pVM
->pStack
);
4751 i64Push(pVM
->pStack
, i
);
4758 /**************************************************************************
4761 **************************************************************************/
4762 static void funcname(FICL_VM
*pVM
)
4770 /**************************************************************************
4771 f i c l W o r d C l a s s i f y
4772 ** This public function helps to classify word types for SEE
4773 ** and the deugger in tools.c. Given a pointer to a word, it returns
4775 **************************************************************************/
4776 WORDKIND
ficlWordClassify(FICL_WORD
*pFW
)
4784 static CODEtoKIND codeMap
[] =
4786 {BRANCH
, branchParen
},
4787 {COLON
, colonParen
},
4788 {CONSTANT
, constantParen
},
4789 {CREATE
, createParen
},
4793 {LITERAL
, literalParen
},
4796 {PLOOP
, plusLoopParen
},
4798 {CSTRINGLIT
, cstringLit
},
4799 {STRINGLIT
, stringLit
},
4803 {VARIABLE
, variableParen
},
4806 #define nMAP (sizeof(codeMap) / sizeof(CODEtoKIND))
4808 FICL_CODE code
= pFW
->code
;
4811 for (i
=0; i
< nMAP
; i
++)
4813 if (codeMap
[i
].code
== code
)
4814 return codeMap
[i
].kind
;
4822 /**************************************************************************
4825 **************************************************************************/
4826 static void ficlRandom(FICL_VM
*pVM
)
4832 /**************************************************************************
4833 ** s e e d - r a n d o m
4835 **************************************************************************/
4836 static void ficlSeedRandom(FICL_VM
*pVM
)
4843 /**************************************************************************
4844 f i c l C o m p i l e C o r e
4845 ** Builds the primitive wordset and the environment-query namespace.
4846 **************************************************************************/
4848 void ficlCompileCore(FICL_SYSTEM
*pSys
)
4850 FICL_DICT
*dp
= pSys
->dp
;
4856 ** see softcore.c for definitions of: abs bl space spaces abort"
4859 dictAppendWord(dp
, "!", store
, FW_DEFAULT
);
4860 dictAppendWord(dp
, "#", numberSign
, FW_DEFAULT
);
4861 dictAppendWord(dp
, "#>", numberSignGreater
,FW_DEFAULT
);
4862 dictAppendWord(dp
, "#s", numberSignS
, FW_DEFAULT
);
4863 dictAppendWord(dp
, "\'", ficlTick
, FW_DEFAULT
);
4864 dictAppendWord(dp
, "(", commentHang
, FW_IMMEDIATE
);
4865 dictAppendWord(dp
, "*", mul
, FW_DEFAULT
);
4866 dictAppendWord(dp
, "*/", mulDiv
, FW_DEFAULT
);
4867 dictAppendWord(dp
, "*/mod", mulDivRem
, FW_DEFAULT
);
4868 dictAppendWord(dp
, "+", add
, FW_DEFAULT
);
4869 dictAppendWord(dp
, "+!", plusStore
, FW_DEFAULT
);
4870 dictAppendWord(dp
, "+loop", plusLoopCoIm
, FW_COMPIMMED
);
4871 dictAppendWord(dp
, ",", comma
, FW_DEFAULT
);
4872 dictAppendWord(dp
, "-", sub
, FW_DEFAULT
);
4873 dictAppendWord(dp
, ".", displayCell
, FW_DEFAULT
);
4874 dictAppendWord(dp
, ".\"", dotQuoteCoIm
, FW_COMPIMMED
);
4875 dictAppendWord(dp
, "/", ficlDiv
, FW_DEFAULT
);
4876 dictAppendWord(dp
, "/mod", slashMod
, FW_DEFAULT
);
4877 dictAppendWord(dp
, "0<", zeroLess
, FW_DEFAULT
);
4878 dictAppendWord(dp
, "0=", zeroEquals
, FW_DEFAULT
);
4879 dictAppendWord(dp
, "1+", onePlus
, FW_DEFAULT
);
4880 dictAppendWord(dp
, "1-", oneMinus
, FW_DEFAULT
);
4881 dictAppendWord(dp
, "2!", twoStore
, FW_DEFAULT
);
4882 dictAppendWord(dp
, "2*", twoMul
, FW_DEFAULT
);
4883 dictAppendWord(dp
, "2/", twoDiv
, FW_DEFAULT
);
4884 dictAppendWord(dp
, "2@", twoFetch
, FW_DEFAULT
);
4885 dictAppendWord(dp
, "2drop", twoDrop
, FW_DEFAULT
);
4886 dictAppendWord(dp
, "2dup", twoDup
, FW_DEFAULT
);
4887 dictAppendWord(dp
, "2over", twoOver
, FW_DEFAULT
);
4888 dictAppendWord(dp
, "2swap", twoSwap
, FW_DEFAULT
);
4889 dictAppendWord(dp
, ":", colon
, FW_DEFAULT
);
4890 dictAppendWord(dp
, ";", semicolonCoIm
, FW_COMPIMMED
);
4891 dictAppendWord(dp
, "<", isLess
, FW_DEFAULT
);
4892 dictAppendWord(dp
, "<#", lessNumberSign
, FW_DEFAULT
);
4893 dictAppendWord(dp
, "=", isEqual
, FW_DEFAULT
);
4894 dictAppendWord(dp
, ">", isGreater
, FW_DEFAULT
);
4895 dictAppendWord(dp
, ">body", toBody
, FW_DEFAULT
);
4896 dictAppendWord(dp
, ">in", toIn
, FW_DEFAULT
);
4897 dictAppendWord(dp
, ">number", toNumber
, FW_DEFAULT
);
4898 dictAppendWord(dp
, ">r", toRStack
, FW_COMPILE
);
4899 dictAppendWord(dp
, "?dup", questionDup
, FW_DEFAULT
);
4900 dictAppendWord(dp
, "@", fetch
, FW_DEFAULT
);
4901 dictAppendWord(dp
, "abort", ficlAbort
, FW_DEFAULT
);
4902 dictAppendWord(dp
, "accept", accept
, FW_DEFAULT
);
4903 dictAppendWord(dp
, "align", align
, FW_DEFAULT
);
4904 dictAppendWord(dp
, "aligned", aligned
, FW_DEFAULT
);
4905 dictAppendWord(dp
, "allot", allot
, FW_DEFAULT
);
4906 dictAppendWord(dp
, "and", bitwiseAnd
, FW_DEFAULT
);
4907 dictAppendWord(dp
, "base", base
, FW_DEFAULT
);
4908 dictAppendWord(dp
, "begin", beginCoIm
, FW_COMPIMMED
);
4909 dictAppendWord(dp
, "c!", cStore
, FW_DEFAULT
);
4910 dictAppendWord(dp
, "c,", cComma
, FW_DEFAULT
);
4911 dictAppendWord(dp
, "c@", cFetch
, FW_DEFAULT
);
4912 dictAppendWord(dp
, "case", caseCoIm
, FW_COMPIMMED
);
4913 dictAppendWord(dp
, "cell+", cellPlus
, FW_DEFAULT
);
4914 dictAppendWord(dp
, "cells", cells
, FW_DEFAULT
);
4915 dictAppendWord(dp
, "char", ficlChar
, FW_DEFAULT
);
4916 dictAppendWord(dp
, "char+", charPlus
, FW_DEFAULT
);
4917 dictAppendWord(dp
, "chars", ficlChars
, FW_DEFAULT
);
4918 dictAppendWord(dp
, "constant", constant
, FW_DEFAULT
);
4919 dictAppendWord(dp
, "count", count
, FW_DEFAULT
);
4920 dictAppendWord(dp
, "cr", cr
, FW_DEFAULT
);
4921 dictAppendWord(dp
, "create", create
, FW_DEFAULT
);
4922 dictAppendWord(dp
, "decimal", decimal
, FW_DEFAULT
);
4923 dictAppendWord(dp
, "depth", depth
, FW_DEFAULT
);
4924 dictAppendWord(dp
, "do", doCoIm
, FW_COMPIMMED
);
4925 dictAppendWord(dp
, "does>", doesCoIm
, FW_COMPIMMED
);
4927 dictAppendWord(dp
, "drop", drop
, FW_DEFAULT
);
4928 dictAppendWord(dp
, "dup", dup
, FW_DEFAULT
);
4929 dictAppendWord(dp
, "else", elseCoIm
, FW_COMPIMMED
);
4930 dictAppendWord(dp
, "emit", emit
, FW_DEFAULT
);
4931 dictAppendWord(dp
, "endcase", endcaseCoIm
, FW_COMPIMMED
);
4932 dictAppendWord(dp
, "endof", endofCoIm
, FW_COMPIMMED
);
4933 dictAppendWord(dp
, "environment?", environmentQ
,FW_DEFAULT
);
4934 dictAppendWord(dp
, "evaluate", evaluate
, FW_DEFAULT
);
4935 dictAppendWord(dp
, "execute", execute
, FW_DEFAULT
);
4936 dictAppendWord(dp
, "exit", exitCoIm
, FW_COMPIMMED
);
4937 dictAppendWord(dp
, "fallthrough",fallthroughCoIm
,FW_COMPIMMED
);
4938 dictAppendWord(dp
, "fill", fill
, FW_DEFAULT
);
4939 dictAppendWord(dp
, "find", cFind
, FW_DEFAULT
);
4940 dictAppendWord(dp
, "fm/mod", fmSlashMod
, FW_DEFAULT
);
4941 dictAppendWord(dp
, "here", here
, FW_DEFAULT
);
4942 dictAppendWord(dp
, "hold", hold
, FW_DEFAULT
);
4943 dictAppendWord(dp
, "i", loopICo
, FW_COMPILE
);
4944 dictAppendWord(dp
, "if", ifCoIm
, FW_COMPIMMED
);
4945 dictAppendWord(dp
, "immediate", immediate
, FW_DEFAULT
);
4946 dictAppendWord(dp
, "invert", bitwiseNot
, FW_DEFAULT
);
4947 dictAppendWord(dp
, "j", loopJCo
, FW_COMPILE
);
4948 dictAppendWord(dp
, "k", loopKCo
, FW_COMPILE
);
4949 dictAppendWord(dp
, "leave", leaveCo
, FW_COMPILE
);
4950 dictAppendWord(dp
, "literal", literalIm
, FW_IMMEDIATE
);
4951 dictAppendWord(dp
, "loop", loopCoIm
, FW_COMPIMMED
);
4952 dictAppendWord(dp
, "lshift", lshift
, FW_DEFAULT
);
4953 dictAppendWord(dp
, "m*", mStar
, FW_DEFAULT
);
4954 dictAppendWord(dp
, "max", ficlMax
, FW_DEFAULT
);
4955 dictAppendWord(dp
, "min", ficlMin
, FW_DEFAULT
);
4956 dictAppendWord(dp
, "mod", ficlMod
, FW_DEFAULT
);
4957 dictAppendWord(dp
, "move", move
, FW_DEFAULT
);
4958 dictAppendWord(dp
, "negate", negate
, FW_DEFAULT
);
4959 dictAppendWord(dp
, "of", ofCoIm
, FW_COMPIMMED
);
4960 dictAppendWord(dp
, "or", bitwiseOr
, FW_DEFAULT
);
4961 dictAppendWord(dp
, "over", over
, FW_DEFAULT
);
4962 dictAppendWord(dp
, "postpone", postponeCoIm
, FW_COMPIMMED
);
4963 dictAppendWord(dp
, "quit", quit
, FW_DEFAULT
);
4964 dictAppendWord(dp
, "r>", fromRStack
, FW_COMPILE
);
4965 dictAppendWord(dp
, "r@", fetchRStack
, FW_COMPILE
);
4966 dictAppendWord(dp
, "recurse", recurseCoIm
, FW_COMPIMMED
);
4967 dictAppendWord(dp
, "repeat", repeatCoIm
, FW_COMPIMMED
);
4968 dictAppendWord(dp
, "rot", rot
, FW_DEFAULT
);
4969 dictAppendWord(dp
, "rshift", rshift
, FW_DEFAULT
);
4970 dictAppendWord(dp
, "s\"", stringQuoteIm
, FW_IMMEDIATE
);
4971 dictAppendWord(dp
, "s>d", sToD
, FW_DEFAULT
);
4972 dictAppendWord(dp
, "sign", sign
, FW_DEFAULT
);
4973 dictAppendWord(dp
, "sm/rem", smSlashRem
, FW_DEFAULT
);
4974 dictAppendWord(dp
, "source", source
, FW_DEFAULT
);
4975 dictAppendWord(dp
, "state", state
, FW_DEFAULT
);
4976 dictAppendWord(dp
, "swap", swap
, FW_DEFAULT
);
4977 dictAppendWord(dp
, "then", endifCoIm
, FW_COMPIMMED
);
4978 dictAppendWord(dp
, "type", type
, FW_DEFAULT
);
4979 dictAppendWord(dp
, "u.", uDot
, FW_DEFAULT
);
4980 dictAppendWord(dp
, "u<", uIsLess
, FW_DEFAULT
);
4981 dictAppendWord(dp
, "um*", umStar
, FW_DEFAULT
);
4982 dictAppendWord(dp
, "um/mod", umSlashMod
, FW_DEFAULT
);
4983 dictAppendWord(dp
, "unloop", unloopCo
, FW_COMPILE
);
4984 dictAppendWord(dp
, "until", untilCoIm
, FW_COMPIMMED
);
4985 dictAppendWord(dp
, "variable", variable
, FW_DEFAULT
);
4986 dictAppendWord(dp
, "while", whileCoIm
, FW_COMPIMMED
);
4987 dictAppendWord(dp
, "word", ficlWord
, FW_DEFAULT
);
4988 dictAppendWord(dp
, "xor", bitwiseXor
, FW_DEFAULT
);
4989 dictAppendWord(dp
, "[", lbracketCoIm
, FW_COMPIMMED
);
4990 dictAppendWord(dp
, "[\']", bracketTickCoIm
,FW_COMPIMMED
);
4991 dictAppendWord(dp
, "[char]", charCoIm
, FW_COMPIMMED
);
4992 dictAppendWord(dp
, "]", rbracket
, FW_DEFAULT
);
4994 ** CORE EXT word set...
4995 ** see softcore.fr for other definitions
4998 dictAppendWord(dp
, ".(", dotParen
, FW_IMMEDIATE
);
5000 dictAppendWord(dp
, "0>", zeroGreater
, FW_DEFAULT
);
5001 dictAppendWord(dp
, "2>r", twoToR
, FW_COMPILE
);
5002 dictAppendWord(dp
, "2r>", twoRFrom
, FW_COMPILE
);
5003 dictAppendWord(dp
, "2r@", twoRFetch
, FW_COMPILE
);
5004 dictAppendWord(dp
, ":noname", colonNoName
, FW_DEFAULT
);
5005 dictAppendWord(dp
, "?do", qDoCoIm
, FW_COMPIMMED
);
5006 dictAppendWord(dp
, "again", againCoIm
, FW_COMPIMMED
);
5007 dictAppendWord(dp
, "c\"", cstringQuoteIm
, FW_IMMEDIATE
);
5008 dictAppendWord(dp
, "hex", hex
, FW_DEFAULT
);
5009 dictAppendWord(dp
, "pad", pad
, FW_DEFAULT
);
5010 dictAppendWord(dp
, "parse", parse
, FW_DEFAULT
);
5011 dictAppendWord(dp
, "pick", pick
, FW_DEFAULT
);
5012 /* query restore-input save-input tib u.r u> unused [compile] */
5013 dictAppendWord(dp
, "roll", roll
, FW_DEFAULT
);
5014 dictAppendWord(dp
, "refill", refill
, FW_DEFAULT
);
5015 dictAppendWord(dp
, "source-id", sourceid
, FW_DEFAULT
);
5016 dictAppendWord(dp
, "to", toValue
, FW_IMMEDIATE
);
5017 dictAppendWord(dp
, "value", constant
, FW_DEFAULT
);
5018 dictAppendWord(dp
, "\\", commentLine
, FW_IMMEDIATE
);
5022 ** Set CORE environment query values
5024 ficlSetEnv(pSys
, "/counted-string", FICL_STRING_MAX
);
5025 ficlSetEnv(pSys
, "/hold", nPAD
);
5026 ficlSetEnv(pSys
, "/pad", nPAD
);
5027 ficlSetEnv(pSys
, "address-unit-bits", 8);
5028 ficlSetEnv(pSys
, "core", FICL_TRUE
);
5029 ficlSetEnv(pSys
, "core-ext", FICL_FALSE
);
5030 ficlSetEnv(pSys
, "floored", FICL_FALSE
);
5031 ficlSetEnv(pSys
, "max-char", UCHAR_MAX
);
5032 ficlSetEnvD(pSys
,"max-d", 0x7fffffff, 0xffffffff);
5033 ficlSetEnv(pSys
, "max-n", 0x7fffffff);
5034 ficlSetEnv(pSys
, "max-u", 0xffffffff);
5035 ficlSetEnvD(pSys
,"max-ud", 0xffffffff, 0xffffffff);
5036 ficlSetEnv(pSys
, "return-stack-cells",FICL_DEFAULT_STACK
);
5037 ficlSetEnv(pSys
, "stack-cells", FICL_DEFAULT_STACK
);
5040 ** DOUBLE word set (partial)
5042 dictAppendWord(dp
, "2constant", twoConstant
, FW_IMMEDIATE
);
5043 dictAppendWord(dp
, "2literal", twoLiteralIm
, FW_IMMEDIATE
);
5044 dictAppendWord(dp
, "2variable", twoVariable
, FW_IMMEDIATE
);
5045 dictAppendWord(dp
, "dnegate", dnegate
, FW_DEFAULT
);
5049 ** EXCEPTION word set
5051 dictAppendWord(dp
, "catch", ficlCatch
, FW_DEFAULT
);
5052 dictAppendWord(dp
, "throw", ficlThrow
, FW_DEFAULT
);
5054 ficlSetEnv(pSys
, "exception", FICL_TRUE
);
5055 ficlSetEnv(pSys
, "exception-ext", FICL_TRUE
);
5058 ** LOCAL and LOCAL EXT
5059 ** see softcore.c for implementation of locals|
5061 #if FICL_WANT_LOCALS
5063 dictAppendWord(dp
, "(link)", linkParen
, FW_COMPILE
);
5064 pSys
->pUnLinkParen
=
5065 dictAppendWord(dp
, "(unlink)", unlinkParen
, FW_COMPILE
);
5066 dictAppendWord(dp
, "doLocal", doLocalIm
, FW_COMPIMMED
);
5067 pSys
->pGetLocalParen
=
5068 dictAppendWord(dp
, "(@local)", getLocalParen
, FW_COMPILE
);
5069 pSys
->pToLocalParen
=
5070 dictAppendWord(dp
, "(toLocal)", toLocalParen
, FW_COMPILE
);
5072 dictAppendWord(dp
, "(@local0)", getLocal0
, FW_COMPILE
);
5074 dictAppendWord(dp
, "(toLocal0)",toLocal0
, FW_COMPILE
);
5076 dictAppendWord(dp
, "(@local1)", getLocal1
, FW_COMPILE
);
5078 dictAppendWord(dp
, "(toLocal1)",toLocal1
, FW_COMPILE
);
5079 dictAppendWord(dp
, "(local)", localParen
, FW_COMPILE
);
5081 pSys
->pGet2LocalParen
=
5082 dictAppendWord(dp
, "(@2local)", get2LocalParen
, FW_COMPILE
);
5083 pSys
->pTo2LocalParen
=
5084 dictAppendWord(dp
, "(to2Local)",to2LocalParen
, FW_COMPILE
);
5085 dictAppendWord(dp
, "(2local)", twoLocalParen
, FW_COMPILE
);
5087 ficlSetEnv(pSys
, "locals", FICL_TRUE
);
5088 ficlSetEnv(pSys
, "locals-ext", FICL_TRUE
);
5089 ficlSetEnv(pSys
, "#locals", FICL_MAX_LOCALS
);
5093 ** Optional MEMORY-ALLOC word set
5096 dictAppendWord(dp
, "allocate", ansAllocate
, FW_DEFAULT
);
5097 dictAppendWord(dp
, "free", ansFree
, FW_DEFAULT
);
5098 dictAppendWord(dp
, "resize", ansResize
, FW_DEFAULT
);
5100 ficlSetEnv(pSys
, "memory-alloc", FICL_TRUE
);
5103 ** optional SEARCH-ORDER word set
5105 ficlCompileSearch(pSys
);
5108 ** TOOLS and TOOLS EXT
5110 ficlCompileTools(pSys
);
5113 ** FILE and FILE EXT
5116 ficlCompileFile(pSys
);
5123 dictAppendWord(dp
, ".hash", dictHashSummary
,FW_DEFAULT
);
5125 dictAppendWord(dp
, ".ver", ficlVersion
, FW_DEFAULT
);
5126 dictAppendWord(dp
, "-roll", minusRoll
, FW_DEFAULT
);
5127 dictAppendWord(dp
, ">name", toName
, FW_DEFAULT
);
5128 dictAppendWord(dp
, "add-parse-step",
5129 addParseStep
, FW_DEFAULT
);
5130 dictAppendWord(dp
, "body>", fromBody
, FW_DEFAULT
);
5131 dictAppendWord(dp
, "compare", compareString
, FW_DEFAULT
); /* STRING */
5132 dictAppendWord(dp
, "compare-insensitive", compareStringInsensitive
, FW_DEFAULT
); /* STRING */
5133 dictAppendWord(dp
, "compile-only",
5134 compileOnly
, FW_DEFAULT
);
5135 dictAppendWord(dp
, "endif", endifCoIm
, FW_COMPIMMED
);
5136 dictAppendWord(dp
, "last-word", getLastWord
, FW_DEFAULT
);
5137 dictAppendWord(dp
, "hash", hash
, FW_DEFAULT
);
5138 dictAppendWord(dp
, "objectify", setObjectFlag
, FW_DEFAULT
);
5139 dictAppendWord(dp
, "?object", isObject
, FW_DEFAULT
);
5140 dictAppendWord(dp
, "parse-word",parseNoCopy
, FW_DEFAULT
);
5141 dictAppendWord(dp
, "sfind", sFind
, FW_DEFAULT
);
5142 dictAppendWord(dp
, "sliteral", sLiteralCoIm
, FW_COMPIMMED
); /* STRING */
5143 dictAppendWord(dp
, "sprintf", ficlSprintf
, FW_DEFAULT
);
5144 dictAppendWord(dp
, "strlen", ficlStrlen
, FW_DEFAULT
);
5145 dictAppendWord(dp
, "q@", quadFetch
, FW_DEFAULT
);
5146 dictAppendWord(dp
, "q!", quadStore
, FW_DEFAULT
);
5147 dictAppendWord(dp
, "w@", wFetch
, FW_DEFAULT
);
5148 dictAppendWord(dp
, "w!", wStore
, FW_DEFAULT
);
5149 dictAppendWord(dp
, "x.", hexDot
, FW_DEFAULT
);
5151 dictAppendWord(dp
, "(user)", userParen
, FW_DEFAULT
);
5152 dictAppendWord(dp
, "user", userVariable
, FW_DEFAULT
);
5155 dictAppendWord(dp
, "random", ficlRandom
, FW_DEFAULT
);
5156 dictAppendWord(dp
, "seed-random",ficlSeedRandom
,FW_DEFAULT
);
5160 ** internal support words
5162 dictAppendWord(dp
, "(create)", createParen
, FW_COMPILE
);
5164 dictAppendWord(dp
, "(exit)", exitParen
, FW_COMPILE
);
5166 dictAppendWord(dp
, "(;)", semiParen
, FW_COMPILE
);
5168 dictAppendWord(dp
, "(literal)", literalParen
, FW_COMPILE
);
5169 pSys
->pTwoLitParen
=
5170 dictAppendWord(dp
, "(2literal)",twoLitParen
, FW_COMPILE
);
5172 dictAppendWord(dp
, "(.\")", stringLit
, FW_COMPILE
);
5174 dictAppendWord(dp
, "(c\")", cstringLit
, FW_COMPILE
);
5176 dictAppendWord(dp
, "(branch0)", branch0
, FW_COMPILE
);
5177 pSys
->pBranchParen
=
5178 dictAppendWord(dp
, "(branch)", branchParen
, FW_COMPILE
);
5180 dictAppendWord(dp
, "(do)", doParen
, FW_COMPILE
);
5182 dictAppendWord(dp
, "(does>)", doesParen
, FW_COMPILE
);
5184 dictAppendWord(dp
, "(?do)", qDoParen
, FW_COMPILE
);
5186 dictAppendWord(dp
, "(loop)", loopParen
, FW_COMPILE
);
5188 dictAppendWord(dp
, "(+loop)", plusLoopParen
, FW_COMPILE
);
5190 dictAppendWord(dp
, "interpret", interpret
, FW_DEFAULT
);
5191 dictAppendWord(dp
, "lookup", lookup
, FW_DEFAULT
);
5193 dictAppendWord(dp
, "(of)", ofParen
, FW_DEFAULT
);
5194 dictAppendWord(dp
, "(variable)",variableParen
, FW_COMPILE
);
5195 dictAppendWord(dp
, "(constant)",constantParen
, FW_COMPILE
);
5196 dictAppendWord(dp
, "(parse-step)",
5197 parseStepParen
, FW_DEFAULT
);
5199 dictAppendWord(dp
, "exit-inner",ficlExitInner
, FW_DEFAULT
);
5202 ** Set up system's outer interpreter loop - maybe this should be in initSystem?
5204 pSys
->pInterp
[0] = pSys
->pInterpret
;
5205 pSys
->pInterp
[1] = pSys
->pBranchParen
;
5206 pSys
->pInterp
[2] = (FICL_WORD
*)(void *)(-2);
5208 assert(dictCellsAvail(dp
) > 0);