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.39 2002/12/30 21:18:06 schweikh Exp $
46 * $DragonFly: src/sys/boot/ficl/words.c,v 1.3 2003/11/10 06:08:33 dillon 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";
78 static void doLocalIm(FICL_VM
*pVM
);
79 static void do2LocalIm(FICL_VM
*pVM
);
84 ** C O N T R O L S T R U C T U R E B U I L D E R S
86 ** Push current dict location for later branch resolution.
87 ** The location may be either a branch target or a patch address...
89 static void markBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
96 static void markControlTag(FICL_VM
*pVM
, char *tag
)
102 static void matchControlTag(FICL_VM
*pVM
, char *tag
)
106 vmCheckStack(pVM
, 1, 0);
108 cp
= (char *)stackPopPtr(pVM
->pStack
);
110 ** Changed the code below to compare the pointers first (by popular demand)
112 if ( (cp
!= tag
) && strcmp(cp
, tag
) )
114 vmThrowErr(pVM
, "Error -- unmatched control structure \"%s\"", tag
);
121 ** Expect a branch target address on the param stack,
122 ** compile a literal offset from the current dict location
123 ** to the target address
125 static void resolveBackBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
130 matchControlTag(pVM
, tag
);
133 vmCheckStack(pVM
, 1, 0);
135 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
136 offset
= patchAddr
- dp
->here
;
137 dictAppendCell(dp
, LVALUEtoCELL(offset
));
144 ** Expect a branch patch address on the param stack,
145 ** compile a literal offset from the patch location
146 ** to the current dict location
148 static void resolveForwardBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
153 matchControlTag(pVM
, tag
);
156 vmCheckStack(pVM
, 1, 0);
158 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
159 offset
= dp
->here
- patchAddr
;
160 *patchAddr
= LVALUEtoCELL(offset
);
166 ** Match the tag to the top of the stack. If success,
167 ** sopy "here" address into the cell whose address is next
168 ** on the stack. Used by do..leave..loop.
170 static void resolveAbsBranch(FICL_DICT
*dp
, FICL_VM
*pVM
, char *tag
)
176 vmCheckStack(pVM
, 2, 0);
178 cp
= stackPopPtr(pVM
->pStack
);
180 ** Changed the comparison below to compare the pointers first (by popular demand)
182 if ((cp
!= tag
) && strcmp(cp
, tag
))
184 vmTextOut(pVM
, "Warning -- Unmatched control word: ", 0);
185 vmTextOut(pVM
, tag
, 1);
188 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
189 *patchAddr
= LVALUEtoCELL(dp
->here
);
195 /**************************************************************************
196 f i c l P a r s e N u m b e r
197 ** Attempts to convert the NULL terminated string in the VM's pad to
198 ** a number using the VM's current base. If successful, pushes the number
199 ** onto the param stack and returns TRUE. Otherwise, returns FALSE.
200 ** (jws 8/01) Trailing decimal point causes a zero cell to be pushed. (See
201 ** the standard for DOUBLE wordset.
202 **************************************************************************/
204 int ficlParseNumber(FICL_VM
*pVM
, STRINGINFO si
)
209 unsigned base
= pVM
->base
;
210 char *cp
= SI_PTR(si
);
211 FICL_COUNT count
= (FICL_COUNT
)SI_COUNT(si
);
234 if ((count
> 0) && (cp
[count
-1] == '.')) /* detect & remove trailing decimal */
240 if (count
== 0) /* detect "+", "-", ".", "+." etc */
243 while ((count
--) && ((ch
= *cp
++) != '\0'))
251 digit
= tolower(ch
) - 'a' + 10;
256 accum
= accum
* base
+ digit
;
259 if (hasDP
) /* simple (required) DOUBLE support */
266 if (pVM
->state
== COMPILE
)
273 /**************************************************************************
274 a d d & f r i e n d s
276 **************************************************************************/
278 static void add(FICL_VM
*pVM
)
282 vmCheckStack(pVM
, 2, 1);
284 i
= stackPopINT(pVM
->pStack
);
285 i
+= stackGetTop(pVM
->pStack
).i
;
286 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
290 static void sub(FICL_VM
*pVM
)
294 vmCheckStack(pVM
, 2, 1);
296 i
= stackPopINT(pVM
->pStack
);
297 i
= stackGetTop(pVM
->pStack
).i
- i
;
298 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
302 static void mul(FICL_VM
*pVM
)
306 vmCheckStack(pVM
, 2, 1);
308 i
= stackPopINT(pVM
->pStack
);
309 i
*= stackGetTop(pVM
->pStack
).i
;
310 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
314 static void negate(FICL_VM
*pVM
)
318 vmCheckStack(pVM
, 1, 1);
320 i
= -stackPopINT(pVM
->pStack
);
325 static void ficlDiv(FICL_VM
*pVM
)
329 vmCheckStack(pVM
, 2, 1);
331 i
= stackPopINT(pVM
->pStack
);
332 i
= stackGetTop(pVM
->pStack
).i
/ i
;
333 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
338 ** slash-mod CORE ( n1 n2 -- n3 n4 )
339 ** Divide n1 by n2, giving the single-cell remainder n3 and the single-cell
340 ** quotient n4. An ambiguous condition exists if n2 is zero. If n1 and n2
341 ** differ in sign, the implementation-defined result returned will be the
342 ** same as that returned by either the phrase
343 ** >R S>D R> FM/MOD or the phrase >R S>D R> SM/REM .
344 ** NOTE: Ficl complies with the second phrase (symmetric division)
346 static void slashMod(FICL_VM
*pVM
)
353 vmCheckStack(pVM
, 2, 2);
355 n2
= stackPopINT(pVM
->pStack
);
356 n1
.lo
= stackPopINT(pVM
->pStack
);
359 qr
= m64SymmetricDivI(n1
, n2
);
365 static void onePlus(FICL_VM
*pVM
)
369 vmCheckStack(pVM
, 1, 1);
371 i
= stackGetTop(pVM
->pStack
).i
;
373 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
377 static void oneMinus(FICL_VM
*pVM
)
381 vmCheckStack(pVM
, 1, 1);
383 i
= stackGetTop(pVM
->pStack
).i
;
385 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
389 static void twoMul(FICL_VM
*pVM
)
393 vmCheckStack(pVM
, 1, 1);
395 i
= stackGetTop(pVM
->pStack
).i
;
397 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
401 static void twoDiv(FICL_VM
*pVM
)
405 vmCheckStack(pVM
, 1, 1);
407 i
= stackGetTop(pVM
->pStack
).i
;
409 stackSetTop(pVM
->pStack
, LVALUEtoCELL(i
));
413 static void mulDiv(FICL_VM
*pVM
)
418 vmCheckStack(pVM
, 3, 1);
420 z
= stackPopINT(pVM
->pStack
);
421 y
= stackPopINT(pVM
->pStack
);
422 x
= stackPopINT(pVM
->pStack
);
425 x
= m64SymmetricDivI(prod
, z
).quot
;
432 static void mulDivRem(FICL_VM
*pVM
)
438 vmCheckStack(pVM
, 3, 2);
440 z
= stackPopINT(pVM
->pStack
);
441 y
= stackPopINT(pVM
->pStack
);
442 x
= stackPopINT(pVM
->pStack
);
445 qr
= m64SymmetricDivI(prod
, z
);
453 /**************************************************************************
454 c o l o n d e f i n i t i o n s
455 ** Code to begin compiling a colon definition
456 ** This function sets the state to COMPILE, then creates a
457 ** new word whose name is the next word in the input stream
458 ** and whose code is colonParen.
459 **************************************************************************/
461 static void colon(FICL_VM
*pVM
)
463 FICL_DICT
*dp
= vmGetDict(pVM
);
464 STRINGINFO si
= vmGetWord(pVM
);
466 dictCheckThreshold(dp
);
468 pVM
->state
= COMPILE
;
469 markControlTag(pVM
, colonTag
);
470 dictAppendWord2(dp
, si
, colonParen
, FW_DEFAULT
| FW_SMUDGE
);
472 pVM
->pSys
->nLocals
= 0;
478 /**************************************************************************
480 ** This is the code that executes a colon definition. It assumes that the
481 ** virtual machine is running a "next" loop (See the vm.c
482 ** for its implementation of member function vmExecute()). The colon
483 ** code simply copies the address of the first word in the list of words
484 ** to interpret into IP after saving its old value. When we return to the
485 ** "next" loop, the virtual machine will call the code for each word in
488 **************************************************************************/
490 static void colonParen(FICL_VM
*pVM
)
492 IPTYPE tempIP
= (IPTYPE
) (pVM
->runningWord
->param
);
493 vmPushIP(pVM
, tempIP
);
499 /**************************************************************************
500 s e m i c o l o n C o I m
502 ** IMMEDIATE code for ";". This function sets the state to INTERPRET and
503 ** terminates a word under compilation by appending code for "(;)" to
504 ** the definition. TO DO: checks for leftover branch target tags on the
505 ** return stack and complains if any are found.
506 **************************************************************************/
507 static void semiParen(FICL_VM
*pVM
)
514 static void semicolonCoIm(FICL_VM
*pVM
)
516 FICL_DICT
*dp
= vmGetDict(pVM
);
518 assert(pVM
->pSys
->pSemiParen
);
519 matchControlTag(pVM
, colonTag
);
522 assert(pVM
->pSys
->pUnLinkParen
);
523 if (pVM
->pSys
->nLocals
> 0)
525 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
526 dictEmpty(pLoc
, pLoc
->pForthWords
->size
);
527 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
529 pVM
->pSys
->nLocals
= 0;
532 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pSemiParen
));
533 pVM
->state
= INTERPRET
;
539 /**************************************************************************
542 ** This function simply pops the previous instruction
543 ** pointer and returns to the "next" loop. Used for exiting from within
544 ** a definition. Note that exitParen is identical to semiParen - they
545 ** are in two different functions so that "see" can correctly identify
546 ** the end of a colon definition, even if it uses "exit".
547 **************************************************************************/
548 static void exitParen(FICL_VM
*pVM
)
554 static void exitCoIm(FICL_VM
*pVM
)
556 FICL_DICT
*dp
= vmGetDict(pVM
);
557 assert(pVM
->pSys
->pExitParen
);
561 if (pVM
->pSys
->nLocals
> 0)
563 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
566 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pExitParen
));
571 /**************************************************************************
572 c o n s t a n t P a r e n
573 ** This is the run-time code for "constant". It simply returns the
574 ** contents of its word's first data cell.
576 **************************************************************************/
578 void constantParen(FICL_VM
*pVM
)
580 FICL_WORD
*pFW
= pVM
->runningWord
;
582 vmCheckStack(pVM
, 0, 1);
584 stackPush(pVM
->pStack
, pFW
->param
[0]);
588 void twoConstParen(FICL_VM
*pVM
)
590 FICL_WORD
*pFW
= pVM
->runningWord
;
592 vmCheckStack(pVM
, 0, 2);
594 stackPush(pVM
->pStack
, pFW
->param
[0]); /* lo */
595 stackPush(pVM
->pStack
, pFW
->param
[1]); /* hi */
600 /**************************************************************************
603 ** Compiles a constant into the dictionary. Constants return their
604 ** value when invoked. Expects a value on top of the parm stack.
605 **************************************************************************/
607 static void constant(FICL_VM
*pVM
)
609 FICL_DICT
*dp
= vmGetDict(pVM
);
610 STRINGINFO si
= vmGetWord(pVM
);
613 vmCheckStack(pVM
, 1, 0);
615 dictAppendWord2(dp
, si
, constantParen
, FW_DEFAULT
);
616 dictAppendCell(dp
, stackPop(pVM
->pStack
));
621 static void twoConstant(FICL_VM
*pVM
)
623 FICL_DICT
*dp
= vmGetDict(pVM
);
624 STRINGINFO si
= vmGetWord(pVM
);
628 vmCheckStack(pVM
, 2, 0);
630 c
= stackPop(pVM
->pStack
);
631 dictAppendWord2(dp
, si
, twoConstParen
, FW_DEFAULT
);
632 dictAppendCell(dp
, stackPop(pVM
->pStack
));
633 dictAppendCell(dp
, c
);
638 /**************************************************************************
639 d i s p l a y C e l l
640 ** Drop and print the contents of the cell at the top of the param
642 **************************************************************************/
644 static void displayCell(FICL_VM
*pVM
)
648 vmCheckStack(pVM
, 1, 0);
650 c
= stackPop(pVM
->pStack
);
651 ltoa((c
).i
, pVM
->pad
, pVM
->base
);
652 strcat(pVM
->pad
, " ");
653 vmTextOut(pVM
, pVM
->pad
, 0);
657 static void uDot(FICL_VM
*pVM
)
661 vmCheckStack(pVM
, 1, 0);
663 u
= stackPopUNS(pVM
->pStack
);
664 ultoa(u
, pVM
->pad
, pVM
->base
);
665 strcat(pVM
->pad
, " ");
666 vmTextOut(pVM
, pVM
->pad
, 0);
671 static void hexDot(FICL_VM
*pVM
)
675 vmCheckStack(pVM
, 1, 0);
677 u
= stackPopUNS(pVM
->pStack
);
678 ultoa(u
, pVM
->pad
, 16);
679 strcat(pVM
->pad
, " ");
680 vmTextOut(pVM
, pVM
->pad
, 0);
685 /**************************************************************************
687 ** FICL ( c-string -- length )
689 ** Returns the length of a C-style (zero-terminated) string.
693 static void ficlStrlen(FICL_VM
*ficlVM
)
695 char *address
= (char *)stackPopPtr(ficlVM
->pStack
);
696 stackPushINT(ficlVM
->pStack
, strlen(address
));
700 /**************************************************************************
702 ** FICL ( i*x c-addr-fmt u-fmt c-addr-buffer u-buffer -- c-addr-buffer u-written success-flag )
703 ** Similar to the C sprintf() function. It formats into a buffer based on
704 ** a "format" string. Each character in the format string is copied verbatim
705 ** to the output buffer, until SPRINTF encounters a percent sign ("%").
706 ** SPRINTF then skips the percent sign, and examines the next character
707 ** (the "format character"). Here are the valid format characters:
708 ** s - read a C-ADDR U-LENGTH string from the stack and copy it to
710 ** d - read a cell from the stack, format it as a string (base-10,
711 ** signed), and copy it to the buffer
712 ** x - same as d, except in base-16
713 ** u - same as d, but unsigned
714 ** % - output a literal percent-sign to the buffer
715 ** SPRINTF returns the c-addr-buffer argument unchanged, the number of bytes
716 ** written, and a flag indicating whether or not it ran out of space while
717 ** writing to the output buffer (TRUE if it ran out of space).
719 ** If SPRINTF runs out of space in the buffer to store the formatted string,
720 ** it still continues parsing, in an effort to preserve your stack (otherwise
721 ** it might leave uneaten arguments behind).
724 **************************************************************************/
725 static void ficlSprintf(FICL_VM
*pVM
) /* */
727 int bufferLength
= stackPopINT(pVM
->pStack
);
728 char *buffer
= (char *)stackPopPtr(pVM
->pStack
);
729 char *bufferStart
= buffer
;
731 int formatLength
= stackPopINT(pVM
->pStack
);
732 char *format
= (char *)stackPopPtr(pVM
->pStack
);
733 char *formatStop
= format
+ formatLength
;
736 int unsignedInteger
= FALSE
;
738 FICL_INT append
= FICL_TRUE
;
740 while (format
< formatStop
)
752 actualLength
= desiredLength
= 1;
758 if (format
== formatStop
)
761 leadingZeroes
= (*format
== '0');
765 if (format
== formatStop
)
769 desiredLength
= isdigit(*format
);
772 desiredLength
= strtol(format
, &format
, 10);
773 if (format
== formatStop
)
776 else if (*format
== '*')
778 desiredLength
= stackPopINT(pVM
->pStack
);
780 if (format
== formatStop
)
790 actualLength
= stackPopINT(pVM
->pStack
);
791 source
= (char *)stackPopPtr(pVM
->pStack
);
799 unsignedInteger
= TRUE
;
803 int integer
= stackPopINT(pVM
->pStack
);
805 ultoa(integer
, scratch
, base
);
807 ltoa(integer
, scratch
, base
);
809 unsignedInteger
= FALSE
;
811 actualLength
= strlen(scratch
);
822 if (append
!= FICL_FALSE
)
825 desiredLength
= actualLength
;
826 if (desiredLength
> bufferLength
)
829 desiredLength
= bufferLength
;
831 while (desiredLength
> actualLength
)
833 *buffer
++ = (char)((leadingZeroes
) ? '0' : ' ');
837 memcpy(buffer
, source
, actualLength
);
838 buffer
+= actualLength
;
839 bufferLength
-= actualLength
;
845 stackPushPtr(pVM
->pStack
, bufferStart
);
846 stackPushINT(pVM
->pStack
, buffer
- bufferStart
);
847 stackPushINT(pVM
->pStack
, append
);
851 /**************************************************************************
852 d u p & f r i e n d s
854 **************************************************************************/
856 static void depth(FICL_VM
*pVM
)
860 vmCheckStack(pVM
, 0, 1);
862 i
= stackDepth(pVM
->pStack
);
868 static void drop(FICL_VM
*pVM
)
871 vmCheckStack(pVM
, 1, 0);
873 stackDrop(pVM
->pStack
, 1);
878 static void twoDrop(FICL_VM
*pVM
)
881 vmCheckStack(pVM
, 2, 0);
883 stackDrop(pVM
->pStack
, 2);
888 static void dup(FICL_VM
*pVM
)
891 vmCheckStack(pVM
, 1, 2);
893 stackPick(pVM
->pStack
, 0);
898 static void twoDup(FICL_VM
*pVM
)
901 vmCheckStack(pVM
, 2, 4);
903 stackPick(pVM
->pStack
, 1);
904 stackPick(pVM
->pStack
, 1);
909 static void over(FICL_VM
*pVM
)
912 vmCheckStack(pVM
, 2, 3);
914 stackPick(pVM
->pStack
, 1);
918 static void twoOver(FICL_VM
*pVM
)
921 vmCheckStack(pVM
, 4, 6);
923 stackPick(pVM
->pStack
, 3);
924 stackPick(pVM
->pStack
, 3);
929 static void pick(FICL_VM
*pVM
)
931 CELL c
= stackPop(pVM
->pStack
);
933 vmCheckStack(pVM
, c
.i
+1, c
.i
+2);
935 stackPick(pVM
->pStack
, c
.i
);
940 static void questionDup(FICL_VM
*pVM
)
944 vmCheckStack(pVM
, 1, 2);
946 c
= stackGetTop(pVM
->pStack
);
949 stackPick(pVM
->pStack
, 0);
955 static void roll(FICL_VM
*pVM
)
957 int i
= stackPop(pVM
->pStack
).i
;
960 vmCheckStack(pVM
, i
+1, i
+1);
962 stackRoll(pVM
->pStack
, i
);
967 static void minusRoll(FICL_VM
*pVM
)
969 int i
= stackPop(pVM
->pStack
).i
;
972 vmCheckStack(pVM
, i
+1, i
+1);
974 stackRoll(pVM
->pStack
, -i
);
979 static void rot(FICL_VM
*pVM
)
982 vmCheckStack(pVM
, 3, 3);
984 stackRoll(pVM
->pStack
, 2);
989 static void swap(FICL_VM
*pVM
)
992 vmCheckStack(pVM
, 2, 2);
994 stackRoll(pVM
->pStack
, 1);
999 static void twoSwap(FICL_VM
*pVM
)
1002 vmCheckStack(pVM
, 4, 4);
1004 stackRoll(pVM
->pStack
, 3);
1005 stackRoll(pVM
->pStack
, 3);
1010 /**************************************************************************
1011 e m i t & f r i e n d s
1013 **************************************************************************/
1015 static void emit(FICL_VM
*pVM
)
1017 char *cp
= pVM
->pad
;
1021 vmCheckStack(pVM
, 1, 0);
1023 i
= stackPopINT(pVM
->pStack
);
1026 vmTextOut(pVM
, cp
, 0);
1031 static void cr(FICL_VM
*pVM
)
1033 vmTextOut(pVM
, "", 1);
1038 static void commentLine(FICL_VM
*pVM
)
1040 char *cp
= vmGetInBuf(pVM
);
1041 char *pEnd
= vmGetInBufEnd(pVM
);
1044 while ((cp
!= pEnd
) && (ch
!= '\r') && (ch
!= '\n'))
1050 ** Cope with DOS or UNIX-style EOLs -
1051 ** Check for /r, /n, /r/n, or /n/r end-of-line sequences,
1052 ** and point cp to next char. If EOL is \0, we're done.
1058 if ( (cp
!= pEnd
) && (ch
!= *cp
)
1059 && ((*cp
== '\r') || (*cp
== '\n')) )
1063 vmUpdateTib(pVM
, cp
);
1070 ** Compilation: Perform the execution semantics given below.
1071 ** Execution: ( "ccc<paren>" -- )
1072 ** Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
1073 ** The number of characters in ccc may be zero to the number of characters
1074 ** in the parse area.
1077 static void commentHang(FICL_VM
*pVM
)
1079 vmParseStringEx(pVM
, ')', 0);
1084 /**************************************************************************
1085 F E T C H & S T O R E
1087 **************************************************************************/
1089 static void fetch(FICL_VM
*pVM
)
1093 vmCheckStack(pVM
, 1, 1);
1095 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1096 stackPush(pVM
->pStack
, *pCell
);
1101 ** two-fetch CORE ( a-addr -- x1 x2 )
1102 ** Fetch the cell pair x1 x2 stored at a-addr. x2 is stored at a-addr and
1103 ** x1 at the next consecutive cell. It is equivalent to the sequence
1104 ** DUP CELL+ @ SWAP @ .
1106 static void twoFetch(FICL_VM
*pVM
)
1110 vmCheckStack(pVM
, 1, 2);
1112 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1113 stackPush(pVM
->pStack
, *pCell
++);
1114 stackPush(pVM
->pStack
, *pCell
);
1120 ** store CORE ( x a-addr -- )
1121 ** Store x at a-addr.
1123 static void store(FICL_VM
*pVM
)
1127 vmCheckStack(pVM
, 2, 0);
1129 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1130 *pCell
= stackPop(pVM
->pStack
);
1134 ** two-store CORE ( x1 x2 a-addr -- )
1135 ** Store the cell pair x1 x2 at a-addr, with x2 at a-addr and x1 at the
1136 ** next consecutive cell. It is equivalent to the sequence
1137 ** SWAP OVER ! CELL+ ! .
1139 static void twoStore(FICL_VM
*pVM
)
1143 vmCheckStack(pVM
, 3, 0);
1145 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1146 *pCell
++ = stackPop(pVM
->pStack
);
1147 *pCell
= stackPop(pVM
->pStack
);
1150 static void plusStore(FICL_VM
*pVM
)
1154 vmCheckStack(pVM
, 2, 0);
1156 pCell
= (CELL
*)stackPopPtr(pVM
->pStack
);
1157 pCell
->i
+= stackPop(pVM
->pStack
).i
;
1161 static void quadFetch(FICL_VM
*pVM
)
1165 vmCheckStack(pVM
, 1, 1);
1167 pw
= (UNS32
*)stackPopPtr(pVM
->pStack
);
1168 PUSHUNS((FICL_UNS
)*pw
);
1172 static void quadStore(FICL_VM
*pVM
)
1176 vmCheckStack(pVM
, 2, 0);
1178 pw
= (UNS32
*)stackPopPtr(pVM
->pStack
);
1179 *pw
= (UNS32
)(stackPop(pVM
->pStack
).u
);
1182 static void wFetch(FICL_VM
*pVM
)
1186 vmCheckStack(pVM
, 1, 1);
1188 pw
= (UNS16
*)stackPopPtr(pVM
->pStack
);
1189 PUSHUNS((FICL_UNS
)*pw
);
1193 static void wStore(FICL_VM
*pVM
)
1197 vmCheckStack(pVM
, 2, 0);
1199 pw
= (UNS16
*)stackPopPtr(pVM
->pStack
);
1200 *pw
= (UNS16
)(stackPop(pVM
->pStack
).u
);
1203 static void cFetch(FICL_VM
*pVM
)
1207 vmCheckStack(pVM
, 1, 1);
1209 pc
= (UNS8
*)stackPopPtr(pVM
->pStack
);
1210 PUSHUNS((FICL_UNS
)*pc
);
1214 static void cStore(FICL_VM
*pVM
)
1218 vmCheckStack(pVM
, 2, 0);
1220 pc
= (UNS8
*)stackPopPtr(pVM
->pStack
);
1221 *pc
= (UNS8
)(stackPop(pVM
->pStack
).u
);
1225 /**************************************************************************
1228 ** Compiles code for a conditional branch into the dictionary
1229 ** and pushes the branch patch address on the stack for later
1230 ** patching by ELSE or THEN/ENDIF.
1231 **************************************************************************/
1233 static void ifCoIm(FICL_VM
*pVM
)
1235 FICL_DICT
*dp
= vmGetDict(pVM
);
1237 assert(pVM
->pSys
->pIfParen
);
1239 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pIfParen
));
1240 markBranch(dp
, pVM
, origTag
);
1241 dictAppendUNS(dp
, 1);
1246 /**************************************************************************
1248 ** Runtime code to do "if" or "until": pop a flag from the stack,
1249 ** fall through if true, branch if false. Probably ought to be
1250 ** called (not?branch) since it does "branch if false".
1251 **************************************************************************/
1253 static void ifParen(FICL_VM
*pVM
)
1258 vmCheckStack(pVM
, 1, 0);
1260 flag
= stackPopUNS(pVM
->pStack
);
1263 { /* fall through */
1264 vmBranchRelative(pVM
, 1);
1267 { /* take branch (to else/endif/begin) */
1268 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1275 /**************************************************************************
1278 ** IMMEDIATE -- compiles an "else"...
1279 ** 1) Compile a branch and a patch address; the address gets patched
1280 ** by "endif" to point past the "else" code.
1281 ** 2) Pop the the "if" patch address
1282 ** 3) Patch the "if" branch to point to the current compile address.
1283 ** 4) Push the "else" patch address. ("endif" patches this to jump past
1285 **************************************************************************/
1287 static void elseCoIm(FICL_VM
*pVM
)
1291 FICL_DICT
*dp
= vmGetDict(pVM
);
1293 assert(pVM
->pSys
->pBranchParen
);
1294 /* (1) compile branch runtime */
1295 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1296 matchControlTag(pVM
, origTag
);
1298 (CELL
*)stackPopPtr(pVM
->pStack
); /* (2) pop "if" patch addr */
1299 markBranch(dp
, pVM
, origTag
); /* (4) push "else" patch addr */
1300 dictAppendUNS(dp
, 1); /* (1) compile patch placeholder */
1301 offset
= dp
->here
- patchAddr
;
1302 *patchAddr
= LVALUEtoCELL(offset
); /* (3) Patch "if" */
1308 /**************************************************************************
1309 b r a n c h P a r e n
1311 ** Runtime for "(branch)" -- expects a literal offset in the next
1312 ** compilation address, and branches to that location.
1313 **************************************************************************/
1315 static void branchParen(FICL_VM
*pVM
)
1317 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1322 /**************************************************************************
1325 **************************************************************************/
1327 static void endifCoIm(FICL_VM
*pVM
)
1329 FICL_DICT
*dp
= vmGetDict(pVM
);
1330 resolveForwardBranch(dp
, pVM
, origTag
);
1335 /**************************************************************************
1337 ** hash ( c-addr u -- code)
1338 ** calculates hashcode of specified string and leaves it on the stack
1339 **************************************************************************/
1341 static void hash(FICL_VM
*pVM
)
1344 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1345 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1346 PUSHUNS(hashHashCode(si
));
1351 /**************************************************************************
1353 ** This is the "user interface" of a Forth. It does the following:
1354 ** while there are words in the VM's Text Input Buffer
1355 ** Copy next word into the pad (vmGetWord)
1356 ** Attempt to find the word in the dictionary (dictLookup)
1357 ** If successful, execute the word.
1358 ** Otherwise, attempt to convert the word to a number (isNumber)
1359 ** If successful, push the number onto the parameter stack.
1360 ** Otherwise, print an error message and exit loop...
1363 ** From the standard, section 3.4
1364 ** Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
1365 ** repeat the following steps until either the parse area is empty or an
1366 ** ambiguous condition exists:
1367 ** a) Skip leading spaces and parse a name (see 3.4.1);
1368 **************************************************************************/
1370 static void interpret(FICL_VM
*pVM
)
1379 si
= vmGetWord0(pVM
);
1382 ** Get next word...if out of text, we're done.
1386 vmThrow(pVM
, VM_OUTOFTEXT
);
1390 ** Attempt to find the incoming token in the dictionary. If that fails...
1391 ** run the parse chain against the incoming token until somebody eats it.
1392 ** Otherwise emit an error message and give up.
1393 ** Although ficlParseWord could be part of the parse list, I've hard coded it
1394 ** in for robustness. ficlInitSystem adds the other default steps to the list.
1396 if (ficlParseWord(pVM
, si
))
1399 for (i
=0; i
< FICL_MAX_PARSE_STEPS
; i
++)
1401 FICL_WORD
*pFW
= pSys
->parseList
[i
];
1406 if (pFW
->code
== parseStepParen
)
1408 FICL_PARSE_STEP pStep
;
1409 pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1410 if ((*pStep
)(pVM
, si
))
1415 stackPushPtr(pVM
->pStack
, SI_PTR(si
));
1416 stackPushUNS(pVM
->pStack
, SI_COUNT(si
));
1417 ficlExecXT(pVM
, pFW
);
1418 if (stackPopINT(pVM
->pStack
))
1424 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
1426 return; /* back to inner interpreter */
1430 /**************************************************************************
1431 f i c l P a r s e W o r d
1432 ** From the standard, section 3.4
1433 ** b) Search the dictionary name space (see 3.4.2). If a definition name
1434 ** matching the string is found:
1435 ** 1.if interpreting, perform the interpretation semantics of the definition
1436 ** (see 3.4.3.2), and continue at a);
1437 ** 2.if compiling, perform the compilation semantics of the definition
1438 ** (see 3.4.3.3), and continue at a).
1440 ** c) If a definition name matching the string is not found, attempt to
1441 ** convert the string to a number (see 3.4.1.3). If successful:
1442 ** 1.if interpreting, place the number on the data stack, and continue at a);
1443 ** 2.if compiling, compile code that when executed will place the number on
1444 ** the stack (see 6.1.1780 LITERAL), and continue at a);
1446 ** d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
1448 ** (jws 4/01) Modified to be a FICL_PARSE_STEP
1449 **************************************************************************/
1450 static int ficlParseWord(FICL_VM
*pVM
, STRINGINFO si
)
1452 FICL_DICT
*dp
= vmGetDict(pVM
);
1456 dictCheck(dp
, pVM
, 0);
1457 vmCheckStack(pVM
, 0, 0);
1460 #if FICL_WANT_LOCALS
1461 if (pVM
->pSys
->nLocals
> 0)
1463 tempFW
= ficlLookupLoc(pVM
->pSys
, si
);
1467 tempFW
= dictLookup(dp
, si
);
1469 if (pVM
->state
== INTERPRET
)
1473 if (wordIsCompileOnly(tempFW
))
1475 vmThrowErr(pVM
, "Error: Compile only!");
1478 vmExecute(pVM
, tempFW
);
1479 return (int)FICL_TRUE
;
1483 else /* (pVM->state == COMPILE) */
1487 if (wordIsImmediate(tempFW
))
1489 vmExecute(pVM
, tempFW
);
1493 dictAppendCell(dp
, LVALUEtoCELL(tempFW
));
1495 return (int)FICL_TRUE
;
1504 ** Surrogate precompiled parse step for ficlParseWord (this step is hard coded in
1507 static void lookup(FICL_VM
*pVM
)
1510 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1511 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1512 stackPushINT(pVM
->pStack
, ficlParseWord(pVM
, si
));
1517 /**************************************************************************
1518 p a r e n P a r s e S t e p
1519 ** (parse-step) ( c-addr u -- flag )
1520 ** runtime for a precompiled parse step - pop a counted string off the
1521 ** stack, run the parse step against it, and push the result flag (FICL_TRUE
1522 ** if success, FICL_FALSE otherwise).
1523 **************************************************************************/
1525 void parseStepParen(FICL_VM
*pVM
)
1528 FICL_WORD
*pFW
= pVM
->runningWord
;
1529 FICL_PARSE_STEP pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1531 SI_SETLEN(si
, stackPopINT(pVM
->pStack
));
1532 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1534 PUSHINT((*pStep
)(pVM
, si
));
1540 static void addParseStep(FICL_VM
*pVM
)
1543 FICL_DICT
*pd
= vmGetDict(pVM
);
1545 vmCheckStack(pVM
, 1, 0);
1547 pStep
= (FICL_WORD
*)(stackPop(pVM
->pStack
).p
);
1548 if ((pStep
!= NULL
) && isAFiclWord(pd
, pStep
))
1549 ficlAddParseStep(pVM
->pSys
, pStep
);
1554 /**************************************************************************
1555 l i t e r a l P a r e n
1557 ** This is the runtime for (literal). It assumes that it is part of a colon
1558 ** definition, and that the next CELL contains a value to be pushed on the
1559 ** parameter stack at runtime. This code is compiled by "literal".
1561 **************************************************************************/
1563 static void literalParen(FICL_VM
*pVM
)
1566 vmCheckStack(pVM
, 0, 1);
1568 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1569 vmBranchRelative(pVM
, 1);
1573 static void twoLitParen(FICL_VM
*pVM
)
1576 vmCheckStack(pVM
, 0, 2);
1578 PUSHINT(*((FICL_INT
*)(pVM
->ip
)+1));
1579 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1580 vmBranchRelative(pVM
, 2);
1585 /**************************************************************************
1588 ** IMMEDIATE code for "literal". This function gets a value from the stack
1589 ** and compiles it into the dictionary preceded by the code for "(literal)".
1591 **************************************************************************/
1593 static void literalIm(FICL_VM
*pVM
)
1595 FICL_DICT
*dp
= vmGetDict(pVM
);
1596 assert(pVM
->pSys
->pLitParen
);
1598 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLitParen
));
1599 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1605 static void twoLiteralIm(FICL_VM
*pVM
)
1607 FICL_DICT
*dp
= vmGetDict(pVM
);
1608 assert(pVM
->pSys
->pTwoLitParen
);
1610 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTwoLitParen
));
1611 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1612 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1617 /**************************************************************************
1618 l o g i c a n d c o m p a r i s o n s
1620 **************************************************************************/
1622 static void zeroEquals(FICL_VM
*pVM
)
1626 vmCheckStack(pVM
, 1, 1);
1628 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) == 0);
1629 stackPush(pVM
->pStack
, c
);
1633 static void zeroLess(FICL_VM
*pVM
)
1637 vmCheckStack(pVM
, 1, 1);
1639 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) < 0);
1640 stackPush(pVM
->pStack
, c
);
1644 static void zeroGreater(FICL_VM
*pVM
)
1648 vmCheckStack(pVM
, 1, 1);
1650 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) > 0);
1651 stackPush(pVM
->pStack
, c
);
1655 static void isEqual(FICL_VM
*pVM
)
1660 vmCheckStack(pVM
, 2, 1);
1662 x
= stackPop(pVM
->pStack
);
1663 y
= stackPop(pVM
->pStack
);
1664 PUSHINT(FICL_BOOL(x
.i
== y
.i
));
1668 static void isLess(FICL_VM
*pVM
)
1672 vmCheckStack(pVM
, 2, 1);
1674 y
= stackPop(pVM
->pStack
);
1675 x
= stackPop(pVM
->pStack
);
1676 PUSHINT(FICL_BOOL(x
.i
< y
.i
));
1680 static void uIsLess(FICL_VM
*pVM
)
1684 vmCheckStack(pVM
, 2, 1);
1686 u2
= stackPopUNS(pVM
->pStack
);
1687 u1
= stackPopUNS(pVM
->pStack
);
1688 PUSHINT(FICL_BOOL(u1
< u2
));
1692 static void isGreater(FICL_VM
*pVM
)
1696 vmCheckStack(pVM
, 2, 1);
1698 y
= stackPop(pVM
->pStack
);
1699 x
= stackPop(pVM
->pStack
);
1700 PUSHINT(FICL_BOOL(x
.i
> y
.i
));
1704 static void bitwiseAnd(FICL_VM
*pVM
)
1708 vmCheckStack(pVM
, 2, 1);
1710 x
= stackPop(pVM
->pStack
);
1711 y
= stackPop(pVM
->pStack
);
1716 static void bitwiseOr(FICL_VM
*pVM
)
1720 vmCheckStack(pVM
, 2, 1);
1722 x
= stackPop(pVM
->pStack
);
1723 y
= stackPop(pVM
->pStack
);
1728 static void bitwiseXor(FICL_VM
*pVM
)
1732 vmCheckStack(pVM
, 2, 1);
1734 x
= stackPop(pVM
->pStack
);
1735 y
= stackPop(pVM
->pStack
);
1740 static void bitwiseNot(FICL_VM
*pVM
)
1744 vmCheckStack(pVM
, 1, 1);
1746 x
= stackPop(pVM
->pStack
);
1752 /**************************************************************************
1754 ** do -- IMMEDIATE COMPILE ONLY
1755 ** Compiles code to initialize a loop: compile (do),
1756 ** allot space to hold the "leave" address, push a branch
1757 ** target address for the loop.
1758 ** (do) -- runtime for "do"
1759 ** pops index and limit from the p stack and moves them
1760 ** to the r stack, then skips to the loop body.
1761 ** loop -- IMMEDIATE COMPILE ONLY
1763 ** Compiles code for the test part of a loop:
1764 ** compile (loop), resolve forward branch from "do", and
1765 ** copy "here" address to the "leave" address allotted by "do"
1766 ** i,j,k -- COMPILE ONLY
1767 ** Runtime: Push loop indices on param stack (i is innermost loop...)
1768 ** Note: each loop has three values on the return stack:
1769 ** ( R: leave limit index )
1770 ** "leave" is the absolute address of the next cell after the loop
1771 ** limit and index are the loop control variables.
1772 ** leave -- COMPILE ONLY
1773 ** Runtime: pop the loop control variables, then pop the
1774 ** "leave" address and jump (absolute) there.
1775 **************************************************************************/
1777 static void doCoIm(FICL_VM
*pVM
)
1779 FICL_DICT
*dp
= vmGetDict(pVM
);
1781 assert(pVM
->pSys
->pDoParen
);
1783 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoParen
));
1785 ** Allot space for a pointer to the end
1786 ** of the loop - "leave" uses this...
1788 markBranch(dp
, pVM
, leaveTag
);
1789 dictAppendUNS(dp
, 0);
1791 ** Mark location of head of loop...
1793 markBranch(dp
, pVM
, doTag
);
1799 static void doParen(FICL_VM
*pVM
)
1803 vmCheckStack(pVM
, 2, 0);
1805 index
= stackPop(pVM
->pStack
);
1806 limit
= stackPop(pVM
->pStack
);
1808 /* copy "leave" target addr to stack */
1809 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
1810 stackPush(pVM
->rStack
, limit
);
1811 stackPush(pVM
->rStack
, index
);
1817 static void qDoCoIm(FICL_VM
*pVM
)
1819 FICL_DICT
*dp
= vmGetDict(pVM
);
1821 assert(pVM
->pSys
->pQDoParen
);
1823 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pQDoParen
));
1825 ** Allot space for a pointer to the end
1826 ** of the loop - "leave" uses this...
1828 markBranch(dp
, pVM
, leaveTag
);
1829 dictAppendUNS(dp
, 0);
1831 ** Mark location of head of loop...
1833 markBranch(dp
, pVM
, doTag
);
1839 static void qDoParen(FICL_VM
*pVM
)
1843 vmCheckStack(pVM
, 2, 0);
1845 index
= stackPop(pVM
->pStack
);
1846 limit
= stackPop(pVM
->pStack
);
1848 /* copy "leave" target addr to stack */
1849 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
1851 if (limit
.u
== index
.u
)
1857 stackPush(pVM
->rStack
, limit
);
1858 stackPush(pVM
->rStack
, index
);
1866 ** Runtime code to break out of a do..loop construct
1867 ** Drop the loop control variables; the branch address
1868 ** past "loop" is next on the return stack.
1870 static void leaveCo(FICL_VM
*pVM
)
1873 stackDrop(pVM
->rStack
, 2);
1880 static void unloopCo(FICL_VM
*pVM
)
1882 stackDrop(pVM
->rStack
, 3);
1887 static void loopCoIm(FICL_VM
*pVM
)
1889 FICL_DICT
*dp
= vmGetDict(pVM
);
1891 assert(pVM
->pSys
->pLoopParen
);
1893 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLoopParen
));
1894 resolveBackBranch(dp
, pVM
, doTag
);
1895 resolveAbsBranch(dp
, pVM
, leaveTag
);
1900 static void plusLoopCoIm(FICL_VM
*pVM
)
1902 FICL_DICT
*dp
= vmGetDict(pVM
);
1904 assert(pVM
->pSys
->pPLoopParen
);
1906 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pPLoopParen
));
1907 resolveBackBranch(dp
, pVM
, doTag
);
1908 resolveAbsBranch(dp
, pVM
, leaveTag
);
1913 static void loopParen(FICL_VM
*pVM
)
1915 FICL_INT index
= stackGetTop(pVM
->rStack
).i
;
1916 FICL_INT limit
= stackFetch(pVM
->rStack
, 1).i
;
1922 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
1923 vmBranchRelative(pVM
, 1); /* fall through the loop */
1926 { /* update index, branch to loop head */
1927 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
1928 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1935 static void plusLoopParen(FICL_VM
*pVM
)
1937 FICL_INT index
,limit
,increment
;
1941 vmCheckStack(pVM
, 1, 0);
1944 index
= stackGetTop(pVM
->rStack
).i
;
1945 limit
= stackFetch(pVM
->rStack
, 1).i
;
1946 increment
= POP().i
;
1951 flag
= (index
< limit
);
1953 flag
= (index
>= limit
);
1957 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
1958 vmBranchRelative(pVM
, 1); /* fall through the loop */
1961 { /* update index, branch to loop head */
1962 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
1963 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1970 static void loopICo(FICL_VM
*pVM
)
1972 CELL index
= stackGetTop(pVM
->rStack
);
1973 stackPush(pVM
->pStack
, index
);
1979 static void loopJCo(FICL_VM
*pVM
)
1981 CELL index
= stackFetch(pVM
->rStack
, 3);
1982 stackPush(pVM
->pStack
, index
);
1988 static void loopKCo(FICL_VM
*pVM
)
1990 CELL index
= stackFetch(pVM
->rStack
, 6);
1991 stackPush(pVM
->pStack
, index
);
1997 /**************************************************************************
1998 r e t u r n s t a c k
2000 **************************************************************************/
2001 static void toRStack(FICL_VM
*pVM
)
2004 vmCheckStack(pVM
, 1, 0);
2007 stackPush(pVM
->rStack
, POP());
2010 static void fromRStack(FICL_VM
*pVM
)
2013 vmCheckStack(pVM
, 0, 1);
2016 PUSH(stackPop(pVM
->rStack
));
2019 static void fetchRStack(FICL_VM
*pVM
)
2022 vmCheckStack(pVM
, 0, 1);
2025 PUSH(stackGetTop(pVM
->rStack
));
2028 static void twoToR(FICL_VM
*pVM
)
2031 vmCheckStack(pVM
, 2, 0);
2033 stackRoll(pVM
->pStack
, 1);
2034 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2035 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2039 static void twoRFrom(FICL_VM
*pVM
)
2042 vmCheckStack(pVM
, 0, 2);
2044 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2045 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2046 stackRoll(pVM
->pStack
, 1);
2050 static void twoRFetch(FICL_VM
*pVM
)
2053 vmCheckStack(pVM
, 0, 2);
2055 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 1));
2056 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 0));
2061 /**************************************************************************
2064 **************************************************************************/
2066 static void variableParen(FICL_VM
*pVM
)
2070 vmCheckStack(pVM
, 0, 1);
2073 fw
= pVM
->runningWord
;
2078 static void variable(FICL_VM
*pVM
)
2080 FICL_DICT
*dp
= vmGetDict(pVM
);
2081 STRINGINFO si
= vmGetWord(pVM
);
2083 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2084 dictAllotCells(dp
, 1);
2089 static void twoVariable(FICL_VM
*pVM
)
2091 FICL_DICT
*dp
= vmGetDict(pVM
);
2092 STRINGINFO si
= vmGetWord(pVM
);
2094 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2095 dictAllotCells(dp
, 2);
2100 /**************************************************************************
2101 b a s e & f r i e n d s
2103 **************************************************************************/
2105 static void base(FICL_VM
*pVM
)
2109 vmCheckStack(pVM
, 0, 1);
2112 pBase
= (CELL
*)(&pVM
->base
);
2113 stackPush(pVM
->pStack
, LVALUEtoCELL(pBase
));
2118 static void decimal(FICL_VM
*pVM
)
2125 static void hex(FICL_VM
*pVM
)
2132 /**************************************************************************
2133 a l l o t & f r i e n d s
2135 **************************************************************************/
2137 static void allot(FICL_VM
*pVM
)
2142 vmCheckStack(pVM
, 1, 0);
2145 dp
= vmGetDict(pVM
);
2149 dictCheck(dp
, pVM
, i
);
2157 static void here(FICL_VM
*pVM
)
2161 vmCheckStack(pVM
, 0, 1);
2164 dp
= vmGetDict(pVM
);
2169 static void comma(FICL_VM
*pVM
)
2174 vmCheckStack(pVM
, 1, 0);
2177 dp
= vmGetDict(pVM
);
2179 dictAppendCell(dp
, c
);
2183 static void cComma(FICL_VM
*pVM
)
2188 vmCheckStack(pVM
, 1, 0);
2191 dp
= vmGetDict(pVM
);
2193 dictAppendChar(dp
, c
);
2197 static void cells(FICL_VM
*pVM
)
2201 vmCheckStack(pVM
, 1, 1);
2205 PUSHINT(i
* (FICL_INT
)sizeof (CELL
));
2209 static void cellPlus(FICL_VM
*pVM
)
2213 vmCheckStack(pVM
, 1, 1);
2217 PUSHPTR(cp
+ sizeof (CELL
));
2223 /**************************************************************************
2225 ** tick CORE ( "<spaces>name" -- xt )
2226 ** Skip leading space delimiters. Parse name delimited by a space. Find
2227 ** name and return xt, the execution token for name. An ambiguous condition
2228 ** exists if name is not found.
2229 **************************************************************************/
2230 void ficlTick(FICL_VM
*pVM
)
2232 FICL_WORD
*pFW
= NULL
;
2233 STRINGINFO si
= vmGetWord(pVM
);
2235 vmCheckStack(pVM
, 0, 1);
2238 pFW
= dictLookup(vmGetDict(pVM
), si
);
2241 int i
= SI_COUNT(si
);
2242 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
2249 static void bracketTickCoIm(FICL_VM
*pVM
)
2258 /**************************************************************************
2260 ** Lookup the next word in the input stream and compile code to
2261 ** insert it into definitions created by the resulting word
2262 ** (defers compilation, even of immediate words)
2263 **************************************************************************/
2265 static void postponeCoIm(FICL_VM
*pVM
)
2267 FICL_DICT
*dp
= vmGetDict(pVM
);
2269 FICL_WORD
*pComma
= ficlLookup(pVM
->pSys
, ",");
2273 pFW
= stackGetTop(pVM
->pStack
).p
;
2274 if (wordIsImmediate(pFW
))
2276 dictAppendCell(dp
, stackPop(pVM
->pStack
));
2281 dictAppendCell(dp
, LVALUEtoCELL(pComma
));
2289 /**************************************************************************
2291 ** Pop an execution token (pointer to a word) off the stack and
2293 **************************************************************************/
2295 static void execute(FICL_VM
*pVM
)
2299 vmCheckStack(pVM
, 1, 0);
2302 pFW
= stackPopPtr(pVM
->pStack
);
2303 vmExecute(pVM
, pFW
);
2309 /**************************************************************************
2311 ** Make the most recently compiled word IMMEDIATE -- it executes even
2312 ** in compile state (most often used for control compiling words
2313 ** such as IF, THEN, etc)
2314 **************************************************************************/
2316 static void immediate(FICL_VM
*pVM
)
2319 dictSetImmediate(vmGetDict(pVM
));
2324 static void compileOnly(FICL_VM
*pVM
)
2327 dictSetFlags(vmGetDict(pVM
), FW_COMPILE
, 0);
2332 static void setObjectFlag(FICL_VM
*pVM
)
2335 dictSetFlags(vmGetDict(pVM
), FW_ISOBJECT
, 0);
2339 static void isObject(FICL_VM
*pVM
)
2342 FICL_WORD
*pFW
= (FICL_WORD
*)stackPopPtr(pVM
->pStack
);
2344 flag
= ((pFW
!= NULL
) && (pFW
->flags
& FW_ISOBJECT
)) ? FICL_TRUE
: FICL_FALSE
;
2345 stackPushINT(pVM
->pStack
, flag
);
2349 static void cstringLit(FICL_VM
*pVM
)
2351 FICL_STRING
*sp
= (FICL_STRING
*)(pVM
->ip
);
2353 char *cp
= sp
->text
;
2354 cp
+= sp
->count
+ 1;
2356 pVM
->ip
= (IPTYPE
)(void *)cp
;
2358 stackPushPtr(pVM
->pStack
, sp
);
2363 static void cstringQuoteIm(FICL_VM
*pVM
)
2365 FICL_DICT
*dp
= vmGetDict(pVM
);
2367 if (pVM
->state
== INTERPRET
)
2369 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
2370 vmGetString(pVM
, sp
, '\"');
2371 stackPushPtr(pVM
->pStack
, sp
);
2372 /* move HERE past string so it doesn't get overwritten. --lch */
2373 dictAllot(dp
, sp
->count
+ sizeof(FICL_COUNT
));
2375 else /* COMPILE state */
2377 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pCStringLit
));
2378 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2385 /**************************************************************************
2387 ** IMMEDIATE word that compiles a string literal for later display
2388 ** Compile stringLit, then copy the bytes of the string from the TIB
2389 ** to the dictionary. Backpatch the count byte and align the dictionary.
2391 ** stringlit: Fetch the count from the dictionary, then push the address
2392 ** and count on the stack. Finally, update ip to point to the first
2393 ** aligned address after the string text.
2394 **************************************************************************/
2396 static void stringLit(FICL_VM
*pVM
)
2402 vmCheckStack(pVM
, 0, 2);
2405 sp
= (FICL_STRING
*)(pVM
->ip
);
2412 pVM
->ip
= (IPTYPE
)(void *)cp
;
2415 static void dotQuoteCoIm(FICL_VM
*pVM
)
2417 FICL_DICT
*dp
= vmGetDict(pVM
);
2418 FICL_WORD
*pType
= ficlLookup(pVM
->pSys
, "type");
2420 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2421 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2423 dictAppendCell(dp
, LVALUEtoCELL(pType
));
2428 static void dotParen(FICL_VM
*pVM
)
2430 char *pSrc
= vmGetInBuf(pVM
);
2431 char *pEnd
= vmGetInBufEnd(pVM
);
2432 char *pDest
= pVM
->pad
;
2436 ** Note: the standard does not want leading spaces skipped (apparently)
2438 for (ch
= *pSrc
; (pEnd
!= pSrc
) && (ch
!= ')'); ch
= *++pSrc
)
2442 if ((pEnd
!= pSrc
) && (ch
== ')'))
2445 vmTextOut(pVM
, pVM
->pad
, 0);
2446 vmUpdateTib(pVM
, pSrc
);
2452 /**************************************************************************
2455 ** Interpretation: Interpretation semantics for this word are undefined.
2456 ** Compilation: ( c-addr1 u -- )
2457 ** Append the run-time semantics given below to the current definition.
2458 ** Run-time: ( -- c-addr2 u )
2459 ** Return c-addr2 u describing a string consisting of the characters
2460 ** specified by c-addr1 u during compilation. A program shall not alter
2461 ** the returned string.
2462 **************************************************************************/
2463 static void sLiteralCoIm(FICL_VM
*pVM
)
2470 vmCheckStack(pVM
, 2, 0);
2473 dp
= vmGetDict(pVM
);
2477 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2478 cpDest
= (char *) dp
->here
;
2479 *cpDest
++ = (char) u
;
2487 dp
->here
= PTRtoCELL
alignPtr(cpDest
);
2492 /**************************************************************************
2494 ** Return the address of the VM's state member (must be sized the
2495 ** same as a CELL for this reason)
2496 **************************************************************************/
2497 static void state(FICL_VM
*pVM
)
2500 vmCheckStack(pVM
, 0, 1);
2502 PUSHPTR(&pVM
->state
);
2507 /**************************************************************************
2508 c r e a t e . . . d o e s >
2509 ** Make a new word in the dictionary with the run-time effect of
2510 ** a variable (push my address), but with extra space allotted
2511 ** for use by does> .
2512 **************************************************************************/
2514 static void createParen(FICL_VM
*pVM
)
2519 vmCheckStack(pVM
, 0, 1);
2522 pCell
= pVM
->runningWord
->param
;
2528 static void create(FICL_VM
*pVM
)
2530 FICL_DICT
*dp
= vmGetDict(pVM
);
2531 STRINGINFO si
= vmGetWord(pVM
);
2533 dictCheckThreshold(dp
);
2535 dictAppendWord2(dp
, si
, createParen
, FW_DEFAULT
);
2536 dictAllotCells(dp
, 1);
2541 static void doDoes(FICL_VM
*pVM
)
2546 vmCheckStack(pVM
, 0, 1);
2549 pCell
= pVM
->runningWord
->param
;
2550 tempIP
= (IPTYPE
)((*pCell
).p
);
2552 vmPushIP(pVM
, tempIP
);
2557 static void doesParen(FICL_VM
*pVM
)
2559 FICL_DICT
*dp
= vmGetDict(pVM
);
2560 dp
->smudge
->code
= doDoes
;
2561 dp
->smudge
->param
[0] = LVALUEtoCELL(pVM
->ip
);
2567 static void doesCoIm(FICL_VM
*pVM
)
2569 FICL_DICT
*dp
= vmGetDict(pVM
);
2570 #if FICL_WANT_LOCALS
2571 assert(pVM
->pSys
->pUnLinkParen
);
2572 if (pVM
->pSys
->nLocals
> 0)
2574 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
2575 dictEmpty(pLoc
, pLoc
->pForthWords
->size
);
2576 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
2579 pVM
->pSys
->nLocals
= 0;
2583 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoesParen
));
2588 /**************************************************************************
2590 ** to-body CORE ( xt -- a-addr )
2591 ** a-addr is the data-field address corresponding to xt. An ambiguous
2592 ** condition exists if xt is not for a word defined via CREATE.
2593 **************************************************************************/
2594 static void toBody(FICL_VM
*pVM
)
2597 /*#$-GUY CHANGE: Added robustness.-$#*/
2599 vmCheckStack(pVM
, 1, 1);
2603 PUSHPTR(pFW
->param
+ 1);
2609 ** from-body ficl ( a-addr -- xt )
2610 ** Reverse effect of >body
2612 static void fromBody(FICL_VM
*pVM
)
2616 vmCheckStack(pVM
, 1, 1);
2619 ptr
= (char *)POPPTR() - sizeof (FICL_WORD
);
2626 ** >name ficl ( xt -- c-addr u )
2627 ** Push the address and length of a word's name given its address
2630 static void toName(FICL_VM
*pVM
)
2634 vmCheckStack(pVM
, 1, 2);
2639 PUSHUNS(pFW
->nName
);
2644 static void getLastWord(FICL_VM
*pVM
)
2646 FICL_DICT
*pDict
= vmGetDict(pVM
);
2647 FICL_WORD
*wp
= pDict
->smudge
;
2649 vmPush(pVM
, LVALUEtoCELL(wp
));
2654 /**************************************************************************
2655 l b r a c k e t e t c
2657 **************************************************************************/
2659 static void lbracketCoIm(FICL_VM
*pVM
)
2661 pVM
->state
= INTERPRET
;
2666 static void rbracket(FICL_VM
*pVM
)
2668 pVM
->state
= COMPILE
;
2673 /**************************************************************************
2674 p i c t u r e d n u m e r i c w o r d s
2676 ** less-number-sign CORE ( -- )
2677 ** Initialize the pictured numeric output conversion process.
2679 **************************************************************************/
2680 static void lessNumberSign(FICL_VM
*pVM
)
2682 FICL_STRING
*sp
= PTRtoSTRING pVM
->pad
;
2688 ** number-sign CORE ( ud1 -- ud2 )
2689 ** Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
2690 ** n. (n is the least-significant digit of ud1.) Convert n to external form
2691 ** and add the resulting character to the beginning of the pictured numeric
2692 ** output string. An ambiguous condition exists if # executes outside of a
2693 ** <# #> delimited number conversion.
2695 static void numberSign(FICL_VM
*pVM
)
2701 vmCheckStack(pVM
, 2, 2);
2704 sp
= PTRtoSTRING pVM
->pad
;
2705 u
= u64Pop(pVM
->pStack
);
2706 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2707 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2708 u64Push(pVM
->pStack
, u
);
2713 ** number-sign-greater CORE ( xd -- c-addr u )
2714 ** Drop xd. Make the pictured numeric output string available as a character
2715 ** string. c-addr and u specify the resulting character string. A program
2716 ** may replace characters within the string.
2718 static void numberSignGreater(FICL_VM
*pVM
)
2722 vmCheckStack(pVM
, 2, 2);
2725 sp
= PTRtoSTRING pVM
->pad
;
2726 sp
->text
[sp
->count
] = 0;
2735 ** number-sign-s CORE ( ud1 -- ud2 )
2736 ** Convert one digit of ud1 according to the rule for #. Continue conversion
2737 ** until the quotient is zero. ud2 is zero. An ambiguous condition exists if
2738 ** #S executes outside of a <# #> delimited number conversion.
2739 ** TO DO: presently does not use ud1 hi cell - use it!
2741 static void numberSignS(FICL_VM
*pVM
)
2747 vmCheckStack(pVM
, 2, 2);
2750 sp
= PTRtoSTRING pVM
->pad
;
2751 u
= u64Pop(pVM
->pStack
);
2755 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2756 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2758 while (u
.hi
|| u
.lo
);
2760 u64Push(pVM
->pStack
, u
);
2765 ** HOLD CORE ( char -- )
2766 ** Add char to the beginning of the pictured numeric output string. An ambiguous
2767 ** condition exists if HOLD executes outside of a <# #> delimited number conversion.
2769 static void hold(FICL_VM
*pVM
)
2774 vmCheckStack(pVM
, 1, 0);
2777 sp
= PTRtoSTRING pVM
->pad
;
2779 sp
->text
[sp
->count
++] = (char) i
;
2784 ** SIGN CORE ( n -- )
2785 ** If n is negative, add a minus sign to the beginning of the pictured
2786 ** numeric output string. An ambiguous condition exists if SIGN
2787 ** executes outside of a <# #> delimited number conversion.
2789 static void sign(FICL_VM
*pVM
)
2794 vmCheckStack(pVM
, 1, 0);
2797 sp
= PTRtoSTRING pVM
->pad
;
2800 sp
->text
[sp
->count
++] = '-';
2805 /**************************************************************************
2807 ** to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
2808 ** ud2 is the unsigned result of converting the characters within the
2809 ** string specified by c-addr1 u1 into digits, using the number in BASE,
2810 ** and adding each into ud1 after multiplying ud1 by the number in BASE.
2811 ** Conversion continues left-to-right until a character that is not
2812 ** convertible, including any + or -, is encountered or the string is
2813 ** entirely converted. c-addr2 is the location of the first unconverted
2814 ** character or the first character past the end of the string if the string
2815 ** was entirely converted. u2 is the number of unconverted characters in the
2816 ** string. An ambiguous condition exists if ud2 overflows during the
2818 **************************************************************************/
2819 static void toNumber(FICL_VM
*pVM
)
2824 FICL_UNS base
= pVM
->base
;
2829 vmCheckStack(pVM
,4,4);
2833 cp
= (char *)POPPTR();
2834 accum
= u64Pop(pVM
->pStack
);
2836 for (ch
= *cp
; count
> 0; ch
= *++cp
, count
--)
2844 digit
= tolower(ch
) - 'a' + 10;
2846 ** Note: following test also catches chars between 9 and a
2847 ** because 'digit' is unsigned!
2852 accum
= m64Mac(accum
, base
, digit
);
2855 u64Push(pVM
->pStack
, accum
);
2864 /**************************************************************************
2866 ** quit CORE ( -- ) ( R: i*x -- )
2867 ** Empty the return stack, store zero in SOURCE-ID if it is present, make
2868 ** the user input device the input source, and enter interpretation state.
2869 ** Do not display a message. Repeat the following:
2871 ** Accept a line from the input source into the input buffer, set >IN to
2872 ** zero, and interpret.
2873 ** Display the implementation-defined system prompt if in
2874 ** interpretation state, all processing has been completed, and no
2875 ** ambiguous condition exists.
2876 **************************************************************************/
2878 static void quit(FICL_VM
*pVM
)
2880 vmThrow(pVM
, VM_QUIT
);
2885 static void ficlAbort(FICL_VM
*pVM
)
2887 vmThrow(pVM
, VM_ABORT
);
2892 /**************************************************************************
2894 ** accept CORE ( c-addr +n1 -- +n2 )
2895 ** Receive a string of at most +n1 characters. An ambiguous condition
2896 ** exists if +n1 is zero or greater than 32,767. Display graphic characters
2897 ** as they are received. A program that depends on the presence or absence
2898 ** of non-graphic characters in the string has an environmental dependency.
2899 ** The editing functions, if any, that the system performs in order to
2900 ** construct the string are implementation-defined.
2902 ** (Although the standard text doesn't say so, I assume that the intent
2903 ** of 'accept' is to store the string at the address specified on
2905 ** Implementation: if there's more text in the TIB, use it. Otherwise
2906 ** throw out for more text. Copy characters up to the max count into the
2907 ** address given, and return the number of actual characters copied.
2909 ** Note (sobral) this may not be the behavior you'd expect if you're
2910 ** trying to get user input at load time!
2911 **************************************************************************/
2912 static void accept(FICL_VM
*pVM
)
2914 FICL_UNS count
, len
;
2919 vmCheckStack(pVM
,2,1);
2922 pBuf
= vmGetInBuf(pVM
);
2923 pEnd
= vmGetInBufEnd(pVM
);
2926 vmThrow(pVM
, VM_RESTART
);
2929 ** Now we have something in the text buffer - use it
2931 count
= stackPopINT(pVM
->pStack
);
2932 cp
= stackPopPtr(pVM
->pStack
);
2934 len
= (count
< len
) ? count
: len
;
2935 strncpy(cp
, vmGetInBuf(pVM
), len
);
2937 vmUpdateTib(pVM
, pBuf
);
2944 /**************************************************************************
2946 ** 6.1.0705 ALIGN CORE ( -- )
2947 ** If the data-space pointer is not aligned, reserve enough space to
2949 **************************************************************************/
2950 static void align(FICL_VM
*pVM
)
2952 FICL_DICT
*dp
= vmGetDict(pVM
);
2959 /**************************************************************************
2962 **************************************************************************/
2963 static void aligned(FICL_VM
*pVM
)
2967 vmCheckStack(pVM
,1,1);
2971 PUSHPTR(alignPtr(addr
));
2976 /**************************************************************************
2977 b e g i n & f r i e n d s
2978 ** Indefinite loop control structures
2981 ** : X ... BEGIN ... test UNTIL ;
2983 ** : X ... BEGIN ... test WHILE ... REPEAT ;
2984 **************************************************************************/
2985 static void beginCoIm(FICL_VM
*pVM
)
2987 FICL_DICT
*dp
= vmGetDict(pVM
);
2988 markBranch(dp
, pVM
, destTag
);
2992 static void untilCoIm(FICL_VM
*pVM
)
2994 FICL_DICT
*dp
= vmGetDict(pVM
);
2996 assert(pVM
->pSys
->pIfParen
);
2998 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pIfParen
));
2999 resolveBackBranch(dp
, pVM
, destTag
);
3003 static void whileCoIm(FICL_VM
*pVM
)
3005 FICL_DICT
*dp
= vmGetDict(pVM
);
3007 assert(pVM
->pSys
->pIfParen
);
3009 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pIfParen
));
3010 markBranch(dp
, pVM
, origTag
);
3012 dictAppendUNS(dp
, 1);
3016 static void repeatCoIm(FICL_VM
*pVM
)
3018 FICL_DICT
*dp
= vmGetDict(pVM
);
3020 assert(pVM
->pSys
->pBranchParen
);
3021 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3023 /* expect "begin" branch marker */
3024 resolveBackBranch(dp
, pVM
, destTag
);
3025 /* expect "while" branch marker */
3026 resolveForwardBranch(dp
, pVM
, origTag
);
3031 static void againCoIm(FICL_VM
*pVM
)
3033 FICL_DICT
*dp
= vmGetDict(pVM
);
3035 assert(pVM
->pSys
->pBranchParen
);
3036 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3038 /* expect "begin" branch marker */
3039 resolveBackBranch(dp
, pVM
, destTag
);
3044 /**************************************************************************
3045 c h a r & f r i e n d s
3046 ** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
3047 ** Skip leading space delimiters. Parse name delimited by a space.
3048 ** Put the value of its first character onto the stack.
3050 ** bracket-char CORE
3051 ** Interpretation: Interpretation semantics for this word are undefined.
3052 ** Compilation: ( "<spaces>name" -- )
3053 ** Skip leading space delimiters. Parse name delimited by a space.
3054 ** Append the run-time semantics given below to the current definition.
3055 ** Run-time: ( -- char )
3056 ** Place char, the value of the first character of name, on the stack.
3057 **************************************************************************/
3058 static void ficlChar(FICL_VM
*pVM
)
3062 vmCheckStack(pVM
,0,1);
3065 si
= vmGetWord(pVM
);
3066 PUSHUNS((FICL_UNS
)(si
.cp
[0]));
3070 static void charCoIm(FICL_VM
*pVM
)
3077 /**************************************************************************
3079 ** char-plus CORE ( c-addr1 -- c-addr2 )
3080 ** Add the size in address units of a character to c-addr1, giving c-addr2.
3081 **************************************************************************/
3082 static void charPlus(FICL_VM
*pVM
)
3086 vmCheckStack(pVM
,1,1);
3094 /**************************************************************************
3096 ** chars CORE ( n1 -- n2 )
3097 ** n2 is the size in address units of n1 characters.
3098 ** For most processors, this function can be a no-op. To guarantee
3099 ** portability, we'll multiply by sizeof (char).
3100 **************************************************************************/
3101 #if defined (_M_IX86)
3102 #pragma warning(disable: 4127)
3104 static void ficlChars(FICL_VM
*pVM
)
3106 if (sizeof (char) > 1)
3110 vmCheckStack(pVM
,1,1);
3113 PUSHINT(i
* sizeof (char));
3115 /* otherwise no-op! */
3118 #if defined (_M_IX86)
3119 #pragma warning(default: 4127)
3123 /**************************************************************************
3125 ** COUNT CORE ( c-addr1 -- c-addr2 u )
3126 ** Return the character string specification for the counted string stored
3127 ** at c-addr1. c-addr2 is the address of the first character after c-addr1.
3128 ** u is the contents of the character at c-addr1, which is the length in
3129 ** characters of the string at c-addr2.
3130 **************************************************************************/
3131 static void count(FICL_VM
*pVM
)
3135 vmCheckStack(pVM
,1,2);
3144 /**************************************************************************
3145 e n v i r o n m e n t ?
3146 ** environment-query CORE ( c-addr u -- false | i*x true )
3147 ** c-addr is the address of a character string and u is the string's
3148 ** character count. u may have a value in the range from zero to an
3149 ** implementation-defined maximum which shall not be less than 31. The
3150 ** character string should contain a keyword from 3.2.6 Environmental
3151 ** queries or the optional word sets to be checked for correspondence
3152 ** with an attribute of the present environment. If the system treats the
3153 ** attribute as unknown, the returned flag is false; otherwise, the flag
3154 ** is true and the i*x returned is of the type specified in the table for
3155 ** the attribute queried.
3156 **************************************************************************/
3157 static void environmentQ(FICL_VM
*pVM
)
3163 vmCheckStack(pVM
,2,1);
3166 envp
= pVM
->pSys
->envp
;
3167 si
.count
= (FICL_COUNT
)stackPopUNS(pVM
->pStack
);
3168 si
.cp
= stackPopPtr(pVM
->pStack
);
3170 pFW
= dictLookup(envp
, si
);
3174 vmExecute(pVM
, pFW
);
3179 PUSHINT(FICL_FALSE
);
3184 /**************************************************************************
3186 ** EVALUATE CORE ( i*x c-addr u -- j*x )
3187 ** Save the current input source specification. Store minus-one (-1) in
3188 ** SOURCE-ID if it is present. Make the string described by c-addr and u
3189 ** both the input source and input buffer, set >IN to zero, and interpret.
3190 ** When the parse area is empty, restore the prior input source
3191 ** specification. Other stack effects are due to the words EVALUATEd.
3193 **************************************************************************/
3194 static void evaluate(FICL_VM
*pVM
)
3201 vmCheckStack(pVM
,2,0);
3209 pVM
->sourceID
.i
= -1;
3210 result
= ficlExecC(pVM
, cp
, count
);
3212 if (result
!= VM_OUTOFTEXT
)
3213 vmThrow(pVM
, result
);
3219 /**************************************************************************
3220 s t r i n g q u o t e
3221 ** Interpreting: get string delimited by a quote from the input stream,
3222 ** copy to a scratch area, and put its count and address on the stack.
3223 ** Compiling: compile code to push the address and count of a string
3224 ** literal, compile the string from the input stream, and align the dict
3226 **************************************************************************/
3227 static void stringQuoteIm(FICL_VM
*pVM
)
3229 FICL_DICT
*dp
= vmGetDict(pVM
);
3231 if (pVM
->state
== INTERPRET
)
3233 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
3234 vmGetString(pVM
, sp
, '\"');
3238 else /* COMPILE state */
3240 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
3241 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
3249 /**************************************************************************
3251 ** Pop count and char address from stack and print the designated string.
3252 **************************************************************************/
3253 static void type(FICL_VM
*pVM
)
3255 FICL_UNS count
= stackPopUNS(pVM
->pStack
);
3256 char *cp
= stackPopPtr(pVM
->pStack
);
3257 char *pDest
= (char *)ficlMalloc(count
+ 1);
3260 ** Since we don't have an output primitive for a counted string
3261 ** (oops), make sure the string is null terminated. If not, copy
3262 ** and terminate it.
3265 vmThrowErr(pVM
, "Error: out of memory");
3267 strncpy(pDest
, cp
, count
);
3268 pDest
[count
] = '\0';
3270 vmTextOut(pVM
, pDest
, 0);
3276 /**************************************************************************
3278 ** word CORE ( char "<chars>ccc<char>" -- c-addr )
3279 ** Skip leading delimiters. Parse characters ccc delimited by char. An
3280 ** ambiguous condition exists if the length of the parsed string is greater
3281 ** than the implementation-defined length of a counted string.
3283 ** c-addr is the address of a transient region containing the parsed word
3284 ** as a counted string. If the parse area was empty or contained no
3285 ** characters other than the delimiter, the resulting string has a zero
3286 ** length. A space, not included in the length, follows the string. A
3287 ** program may replace characters within the string.
3288 ** NOTE! Ficl also NULL-terminates the dest string.
3289 **************************************************************************/
3290 static void ficlWord(FICL_VM
*pVM
)
3296 vmCheckStack(pVM
,1,1);
3299 sp
= (FICL_STRING
*)pVM
->pad
;
3300 delim
= (char)POPINT();
3301 si
= vmParseStringEx(pVM
, delim
, 1);
3303 if (SI_COUNT(si
) > nPAD
-1)
3304 SI_SETLEN(si
, nPAD
-1);
3306 sp
->count
= (FICL_COUNT
)SI_COUNT(si
);
3307 strncpy(sp
->text
, SI_PTR(si
), SI_COUNT(si
));
3308 /*#$-GUY CHANGE: I added this.-$#*/
3309 sp
->text
[sp
->count
] = 0;
3310 strcat(sp
->text
, " ");
3317 /**************************************************************************
3319 ** ficl PARSE-WORD ( <spaces>name -- c-addr u )
3320 ** Skip leading spaces and parse name delimited by a space. c-addr is the
3321 ** address within the input buffer and u is the length of the selected
3322 ** string. If the parse area is empty, the resulting string has a zero length.
3323 **************************************************************************/
3324 static void parseNoCopy(FICL_VM
*pVM
)
3328 vmCheckStack(pVM
,0,2);
3331 si
= vmGetWord0(pVM
);
3332 PUSHPTR(SI_PTR(si
));
3333 PUSHUNS(SI_COUNT(si
));
3338 /**************************************************************************
3340 ** CORE EXT ( char "ccc<char>" -- c-addr u )
3341 ** Parse ccc delimited by the delimiter char.
3342 ** c-addr is the address (within the input buffer) and u is the length of
3343 ** the parsed string. If the parse area was empty, the resulting string has
3345 ** NOTE! PARSE differs from WORD: it does not skip leading delimiters.
3346 **************************************************************************/
3347 static void parse(FICL_VM
*pVM
)
3353 vmCheckStack(pVM
,1,2);
3356 delim
= (char)POPINT();
3358 si
= vmParseStringEx(pVM
, delim
, 0);
3359 PUSHPTR(SI_PTR(si
));
3360 PUSHUNS(SI_COUNT(si
));
3365 /**************************************************************************
3367 ** CORE ( c-addr u char -- )
3368 ** If u is greater than zero, store char in each of u consecutive
3369 ** characters of memory beginning at c-addr.
3370 **************************************************************************/
3371 static void fill(FICL_VM
*pVM
)
3377 vmCheckStack(pVM
,3,0);
3379 ch
= (char)POPINT();
3381 cp
= (char *)POPPTR();
3392 /**************************************************************************
3394 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3395 ** Find the definition named in the counted string at c-addr. If the
3396 ** definition is not found, return c-addr and zero. If the definition is
3397 ** found, return its execution token xt. If the definition is immediate,
3398 ** also return one (1), otherwise also return minus-one (-1). For a given
3399 ** string, the values returned by FIND while compiling may differ from
3400 ** those returned while not compiling.
3401 **************************************************************************/
3402 static void do_find(FICL_VM
*pVM
, STRINGINFO si
, void *returnForFailure
)
3406 pFW
= dictLookup(vmGetDict(pVM
), si
);
3410 PUSHINT((wordIsImmediate(pFW
) ? 1 : -1));
3414 PUSHPTR(returnForFailure
);
3422 /**************************************************************************
3424 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3425 ** Find the definition named in the counted string at c-addr. If the
3426 ** definition is not found, return c-addr and zero. If the definition is
3427 ** found, return its execution token xt. If the definition is immediate,
3428 ** also return one (1), otherwise also return minus-one (-1). For a given
3429 ** string, the values returned by FIND while compiling may differ from
3430 ** those returned while not compiling.
3431 **************************************************************************/
3432 static void cFind(FICL_VM
*pVM
)
3438 vmCheckStack(pVM
,1,2);
3442 do_find(pVM
, si
, sp
);
3447 /**************************************************************************
3449 ** FICL ( c-addr u -- 0 0 | xt 1 | xt -1 )
3450 ** Like FIND, but takes "c-addr u" for the string.
3451 **************************************************************************/
3452 static void sFind(FICL_VM
*pVM
)
3457 vmCheckStack(pVM
,2,2);
3460 si
.count
= stackPopINT(pVM
->pStack
);
3461 si
.cp
= stackPopPtr(pVM
->pStack
);
3463 do_find(pVM
, si
, NULL
);
3468 /**************************************************************************
3470 ** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
3471 ** Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
3472 ** Input and output stack arguments are signed. An ambiguous condition
3473 ** exists if n1 is zero or if the quotient lies outside the range of a
3474 ** single-cell signed integer.
3475 **************************************************************************/
3476 static void fmSlashMod(FICL_VM
*pVM
)
3482 vmCheckStack(pVM
,3,2);
3486 d1
= i64Pop(pVM
->pStack
);
3487 qr
= m64FlooredDivI(d1
, n1
);
3494 /**************************************************************************
3496 ** s-m-slash-rem CORE ( d1 n1 -- n2 n3 )
3497 ** Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
3498 ** Input and output stack arguments are signed. An ambiguous condition
3499 ** exists if n1 is zero or if the quotient lies outside the range of a
3500 ** single-cell signed integer.
3501 **************************************************************************/
3502 static void smSlashRem(FICL_VM
*pVM
)
3508 vmCheckStack(pVM
,3,2);
3512 d1
= i64Pop(pVM
->pStack
);
3513 qr
= m64SymmetricDivI(d1
, n1
);
3520 static void ficlMod(FICL_VM
*pVM
)
3526 vmCheckStack(pVM
,2,1);
3532 qr
= m64SymmetricDivI(d1
, n1
);
3538 /**************************************************************************
3540 ** u-m-slash-mod CORE ( ud u1 -- u2 u3 )
3541 ** Divide ud by u1, giving the quotient u3 and the remainder u2.
3542 ** All values and arithmetic are unsigned. An ambiguous condition
3543 ** exists if u1 is zero or if the quotient lies outside the range of a
3544 ** single-cell unsigned integer.
3545 *************************************************************************/
3546 static void umSlashMod(FICL_VM
*pVM
)
3552 u1
= stackPopUNS(pVM
->pStack
);
3553 ud
= u64Pop(pVM
->pStack
);
3554 qr
= ficlLongDiv(ud
, u1
);
3561 /**************************************************************************
3563 ** l-shift CORE ( x1 u -- x2 )
3564 ** Perform a logical left shift of u bit-places on x1, giving x2.
3565 ** Put zeroes into the least significant bits vacated by the shift.
3566 ** An ambiguous condition exists if u is greater than or equal to the
3567 ** number of bits in a cell.
3569 ** r-shift CORE ( x1 u -- x2 )
3570 ** Perform a logical right shift of u bit-places on x1, giving x2.
3571 ** Put zeroes into the most significant bits vacated by the shift. An
3572 ** ambiguous condition exists if u is greater than or equal to the
3573 ** number of bits in a cell.
3574 **************************************************************************/
3575 static void lshift(FICL_VM
*pVM
)
3580 vmCheckStack(pVM
,2,1);
3585 PUSHUNS(x1
<< nBits
);
3590 static void rshift(FICL_VM
*pVM
)
3595 vmCheckStack(pVM
,2,1);
3601 PUSHUNS(x1
>> nBits
);
3606 /**************************************************************************
3608 ** m-star CORE ( n1 n2 -- d )
3609 ** d is the signed product of n1 times n2.
3610 **************************************************************************/
3611 static void mStar(FICL_VM
*pVM
)
3617 vmCheckStack(pVM
,2,2);
3623 d
= m64MulI(n1
, n2
);
3624 i64Push(pVM
->pStack
, d
);
3629 static void umStar(FICL_VM
*pVM
)
3635 vmCheckStack(pVM
,2,2);
3641 ud
= ficlLongMul(u1
, u2
);
3642 u64Push(pVM
->pStack
, ud
);
3647 /**************************************************************************
3650 **************************************************************************/
3651 static void ficlMax(FICL_VM
*pVM
)
3656 vmCheckStack(pVM
,2,1);
3662 PUSHINT((n1
> n2
) ? n1
: n2
);
3666 static void ficlMin(FICL_VM
*pVM
)
3671 vmCheckStack(pVM
,2,1);
3677 PUSHINT((n1
< n2
) ? n1
: n2
);
3682 /**************************************************************************
3684 ** CORE ( addr1 addr2 u -- )
3685 ** If u is greater than zero, copy the contents of u consecutive address
3686 ** units at addr1 to the u consecutive address units at addr2. After MOVE
3687 ** completes, the u consecutive address units at addr2 contain exactly
3688 ** what the u consecutive address units at addr1 contained before the move.
3689 ** NOTE! This implementation assumes that a char is the same size as
3691 **************************************************************************/
3692 static void move(FICL_VM
*pVM
)
3698 vmCheckStack(pVM
,3,0);
3708 ** Do the copy carefully, so as to be
3709 ** correct even if the two ranges overlap
3714 *addr2
++ = *addr1
++;
3721 *addr2
-- = *addr1
--;
3728 /**************************************************************************
3731 **************************************************************************/
3732 static void recurseCoIm(FICL_VM
*pVM
)
3734 FICL_DICT
*pDict
= vmGetDict(pVM
);
3737 dictAppendCell(pDict
, LVALUEtoCELL(pDict
->smudge
));
3742 /**************************************************************************
3744 ** s-to-d CORE ( n -- d )
3745 ** Convert the number n to the double-cell number d with the same
3747 **************************************************************************/
3748 static void sToD(FICL_VM
*pVM
)
3752 vmCheckStack(pVM
,1,2);
3757 /* sign extend to 64 bits.. */
3759 PUSHINT((s
< 0) ? -1 : 0);
3764 /**************************************************************************
3766 ** CORE ( -- c-addr u )
3767 ** c-addr is the address of, and u is the number of characters in, the
3769 **************************************************************************/
3770 static void source(FICL_VM
*pVM
)
3773 vmCheckStack(pVM
,0,2);
3775 PUSHPTR(pVM
->tib
.cp
);
3776 PUSHINT(vmGetInBufLen(pVM
));
3781 /**************************************************************************
3784 **************************************************************************/
3785 static void ficlVersion(FICL_VM
*pVM
)
3787 vmTextOut(pVM
, "ficl Version " FICL_VER
, 1);
3792 /**************************************************************************
3795 **************************************************************************/
3796 static void toIn(FICL_VM
*pVM
)
3799 vmCheckStack(pVM
,0,1);
3801 PUSHPTR(&pVM
->tib
.index
);
3806 /**************************************************************************
3807 c o l o n N o N a m e
3808 ** CORE EXT ( C: -- colon-sys ) ( S: -- xt )
3809 ** Create an unnamed colon definition and push its address.
3810 ** Change state to compile.
3811 **************************************************************************/
3812 static void colonNoName(FICL_VM
*pVM
)
3814 FICL_DICT
*dp
= vmGetDict(pVM
);
3819 SI_SETPTR(si
, NULL
);
3821 pVM
->state
= COMPILE
;
3822 pFW
= dictAppendWord2(dp
, si
, colonParen
, FW_DEFAULT
| FW_SMUDGE
);
3824 markControlTag(pVM
, colonTag
);
3829 /**************************************************************************
3830 u s e r V a r i a b l e
3831 ** user ( u -- ) "<spaces>name"
3832 ** Get a name from the input stream and create a user variable
3833 ** with the name and the index supplied. The run-time effect
3834 ** of a user variable is to push the address of the indexed cell
3835 ** in the running vm's user array.
3837 ** User variables are vm local cells. Each vm has an array of
3838 ** FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
3839 ** Ficl's user facility is implemented with two primitives,
3840 ** "user" and "(user)", a variable ("nUser") (in softcore.c) that
3841 ** holds the index of the next free user cell, and a redefinition
3842 ** (also in softcore) of "user" that defines a user word and increments
3844 **************************************************************************/
3846 static void userParen(FICL_VM
*pVM
)
3848 FICL_INT i
= pVM
->runningWord
->param
[0].i
;
3849 PUSHPTR(&pVM
->user
[i
]);
3854 static void userVariable(FICL_VM
*pVM
)
3856 FICL_DICT
*dp
= vmGetDict(pVM
);
3857 STRINGINFO si
= vmGetWord(pVM
);
3860 c
= stackPop(pVM
->pStack
);
3861 if (c
.i
>= FICL_USER_CELLS
)
3863 vmThrowErr(pVM
, "Error - out of user space");
3866 dictAppendWord2(dp
, si
, userParen
, FW_DEFAULT
);
3867 dictAppendCell(dp
, c
);
3873 /**************************************************************************
3876 ** Interpretation: ( x "<spaces>name" -- )
3877 ** Skip leading spaces and parse name delimited by a space. Store x in
3878 ** name. An ambiguous condition exists if name was not defined by VALUE.
3879 ** NOTE: In ficl, VALUE is an alias of CONSTANT
3880 **************************************************************************/
3881 static void toValue(FICL_VM
*pVM
)
3883 STRINGINFO si
= vmGetWord(pVM
);
3884 FICL_DICT
*dp
= vmGetDict(pVM
);
3887 #if FICL_WANT_LOCALS
3888 if ((pVM
->pSys
->nLocals
> 0) && (pVM
->state
== COMPILE
))
3890 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
3891 pFW
= dictLookup(pLoc
, si
);
3892 if (pFW
&& (pFW
->code
== doLocalIm
))
3894 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
3895 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
3898 else if (pFW
&& pFW
->code
== do2LocalIm
)
3900 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
3901 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
3907 assert(pVM
->pSys
->pStore
);
3909 pFW
= dictLookup(dp
, si
);
3912 int i
= SI_COUNT(si
);
3913 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
3916 if (pVM
->state
== INTERPRET
)
3917 pFW
->param
[0] = stackPop(pVM
->pStack
);
3918 else /* compile code to store to word's param */
3920 PUSHPTR(&pFW
->param
[0]);
3922 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStore
));
3928 #if FICL_WANT_LOCALS
3929 /**************************************************************************
3932 ** Link a frame on the return stack, reserving nCells of space for
3933 ** locals - the value of nCells is the next cell in the instruction
3935 **************************************************************************/
3936 static void linkParen(FICL_VM
*pVM
)
3938 FICL_INT nLink
= *(FICL_INT
*)(pVM
->ip
);
3939 vmBranchRelative(pVM
, 1);
3940 stackLink(pVM
->rStack
, nLink
);
3945 static void unlinkParen(FICL_VM
*pVM
)
3947 stackUnlink(pVM
->rStack
);
3952 /**************************************************************************
3954 ** Immediate - cfa of a local while compiling - when executed, compiles
3955 ** code to fetch the value of a local given the local's index in the
3957 **************************************************************************/
3958 static void getLocalParen(FICL_VM
*pVM
)
3960 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
3961 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
3966 static void toLocalParen(FICL_VM
*pVM
)
3968 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
3969 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
3974 static void getLocal0(FICL_VM
*pVM
)
3976 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[0]);
3981 static void toLocal0(FICL_VM
*pVM
)
3983 pVM
->rStack
->pFrame
[0] = stackPop(pVM
->pStack
);
3988 static void getLocal1(FICL_VM
*pVM
)
3990 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[1]);
3995 static void toLocal1(FICL_VM
*pVM
)
3997 pVM
->rStack
->pFrame
[1] = stackPop(pVM
->pStack
);
4003 ** Each local is recorded in a private locals dictionary as a
4004 ** word that does doLocalIm at runtime. DoLocalIm compiles code
4005 ** into the client definition to fetch the value of the
4006 ** corresponding local variable from the return stack.
4007 ** The private dictionary gets initialized at the end of each block
4008 ** that uses locals (in ; and does> for example).
4010 static void doLocalIm(FICL_VM
*pVM
)
4012 FICL_DICT
*pDict
= vmGetDict(pVM
);
4013 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4015 if (pVM
->state
== INTERPRET
)
4017 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4024 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal0
));
4026 else if (nLocal
== 1)
4028 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal1
));
4032 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocalParen
));
4033 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4040 /**************************************************************************
4042 ** paren-local-paren LOCAL
4043 ** Interpretation: Interpretation semantics for this word are undefined.
4044 ** Execution: ( c-addr u -- )
4045 ** When executed during compilation, (LOCAL) passes a message to the
4046 ** system that has one of two meanings. If u is non-zero,
4047 ** the message identifies a new local whose definition name is given by
4048 ** the string of characters identified by c-addr u. If u is zero,
4049 ** the message is last local and c-addr has no significance.
4051 ** The result of executing (LOCAL) during compilation of a definition is
4052 ** to create a set of named local identifiers, each of which is
4053 ** a definition name, that only have execution semantics within the scope
4054 ** of that definition's source.
4056 ** local Execution: ( -- x )
4058 ** Push the local's value, x, onto the stack. The local's value is
4059 ** initialized as described in 13.3.3 Processing locals and may be
4060 ** changed by preceding the local's name with TO. An ambiguous condition
4061 ** exists when local is executed while in interpretation state.
4062 **************************************************************************/
4063 static void localParen(FICL_VM
*pVM
)
4068 vmCheckStack(pVM
,2,0);
4071 pDict
= vmGetDict(pVM
);
4072 SI_SETLEN(si
, POPUNS());
4073 SI_SETPTR(si
, (char *)POPPTR());
4075 if (SI_COUNT(si
) > 0)
4076 { /* add a local to the **locals** dict and update nLocals */
4077 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4078 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4080 vmThrowErr(pVM
, "Error: out of local space");
4083 dictAppendWord2(pLoc
, si
, doLocalIm
, FW_COMPIMMED
);
4084 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4086 if (pVM
->pSys
->nLocals
== 0)
4087 { /* compile code to create a local stack frame */
4088 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4089 /* save location in dictionary for #locals */
4090 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4091 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4092 /* compile code to initialize first local */
4093 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal0
));
4095 else if (pVM
->pSys
->nLocals
== 1)
4097 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal1
));
4101 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
4102 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4105 (pVM
->pSys
->nLocals
)++;
4107 else if (pVM
->pSys
->nLocals
> 0)
4108 { /* write nLocals to (link) param area in dictionary */
4109 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4116 static void get2LocalParen(FICL_VM
*pVM
)
4118 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4119 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4120 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4125 static void do2LocalIm(FICL_VM
*pVM
)
4127 FICL_DICT
*pDict
= vmGetDict(pVM
);
4128 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4130 if (pVM
->state
== INTERPRET
)
4132 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4133 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4137 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGet2LocalParen
));
4138 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4144 static void to2LocalParen(FICL_VM
*pVM
)
4146 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4147 pVM
->rStack
->pFrame
[nLocal
+1] = stackPop(pVM
->pStack
);
4148 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
4153 static void twoLocalParen(FICL_VM
*pVM
)
4155 FICL_DICT
*pDict
= vmGetDict(pVM
);
4157 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
4158 SI_SETPTR(si
, (char *)stackPopPtr(pVM
->pStack
));
4160 if (SI_COUNT(si
) > 0)
4161 { /* add a local to the **locals** dict and update nLocals */
4162 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4163 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4165 vmThrowErr(pVM
, "Error: out of local space");
4168 dictAppendWord2(pLoc
, si
, do2LocalIm
, FW_COMPIMMED
);
4169 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4171 if (pVM
->pSys
->nLocals
== 0)
4172 { /* compile code to create a local stack frame */
4173 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4174 /* save location in dictionary for #locals */
4175 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4176 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4179 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
4180 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4182 pVM
->pSys
->nLocals
+= 2;
4184 else if (pVM
->pSys
->nLocals
> 0)
4185 { /* write nLocals to (link) param area in dictionary */
4186 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4194 /**************************************************************************
4196 ** STRING ( c-addr1 u1 c-addr2 u2 -- n )
4197 ** Compare the string specified by c-addr1 u1 to the string specified by
4198 ** c-addr2 u2. The strings are compared, beginning at the given addresses,
4199 ** character by character, up to the length of the shorter string or until a
4200 ** difference is found. If the two strings are identical, n is zero. If the two
4201 ** strings are identical up to the length of the shorter string, n is minus-one
4202 ** (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not
4203 ** identical up to the length of the shorter string, n is minus-one (-1) if the
4204 ** first non-matching character in the string specified by c-addr1 u1 has a
4205 ** lesser numeric value than the corresponding character in the string specified
4206 ** by c-addr2 u2 and one (1) otherwise.
4207 **************************************************************************/
4208 static void compareInternal(FICL_VM
*pVM
, int caseInsensitive
)
4211 FICL_UNS u1
, u2
, uMin
;
4214 vmCheckStack(pVM
, 4, 1);
4215 u2
= stackPopUNS(pVM
->pStack
);
4216 cp2
= (char *)stackPopPtr(pVM
->pStack
);
4217 u1
= stackPopUNS(pVM
->pStack
);
4218 cp1
= (char *)stackPopPtr(pVM
->pStack
);
4220 uMin
= (u1
< u2
)? u1
: u2
;
4221 for ( ; (uMin
> 0) && (n
== 0); uMin
--)
4225 if (caseInsensitive
)
4227 c1
= (char)tolower(c1
);
4228 c2
= (char)tolower(c2
);
4246 static void compareString(FICL_VM
*pVM
)
4248 compareInternal(pVM
, FALSE
);
4252 static void compareStringInsensitive(FICL_VM
*pVM
)
4254 compareInternal(pVM
, TRUE
);
4258 /**************************************************************************
4260 ** CORE EXT ( -- c-addr )
4261 ** c-addr is the address of a transient region that can be used to hold
4262 ** data for intermediate processing.
4263 **************************************************************************/
4264 static void pad(FICL_VM
*pVM
)
4266 stackPushPtr(pVM
->pStack
, pVM
->pad
);
4270 /**************************************************************************
4272 ** CORE EXT, FILE ( -- 0 | -1 | fileid )
4273 ** Identifies the input source as follows:
4275 ** SOURCE-ID Input source
4276 ** --------- ------------
4277 ** fileid Text file fileid
4278 ** -1 String (via EVALUATE)
4279 ** 0 User input device
4280 **************************************************************************/
4281 static void sourceid(FICL_VM
*pVM
)
4283 PUSHINT(pVM
->sourceID
.i
);
4288 /**************************************************************************
4290 ** CORE EXT ( -- flag )
4291 ** Attempt to fill the input buffer from the input source, returning a true
4292 ** flag if successful.
4293 ** When the input source is the user input device, attempt to receive input
4294 ** into the terminal input buffer. If successful, make the result the input
4295 ** buffer, set >IN to zero, and return true. Receipt of a line containing no
4296 ** characters is considered successful. If there is no input available from
4297 ** the current input source, return false.
4298 ** When the input source is a string from EVALUATE, return false and
4299 ** perform no other action.
4300 **************************************************************************/
4301 static void refill(FICL_VM
*pVM
)
4303 FICL_INT ret
= (pVM
->sourceID
.i
== -1) ? FICL_FALSE
: FICL_TRUE
;
4304 if (ret
&& (pVM
->fRestart
== 0))
4305 vmThrow(pVM
, VM_RESTART
);
4312 /**************************************************************************
4313 freebsd exception handling words
4314 ** Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
4315 ** the word in ToS. If an exception happens, restore the state to what
4316 ** it was before, and pushes the exception value on the stack. If not,
4319 ** Notice that Catch implements an inner interpreter. This is ugly,
4320 ** but given how ficl works, it cannot be helped. The problem is that
4321 ** colon definitions will be executed *after* the function returns,
4322 ** while "code" definitions will be executed immediately. I considered
4323 ** other solutions to this problem, but all of them shared the same
4324 ** basic problem (with added disadvantages): if ficl ever changes it's
4325 ** inner thread modus operandi, one would have to fix this word.
4327 ** More comments can be found throughout catch's code.
4329 ** Daniel C. Sobral Jan 09/1999
4330 ** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
4331 **************************************************************************/
4333 static void ficlCatch(FICL_VM
*pVM
)
4343 assert(pVM
->pSys
->pExitInner
);
4348 ** We need this *before* we save the stack pointer, or
4349 ** we'll have to pop one element out of the stack after
4350 ** an exception. I prefer to get done with it up front. :-)
4353 vmCheckStack(pVM
, 1, 0);
4355 pFW
= stackPopPtr(pVM
->pStack
);
4358 ** Save vm's state -- a catch will not back out environmental
4361 ** We are *not* saving dictionary state, since it is
4362 ** global instead of per vm, and we are not saving
4363 ** stack contents, since we are not required to (and,
4364 ** thus, it would be useless). We save pVM, and pVM
4365 ** "stacks" (a structure containing general information
4366 ** about it, including the current stack pointer).
4368 memcpy((void*)&VM
, (void*)pVM
, sizeof(FICL_VM
));
4369 memcpy((void*)&pStack
, (void*)pVM
->pStack
, sizeof(FICL_STACK
));
4370 memcpy((void*)&rStack
, (void*)pVM
->rStack
, sizeof(FICL_STACK
));
4373 ** Give pVM a jmp_buf
4375 pVM
->pState
= &vmState
;
4380 except
= setjmp(vmState
);
4385 ** Setup condition - push poison pill so that the VM throws
4386 ** VM_INNEREXIT if the XT terminates normally, then execute
4390 vmPushIP(pVM
, &(pVM
->pSys
->pExitInner
)); /* Open mouth, insert emetic */
4391 vmExecute(pVM
, pFW
);
4396 ** Normal exit from XT - lose the poison pill,
4397 ** restore old setjmp vector and push a zero.
4400 vmPopIP(pVM
); /* Gack - hurl poison pill */
4401 pVM
->pState
= VM
.pState
; /* Restore just the setjmp vector */
4402 PUSHINT(0); /* Push 0 -- everything is ok */
4406 ** Some other exception got thrown - restore pre-existing VM state
4407 ** and push the exception code
4410 /* Restore vm's state */
4411 memcpy((void*)pVM
, (void*)&VM
, sizeof(FICL_VM
));
4412 memcpy((void*)pVM
->pStack
, (void*)&pStack
, sizeof(FICL_STACK
));
4413 memcpy((void*)pVM
->rStack
, (void*)&rStack
, sizeof(FICL_STACK
));
4415 PUSHINT(except
);/* Push error */
4420 /**************************************************************************
4423 ** Throw -- From ANS Forth standard.
4425 ** Throw takes the ToS and, if that's different from zero,
4426 ** returns to the last executed catch context. Further throws will
4427 ** unstack previously executed "catches", in LIFO mode.
4429 ** Daniel C. Sobral Jan 09/1999
4430 **************************************************************************/
4431 static void ficlThrow(FICL_VM
*pVM
)
4435 except
= stackPopINT(pVM
->pStack
);
4438 vmThrow(pVM
, except
);
4442 /**************************************************************************
4445 **************************************************************************/
4446 static void ansAllocate(FICL_VM
*pVM
)
4451 size
= stackPopINT(pVM
->pStack
);
4452 p
= ficlMalloc(size
);
4461 /**************************************************************************
4464 **************************************************************************/
4465 static void ansFree(FICL_VM
*pVM
)
4469 p
= stackPopPtr(pVM
->pStack
);
4475 /**************************************************************************
4478 **************************************************************************/
4479 static void ansResize(FICL_VM
*pVM
)
4484 size
= stackPopINT(pVM
->pStack
);
4485 old
= stackPopPtr(pVM
->pStack
);
4486 new = ficlRealloc(old
, size
);
4500 /**************************************************************************
4501 ** e x i t - i n n e r
4502 ** Signals execXT that an inner loop has completed
4503 **************************************************************************/
4504 static void ficlExitInner(FICL_VM
*pVM
)
4506 vmThrow(pVM
, VM_INNEREXIT
);
4510 /**************************************************************************
4512 ** DOUBLE ( d1 -- d2 )
4513 ** d2 is the negation of d1.
4514 **************************************************************************/
4515 static void dnegate(FICL_VM
*pVM
)
4517 DPINT i
= i64Pop(pVM
->pStack
);
4519 i64Push(pVM
->pStack
, i
);
4526 /**************************************************************************
4529 **************************************************************************/
4530 static void funcname(FICL_VM
*pVM
)
4538 /**************************************************************************
4539 f i c l W o r d C l a s s i f y
4540 ** This public function helps to classify word types for SEE
4541 ** and the deugger in tools.c. Given a pointer to a word, it returns
4543 **************************************************************************/
4544 WORDKIND
ficlWordClassify(FICL_WORD
*pFW
)
4552 static CODEtoKIND codeMap
[] =
4554 {BRANCH
, branchParen
},
4555 {COLON
, colonParen
},
4556 {CONSTANT
, constantParen
},
4557 {CREATE
, createParen
},
4561 {LITERAL
, literalParen
},
4563 {PLOOP
, plusLoopParen
},
4565 {CSTRINGLIT
, cstringLit
},
4566 {STRINGLIT
, stringLit
},
4570 {VARIABLE
, variableParen
},
4573 #define nMAP (sizeof(codeMap) / sizeof(CODEtoKIND))
4575 FICL_CODE code
= pFW
->code
;
4578 for (i
=0; i
< nMAP
; i
++)
4580 if (codeMap
[i
].code
== code
)
4581 return codeMap
[i
].kind
;
4588 /**************************************************************************
4589 f i c l C o m p i l e C o r e
4590 ** Builds the primitive wordset and the environment-query namespace.
4591 **************************************************************************/
4593 void ficlCompileCore(FICL_SYSTEM
*pSys
)
4595 FICL_DICT
*dp
= pSys
->dp
;
4601 ** see softcore.c for definitions of: abs bl space spaces abort"
4604 dictAppendWord(dp
, "!", store
, FW_DEFAULT
);
4605 dictAppendWord(dp
, "#", numberSign
, FW_DEFAULT
);
4606 dictAppendWord(dp
, "#>", numberSignGreater
,FW_DEFAULT
);
4607 dictAppendWord(dp
, "#s", numberSignS
, FW_DEFAULT
);
4608 dictAppendWord(dp
, "\'", ficlTick
, FW_DEFAULT
);
4609 dictAppendWord(dp
, "(", commentHang
, FW_IMMEDIATE
);
4610 dictAppendWord(dp
, "*", mul
, FW_DEFAULT
);
4611 dictAppendWord(dp
, "*/", mulDiv
, FW_DEFAULT
);
4612 dictAppendWord(dp
, "*/mod", mulDivRem
, FW_DEFAULT
);
4613 dictAppendWord(dp
, "+", add
, FW_DEFAULT
);
4614 dictAppendWord(dp
, "+!", plusStore
, FW_DEFAULT
);
4615 dictAppendWord(dp
, "+loop", plusLoopCoIm
, FW_COMPIMMED
);
4616 dictAppendWord(dp
, ",", comma
, FW_DEFAULT
);
4617 dictAppendWord(dp
, "-", sub
, FW_DEFAULT
);
4618 dictAppendWord(dp
, ".", displayCell
, FW_DEFAULT
);
4619 dictAppendWord(dp
, ".\"", dotQuoteCoIm
, FW_COMPIMMED
);
4620 dictAppendWord(dp
, "/", ficlDiv
, FW_DEFAULT
);
4621 dictAppendWord(dp
, "/mod", slashMod
, FW_DEFAULT
);
4622 dictAppendWord(dp
, "0<", zeroLess
, FW_DEFAULT
);
4623 dictAppendWord(dp
, "0=", zeroEquals
, FW_DEFAULT
);
4624 dictAppendWord(dp
, "1+", onePlus
, FW_DEFAULT
);
4625 dictAppendWord(dp
, "1-", oneMinus
, FW_DEFAULT
);
4626 dictAppendWord(dp
, "2!", twoStore
, FW_DEFAULT
);
4627 dictAppendWord(dp
, "2*", twoMul
, FW_DEFAULT
);
4628 dictAppendWord(dp
, "2/", twoDiv
, FW_DEFAULT
);
4629 dictAppendWord(dp
, "2@", twoFetch
, FW_DEFAULT
);
4630 dictAppendWord(dp
, "2drop", twoDrop
, FW_DEFAULT
);
4631 dictAppendWord(dp
, "2dup", twoDup
, FW_DEFAULT
);
4632 dictAppendWord(dp
, "2over", twoOver
, FW_DEFAULT
);
4633 dictAppendWord(dp
, "2swap", twoSwap
, FW_DEFAULT
);
4634 dictAppendWord(dp
, ":", colon
, FW_DEFAULT
);
4635 dictAppendWord(dp
, ";", semicolonCoIm
, FW_COMPIMMED
);
4636 dictAppendWord(dp
, "<", isLess
, FW_DEFAULT
);
4637 dictAppendWord(dp
, "<#", lessNumberSign
, FW_DEFAULT
);
4638 dictAppendWord(dp
, "=", isEqual
, FW_DEFAULT
);
4639 dictAppendWord(dp
, ">", isGreater
, FW_DEFAULT
);
4640 dictAppendWord(dp
, ">body", toBody
, FW_DEFAULT
);
4641 dictAppendWord(dp
, ">in", toIn
, FW_DEFAULT
);
4642 dictAppendWord(dp
, ">number", toNumber
, FW_DEFAULT
);
4643 dictAppendWord(dp
, ">r", toRStack
, FW_COMPILE
);
4644 dictAppendWord(dp
, "?dup", questionDup
, FW_DEFAULT
);
4645 dictAppendWord(dp
, "@", fetch
, FW_DEFAULT
);
4646 dictAppendWord(dp
, "abort", ficlAbort
, FW_DEFAULT
);
4647 dictAppendWord(dp
, "accept", accept
, FW_DEFAULT
);
4648 dictAppendWord(dp
, "align", align
, FW_DEFAULT
);
4649 dictAppendWord(dp
, "aligned", aligned
, FW_DEFAULT
);
4650 dictAppendWord(dp
, "allot", allot
, FW_DEFAULT
);
4651 dictAppendWord(dp
, "and", bitwiseAnd
, FW_DEFAULT
);
4652 dictAppendWord(dp
, "base", base
, FW_DEFAULT
);
4653 dictAppendWord(dp
, "begin", beginCoIm
, FW_COMPIMMED
);
4654 dictAppendWord(dp
, "c!", cStore
, FW_DEFAULT
);
4655 dictAppendWord(dp
, "c,", cComma
, FW_DEFAULT
);
4656 dictAppendWord(dp
, "c@", cFetch
, FW_DEFAULT
);
4657 dictAppendWord(dp
, "cell+", cellPlus
, FW_DEFAULT
);
4658 dictAppendWord(dp
, "cells", cells
, FW_DEFAULT
);
4659 dictAppendWord(dp
, "char", ficlChar
, FW_DEFAULT
);
4660 dictAppendWord(dp
, "char+", charPlus
, FW_DEFAULT
);
4661 dictAppendWord(dp
, "chars", ficlChars
, FW_DEFAULT
);
4662 dictAppendWord(dp
, "constant", constant
, FW_DEFAULT
);
4663 dictAppendWord(dp
, "count", count
, FW_DEFAULT
);
4664 dictAppendWord(dp
, "cr", cr
, FW_DEFAULT
);
4665 dictAppendWord(dp
, "create", create
, FW_DEFAULT
);
4666 dictAppendWord(dp
, "decimal", decimal
, FW_DEFAULT
);
4667 dictAppendWord(dp
, "depth", depth
, FW_DEFAULT
);
4668 dictAppendWord(dp
, "do", doCoIm
, FW_COMPIMMED
);
4669 dictAppendWord(dp
, "does>", doesCoIm
, FW_COMPIMMED
);
4670 dictAppendWord(dp
, "drop", drop
, FW_DEFAULT
);
4671 dictAppendWord(dp
, "dup", dup
, FW_DEFAULT
);
4672 dictAppendWord(dp
, "else", elseCoIm
, FW_COMPIMMED
);
4673 dictAppendWord(dp
, "emit", emit
, FW_DEFAULT
);
4674 dictAppendWord(dp
, "environment?", environmentQ
,FW_DEFAULT
);
4675 dictAppendWord(dp
, "evaluate", evaluate
, FW_DEFAULT
);
4676 dictAppendWord(dp
, "execute", execute
, FW_DEFAULT
);
4677 dictAppendWord(dp
, "exit", exitCoIm
, FW_COMPIMMED
);
4678 dictAppendWord(dp
, "fill", fill
, FW_DEFAULT
);
4679 dictAppendWord(dp
, "find", cFind
, FW_DEFAULT
);
4680 dictAppendWord(dp
, "fm/mod", fmSlashMod
, FW_DEFAULT
);
4681 dictAppendWord(dp
, "here", here
, FW_DEFAULT
);
4682 dictAppendWord(dp
, "hold", hold
, FW_DEFAULT
);
4683 dictAppendWord(dp
, "i", loopICo
, FW_COMPILE
);
4684 dictAppendWord(dp
, "if", ifCoIm
, FW_COMPIMMED
);
4685 dictAppendWord(dp
, "immediate", immediate
, FW_DEFAULT
);
4686 dictAppendWord(dp
, "invert", bitwiseNot
, FW_DEFAULT
);
4687 dictAppendWord(dp
, "j", loopJCo
, FW_COMPILE
);
4688 dictAppendWord(dp
, "k", loopKCo
, FW_COMPILE
);
4689 dictAppendWord(dp
, "leave", leaveCo
, FW_COMPILE
);
4690 dictAppendWord(dp
, "literal", literalIm
, FW_IMMEDIATE
);
4691 dictAppendWord(dp
, "loop", loopCoIm
, FW_COMPIMMED
);
4692 dictAppendWord(dp
, "lshift", lshift
, FW_DEFAULT
);
4693 dictAppendWord(dp
, "m*", mStar
, FW_DEFAULT
);
4694 dictAppendWord(dp
, "max", ficlMax
, FW_DEFAULT
);
4695 dictAppendWord(dp
, "min", ficlMin
, FW_DEFAULT
);
4696 dictAppendWord(dp
, "mod", ficlMod
, FW_DEFAULT
);
4697 dictAppendWord(dp
, "move", move
, FW_DEFAULT
);
4698 dictAppendWord(dp
, "negate", negate
, FW_DEFAULT
);
4699 dictAppendWord(dp
, "or", bitwiseOr
, FW_DEFAULT
);
4700 dictAppendWord(dp
, "over", over
, FW_DEFAULT
);
4701 dictAppendWord(dp
, "postpone", postponeCoIm
, FW_COMPIMMED
);
4702 dictAppendWord(dp
, "quit", quit
, FW_DEFAULT
);
4703 dictAppendWord(dp
, "r>", fromRStack
, FW_COMPILE
);
4704 dictAppendWord(dp
, "r@", fetchRStack
, FW_COMPILE
);
4705 dictAppendWord(dp
, "recurse", recurseCoIm
, FW_COMPIMMED
);
4706 dictAppendWord(dp
, "repeat", repeatCoIm
, FW_COMPIMMED
);
4707 dictAppendWord(dp
, "rot", rot
, FW_DEFAULT
);
4708 dictAppendWord(dp
, "rshift", rshift
, FW_DEFAULT
);
4709 dictAppendWord(dp
, "s\"", stringQuoteIm
, FW_IMMEDIATE
);
4710 dictAppendWord(dp
, "s>d", sToD
, FW_DEFAULT
);
4711 dictAppendWord(dp
, "sign", sign
, FW_DEFAULT
);
4712 dictAppendWord(dp
, "sm/rem", smSlashRem
, FW_DEFAULT
);
4713 dictAppendWord(dp
, "source", source
, FW_DEFAULT
);
4714 dictAppendWord(dp
, "state", state
, FW_DEFAULT
);
4715 dictAppendWord(dp
, "swap", swap
, FW_DEFAULT
);
4716 dictAppendWord(dp
, "then", endifCoIm
, FW_COMPIMMED
);
4717 dictAppendWord(dp
, "type", type
, FW_DEFAULT
);
4718 dictAppendWord(dp
, "u.", uDot
, FW_DEFAULT
);
4719 dictAppendWord(dp
, "u<", uIsLess
, FW_DEFAULT
);
4720 dictAppendWord(dp
, "um*", umStar
, FW_DEFAULT
);
4721 dictAppendWord(dp
, "um/mod", umSlashMod
, FW_DEFAULT
);
4722 dictAppendWord(dp
, "unloop", unloopCo
, FW_COMPILE
);
4723 dictAppendWord(dp
, "until", untilCoIm
, FW_COMPIMMED
);
4724 dictAppendWord(dp
, "variable", variable
, FW_DEFAULT
);
4725 dictAppendWord(dp
, "while", whileCoIm
, FW_COMPIMMED
);
4726 dictAppendWord(dp
, "word", ficlWord
, FW_DEFAULT
);
4727 dictAppendWord(dp
, "xor", bitwiseXor
, FW_DEFAULT
);
4728 dictAppendWord(dp
, "[", lbracketCoIm
, FW_COMPIMMED
);
4729 dictAppendWord(dp
, "[\']", bracketTickCoIm
,FW_COMPIMMED
);
4730 dictAppendWord(dp
, "[char]", charCoIm
, FW_COMPIMMED
);
4731 dictAppendWord(dp
, "]", rbracket
, FW_DEFAULT
);
4733 ** CORE EXT word set...
4734 ** see softcore.fr for other definitions
4737 dictAppendWord(dp
, ".(", dotParen
, FW_IMMEDIATE
);
4739 dictAppendWord(dp
, "0>", zeroGreater
, FW_DEFAULT
);
4740 dictAppendWord(dp
, "2>r", twoToR
, FW_COMPILE
);
4741 dictAppendWord(dp
, "2r>", twoRFrom
, FW_COMPILE
);
4742 dictAppendWord(dp
, "2r@", twoRFetch
, FW_COMPILE
);
4743 dictAppendWord(dp
, ":noname", colonNoName
, FW_DEFAULT
);
4744 dictAppendWord(dp
, "?do", qDoCoIm
, FW_COMPIMMED
);
4745 dictAppendWord(dp
, "again", againCoIm
, FW_COMPIMMED
);
4746 dictAppendWord(dp
, "c\"", cstringQuoteIm
, FW_IMMEDIATE
);
4747 /* case of endof endcase */
4748 dictAppendWord(dp
, "hex", hex
, FW_DEFAULT
);
4749 dictAppendWord(dp
, "pad", pad
, FW_DEFAULT
);
4750 dictAppendWord(dp
, "parse", parse
, FW_DEFAULT
);
4751 dictAppendWord(dp
, "pick", pick
, FW_DEFAULT
);
4752 /* query restore-input save-input tib u.r u> unused [compile] */
4753 dictAppendWord(dp
, "roll", roll
, FW_DEFAULT
);
4754 dictAppendWord(dp
, "refill", refill
, FW_DEFAULT
);
4755 dictAppendWord(dp
, "source-id", sourceid
, FW_DEFAULT
);
4756 dictAppendWord(dp
, "to", toValue
, FW_IMMEDIATE
);
4757 dictAppendWord(dp
, "value", constant
, FW_DEFAULT
);
4758 dictAppendWord(dp
, "\\", commentLine
, FW_IMMEDIATE
);
4762 ** Set CORE environment query values
4764 ficlSetEnv(pSys
, "/counted-string", FICL_STRING_MAX
);
4765 ficlSetEnv(pSys
, "/hold", nPAD
);
4766 ficlSetEnv(pSys
, "/pad", nPAD
);
4767 ficlSetEnv(pSys
, "address-unit-bits", 8);
4768 ficlSetEnv(pSys
, "core", FICL_TRUE
);
4769 ficlSetEnv(pSys
, "core-ext", FICL_FALSE
);
4770 ficlSetEnv(pSys
, "floored", FICL_FALSE
);
4771 ficlSetEnv(pSys
, "max-char", UCHAR_MAX
);
4772 ficlSetEnvD(pSys
,"max-d", 0x7fffffff, 0xffffffff);
4773 ficlSetEnv(pSys
, "max-n", 0x7fffffff);
4774 ficlSetEnv(pSys
, "max-u", 0xffffffff);
4775 ficlSetEnvD(pSys
,"max-ud", 0xffffffff, 0xffffffff);
4776 ficlSetEnv(pSys
, "return-stack-cells",FICL_DEFAULT_STACK
);
4777 ficlSetEnv(pSys
, "stack-cells", FICL_DEFAULT_STACK
);
4780 ** DOUBLE word set (partial)
4782 dictAppendWord(dp
, "2constant", twoConstant
, FW_IMMEDIATE
);
4783 dictAppendWord(dp
, "2literal", twoLiteralIm
, FW_IMMEDIATE
);
4784 dictAppendWord(dp
, "2variable", twoVariable
, FW_IMMEDIATE
);
4785 dictAppendWord(dp
, "dnegate", dnegate
, FW_DEFAULT
);
4789 ** EXCEPTION word set
4791 dictAppendWord(dp
, "catch", ficlCatch
, FW_DEFAULT
);
4792 dictAppendWord(dp
, "throw", ficlThrow
, FW_DEFAULT
);
4794 ficlSetEnv(pSys
, "exception", FICL_TRUE
);
4795 ficlSetEnv(pSys
, "exception-ext", FICL_TRUE
);
4798 ** LOCAL and LOCAL EXT
4799 ** see softcore.c for implementation of locals|
4801 #if FICL_WANT_LOCALS
4803 dictAppendWord(dp
, "(link)", linkParen
, FW_COMPILE
);
4804 pSys
->pUnLinkParen
=
4805 dictAppendWord(dp
, "(unlink)", unlinkParen
, FW_COMPILE
);
4806 dictAppendWord(dp
, "doLocal", doLocalIm
, FW_COMPIMMED
);
4807 pSys
->pGetLocalParen
=
4808 dictAppendWord(dp
, "(@local)", getLocalParen
, FW_COMPILE
);
4809 pSys
->pToLocalParen
=
4810 dictAppendWord(dp
, "(toLocal)", toLocalParen
, FW_COMPILE
);
4812 dictAppendWord(dp
, "(@local0)", getLocal0
, FW_COMPILE
);
4814 dictAppendWord(dp
, "(toLocal0)",toLocal0
, FW_COMPILE
);
4816 dictAppendWord(dp
, "(@local1)", getLocal1
, FW_COMPILE
);
4818 dictAppendWord(dp
, "(toLocal1)",toLocal1
, FW_COMPILE
);
4819 dictAppendWord(dp
, "(local)", localParen
, FW_COMPILE
);
4821 pSys
->pGet2LocalParen
=
4822 dictAppendWord(dp
, "(@2local)", get2LocalParen
, FW_COMPILE
);
4823 pSys
->pTo2LocalParen
=
4824 dictAppendWord(dp
, "(to2Local)",to2LocalParen
, FW_COMPILE
);
4825 dictAppendWord(dp
, "(2local)", twoLocalParen
, FW_COMPILE
);
4827 ficlSetEnv(pSys
, "locals", FICL_TRUE
);
4828 ficlSetEnv(pSys
, "locals-ext", FICL_TRUE
);
4829 ficlSetEnv(pSys
, "#locals", FICL_MAX_LOCALS
);
4833 ** Optional MEMORY-ALLOC word set
4836 dictAppendWord(dp
, "allocate", ansAllocate
, FW_DEFAULT
);
4837 dictAppendWord(dp
, "free", ansFree
, FW_DEFAULT
);
4838 dictAppendWord(dp
, "resize", ansResize
, FW_DEFAULT
);
4840 ficlSetEnv(pSys
, "memory-alloc", FICL_TRUE
);
4843 ** optional SEARCH-ORDER word set
4845 ficlCompileSearch(pSys
);
4848 ** TOOLS and TOOLS EXT
4850 ficlCompileTools(pSys
);
4853 ** FILE and FILE EXT
4856 ficlCompileFile(pSys
);
4863 dictAppendWord(dp
, ".hash", dictHashSummary
,FW_DEFAULT
);
4865 dictAppendWord(dp
, ".ver", ficlVersion
, FW_DEFAULT
);
4866 dictAppendWord(dp
, "-roll", minusRoll
, FW_DEFAULT
);
4867 dictAppendWord(dp
, ">name", toName
, FW_DEFAULT
);
4868 dictAppendWord(dp
, "add-parse-step",
4869 addParseStep
, FW_DEFAULT
);
4870 dictAppendWord(dp
, "body>", fromBody
, FW_DEFAULT
);
4871 dictAppendWord(dp
, "compare", compareString
, FW_DEFAULT
); /* STRING */
4872 dictAppendWord(dp
, "compare-insensitive", compareStringInsensitive
, FW_DEFAULT
); /* STRING */
4873 dictAppendWord(dp
, "compile-only",
4874 compileOnly
, FW_DEFAULT
);
4875 dictAppendWord(dp
, "endif", endifCoIm
, FW_COMPIMMED
);
4876 dictAppendWord(dp
, "last-word", getLastWord
, FW_DEFAULT
);
4877 dictAppendWord(dp
, "hash", hash
, FW_DEFAULT
);
4878 dictAppendWord(dp
, "objectify", setObjectFlag
, FW_DEFAULT
);
4879 dictAppendWord(dp
, "?object", isObject
, FW_DEFAULT
);
4880 dictAppendWord(dp
, "parse-word",parseNoCopy
, FW_DEFAULT
);
4881 dictAppendWord(dp
, "sfind", sFind
, FW_DEFAULT
);
4882 dictAppendWord(dp
, "sliteral", sLiteralCoIm
, FW_COMPIMMED
); /* STRING */
4883 dictAppendWord(dp
, "sprintf", ficlSprintf
, FW_DEFAULT
);
4884 dictAppendWord(dp
, "strlen", ficlStrlen
, FW_DEFAULT
);
4885 dictAppendWord(dp
, "q@", quadFetch
, FW_DEFAULT
);
4886 dictAppendWord(dp
, "q!", quadStore
, FW_DEFAULT
);
4887 dictAppendWord(dp
, "w@", wFetch
, FW_DEFAULT
);
4888 dictAppendWord(dp
, "w!", wStore
, FW_DEFAULT
);
4889 dictAppendWord(dp
, "x.", hexDot
, FW_DEFAULT
);
4891 dictAppendWord(dp
, "(user)", userParen
, FW_DEFAULT
);
4892 dictAppendWord(dp
, "user", userVariable
, FW_DEFAULT
);
4896 ** internal support words
4898 dictAppendWord(dp
, "(create)", createParen
, FW_COMPILE
);
4900 dictAppendWord(dp
, "(exit)", exitParen
, FW_COMPILE
);
4902 dictAppendWord(dp
, "(;)", semiParen
, FW_COMPILE
);
4904 dictAppendWord(dp
, "(literal)", literalParen
, FW_COMPILE
);
4905 pSys
->pTwoLitParen
=
4906 dictAppendWord(dp
, "(2literal)",twoLitParen
, FW_COMPILE
);
4908 dictAppendWord(dp
, "(.\")", stringLit
, FW_COMPILE
);
4910 dictAppendWord(dp
, "(c\")", cstringLit
, FW_COMPILE
);
4912 dictAppendWord(dp
, "(if)", ifParen
, FW_COMPILE
);
4913 pSys
->pBranchParen
=
4914 dictAppendWord(dp
, "(branch)", branchParen
, FW_COMPILE
);
4916 dictAppendWord(dp
, "(do)", doParen
, FW_COMPILE
);
4918 dictAppendWord(dp
, "(does>)", doesParen
, FW_COMPILE
);
4920 dictAppendWord(dp
, "(?do)", qDoParen
, FW_COMPILE
);
4922 dictAppendWord(dp
, "(loop)", loopParen
, FW_COMPILE
);
4924 dictAppendWord(dp
, "(+loop)", plusLoopParen
, FW_COMPILE
);
4926 dictAppendWord(dp
, "interpret", interpret
, FW_DEFAULT
);
4927 dictAppendWord(dp
, "lookup", lookup
, FW_DEFAULT
);
4928 dictAppendWord(dp
, "(variable)",variableParen
, FW_COMPILE
);
4929 dictAppendWord(dp
, "(constant)",constantParen
, FW_COMPILE
);
4930 dictAppendWord(dp
, "(parse-step)",
4931 parseStepParen
, FW_DEFAULT
);
4933 dictAppendWord(dp
, "exit-inner",ficlExitInner
, FW_DEFAULT
);
4936 ** Set up system's outer interpreter loop - maybe this should be in initSystem?
4938 pSys
->pInterp
[0] = pSys
->pInterpret
;
4939 pSys
->pInterp
[1] = pSys
->pBranchParen
;
4940 pSys
->pInterp
[2] = (FICL_WORD
*)(void *)(-2);
4942 assert(dictCellsAvail(dp
) > 0);