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
57 static void colonParen(FICL_VM
*pVM
);
58 static void literalIm(FICL_VM
*pVM
);
59 static int ficlParseWord(FICL_VM
*pVM
, STRINGINFO si
);
62 ** Control structure building words use these
63 ** strings' addresses as markers on the stack to
64 ** check for structure completion.
66 static char doTag
[] = "do";
67 static char colonTag
[] = "colon";
68 static char leaveTag
[] = "leave";
70 static char destTag
[] = "target";
71 static char origTag
[] = "origin";
73 static char caseTag
[] = "case";
74 static char ofTag
[] = "of";
75 static char fallthroughTag
[] = "fallthrough";
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
)
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 /**************************************************************************
1226 b r a n c h P a r e n
1228 ** Runtime for "(branch)" -- expects a literal offset in the next
1229 ** compilation address, and branches to that location.
1230 **************************************************************************/
1232 static void branchParen(FICL_VM
*pVM
)
1234 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1239 /**************************************************************************
1241 ** Runtime code for "(branch0)"; pop a flag from the stack,
1242 ** branch if 0. fall through otherwise. The heart of "if" and "until".
1243 **************************************************************************/
1245 static void branch0(FICL_VM
*pVM
)
1250 vmCheckStack(pVM
, 1, 0);
1252 flag
= stackPopUNS(pVM
->pStack
);
1255 { /* fall through */
1256 vmBranchRelative(pVM
, 1);
1259 { /* take branch (to else/endif/begin) */
1260 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
1267 /**************************************************************************
1269 ** IMMEDIATE COMPILE-ONLY
1270 ** Compiles code for a conditional branch into the dictionary
1271 ** and pushes the branch patch address on the stack for later
1272 ** patching by ELSE or THEN/ENDIF.
1273 **************************************************************************/
1275 static void ifCoIm(FICL_VM
*pVM
)
1277 FICL_DICT
*dp
= vmGetDict(pVM
);
1279 assert(pVM
->pSys
->pBranch0
);
1281 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
1282 markBranch(dp
, pVM
, origTag
);
1283 dictAppendUNS(dp
, 1);
1288 /**************************************************************************
1291 ** IMMEDIATE COMPILE-ONLY
1292 ** compiles an "else"...
1293 ** 1) Compile a branch and a patch address; the address gets patched
1294 ** by "endif" to point past the "else" code.
1295 ** 2) Pop the "if" patch address
1296 ** 3) Patch the "if" branch to point to the current compile address.
1297 ** 4) Push the "else" patch address. ("endif" patches this to jump past
1299 **************************************************************************/
1301 static void elseCoIm(FICL_VM
*pVM
)
1305 FICL_DICT
*dp
= vmGetDict(pVM
);
1307 assert(pVM
->pSys
->pBranchParen
);
1308 /* (1) compile branch runtime */
1309 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1310 matchControlTag(pVM
, origTag
);
1312 (CELL
*)stackPopPtr(pVM
->pStack
); /* (2) pop "if" patch addr */
1313 markBranch(dp
, pVM
, origTag
); /* (4) push "else" patch addr */
1314 dictAppendUNS(dp
, 1); /* (1) compile patch placeholder */
1315 offset
= dp
->here
- patchAddr
;
1316 *patchAddr
= LVALUEtoCELL(offset
); /* (3) Patch "if" */
1322 /**************************************************************************
1324 ** IMMEDIATE COMPILE-ONLY
1325 **************************************************************************/
1327 static void endifCoIm(FICL_VM
*pVM
)
1329 FICL_DICT
*dp
= vmGetDict(pVM
);
1330 resolveForwardBranch(dp
, pVM
, origTag
);
1335 /**************************************************************************
1337 ** IMMEDIATE COMPILE-ONLY
1340 ** At compile-time, a CASE-SYS (see DPANS94 6.2.0873) looks like this:
1342 ** and an OF-SYS (see DPANS94 6.2.1950) looks like this:
1343 ** i*addr i caseTag addr ofTag
1344 ** The integer under caseTag is the count of fixup addresses that branch
1346 **************************************************************************/
1348 static void caseCoIm(FICL_VM
*pVM
)
1351 vmCheckStack(pVM
, 0, 2);
1355 markControlTag(pVM
, caseTag
);
1360 /**************************************************************************
1361 e n d c a s eC o I m
1362 ** IMMEDIATE COMPILE-ONLY
1363 **************************************************************************/
1365 static void endcaseCoIm(FICL_VM
*pVM
)
1367 FICL_UNS fixupCount
;
1372 assert(pVM
->pSys
->pDrop
);
1375 ** if the last OF ended with FALLTHROUGH,
1376 ** just add the FALLTHROUGH fixup to the
1379 if (stackGetTop(pVM
->pStack
).p
== fallthroughTag
)
1381 matchControlTag(pVM
, fallthroughTag
);
1382 patchAddr
= POPPTR();
1383 matchControlTag(pVM
, caseTag
);
1384 fixupCount
= POPUNS();
1386 PUSHUNS(fixupCount
+ 1);
1387 markControlTag(pVM
, caseTag
);
1390 matchControlTag(pVM
, caseTag
);
1393 vmCheckStack(pVM
, 1, 0);
1395 fixupCount
= POPUNS();
1397 vmCheckStack(pVM
, fixupCount
, 0);
1400 dp
= vmGetDict(pVM
);
1402 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDrop
));
1404 while (fixupCount
--)
1406 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1407 offset
= dp
->here
- patchAddr
;
1408 *patchAddr
= LVALUEtoCELL(offset
);
1414 static void ofParen(FICL_VM
*pVM
)
1419 vmCheckStack(pVM
, 2, 1);
1423 b
= stackGetTop(pVM
->pStack
).u
;
1426 { /* fall through */
1427 stackDrop(pVM
->pStack
, 1);
1428 vmBranchRelative(pVM
, 1);
1431 { /* take branch to next of or endswitch */
1432 vmBranchRelative(pVM
, *(int *)(pVM
->ip
));
1439 /**************************************************************************
1441 ** IMMEDIATE COMPILE-ONLY
1442 **************************************************************************/
1444 static void ofCoIm(FICL_VM
*pVM
)
1446 FICL_DICT
*dp
= vmGetDict(pVM
);
1447 CELL
*fallthroughFixup
= NULL
;
1449 assert(pVM
->pSys
->pBranch0
);
1452 vmCheckStack(pVM
, 1, 3);
1455 if (stackGetTop(pVM
->pStack
).p
== fallthroughTag
)
1457 matchControlTag(pVM
, fallthroughTag
);
1458 fallthroughFixup
= POPPTR();
1461 matchControlTag(pVM
, caseTag
);
1463 markControlTag(pVM
, caseTag
);
1465 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pOfParen
));
1466 markBranch(dp
, pVM
, ofTag
);
1467 dictAppendUNS(dp
, 2);
1469 if (fallthroughFixup
!= NULL
)
1471 FICL_INT offset
= dp
->here
- fallthroughFixup
;
1472 *fallthroughFixup
= LVALUEtoCELL(offset
);
1479 /**************************************************************************
1481 ** IMMEDIATE COMPILE-ONLY
1482 **************************************************************************/
1484 static void endofCoIm(FICL_VM
*pVM
)
1487 FICL_UNS fixupCount
;
1489 FICL_DICT
*dp
= vmGetDict(pVM
);
1492 vmCheckStack(pVM
, 4, 3);
1495 assert(pVM
->pSys
->pBranchParen
);
1497 /* ensure we're in an OF, */
1498 matchControlTag(pVM
, ofTag
);
1499 /* grab the address of the branch location after the OF */
1500 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1501 /* ensure we're also in a "case" */
1502 matchControlTag(pVM
, caseTag
);
1503 /* grab the current number of ENDOF fixups */
1504 fixupCount
= POPUNS();
1506 /* compile branch runtime */
1507 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1509 /* push a new ENDOF fixup, the updated count of ENDOF fixups, and the caseTag */
1511 PUSHUNS(fixupCount
+ 1);
1512 markControlTag(pVM
, caseTag
);
1514 /* reserve space for the ENDOF fixup */
1515 dictAppendUNS(dp
, 2);
1517 /* and patch the original OF */
1518 offset
= dp
->here
- patchAddr
;
1519 *patchAddr
= LVALUEtoCELL(offset
);
1523 /**************************************************************************
1524 f a l l t h r o u g h C o I m
1525 ** IMMEDIATE COMPILE-ONLY
1526 **************************************************************************/
1528 static void fallthroughCoIm(FICL_VM
*pVM
)
1532 FICL_DICT
*dp
= vmGetDict(pVM
);
1535 vmCheckStack(pVM
, 4, 3);
1538 /* ensure we're in an OF, */
1539 matchControlTag(pVM
, ofTag
);
1540 /* grab the address of the branch location after the OF */
1541 patchAddr
= (CELL
*)stackPopPtr(pVM
->pStack
);
1542 /* ensure we're also in a "case" */
1543 matchControlTag(pVM
, caseTag
);
1545 /* okay, here we go. put the case tag back. */
1546 markControlTag(pVM
, caseTag
);
1548 /* compile branch runtime */
1549 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
1551 /* push a new FALLTHROUGH fixup and the fallthroughTag */
1553 markControlTag(pVM
, fallthroughTag
);
1555 /* reserve space for the FALLTHROUGH fixup */
1556 dictAppendUNS(dp
, 2);
1558 /* and patch the original OF */
1559 offset
= dp
->here
- patchAddr
;
1560 *patchAddr
= LVALUEtoCELL(offset
);
1563 /**************************************************************************
1565 ** hash ( c-addr u -- code)
1566 ** calculates hashcode of specified string and leaves it on the stack
1567 **************************************************************************/
1569 static void hash(FICL_VM
*pVM
)
1572 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1573 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1574 PUSHUNS(hashHashCode(si
));
1579 /**************************************************************************
1581 ** This is the "user interface" of a Forth. It does the following:
1582 ** while there are words in the VM's Text Input Buffer
1583 ** Copy next word into the pad (vmGetWord)
1584 ** Attempt to find the word in the dictionary (dictLookup)
1585 ** If successful, execute the word.
1586 ** Otherwise, attempt to convert the word to a number (isNumber)
1587 ** If successful, push the number onto the parameter stack.
1588 ** Otherwise, print an error message and exit loop...
1591 ** From the standard, section 3.4
1592 ** Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
1593 ** repeat the following steps until either the parse area is empty or an
1594 ** ambiguous condition exists:
1595 ** a) Skip leading spaces and parse a name (see 3.4.1);
1596 **************************************************************************/
1598 static void interpret(FICL_VM
*pVM
)
1607 si
= vmGetWord0(pVM
);
1610 ** Get next word...if out of text, we're done.
1614 vmThrow(pVM
, VM_OUTOFTEXT
);
1618 ** Attempt to find the incoming token in the dictionary. If that fails...
1619 ** run the parse chain against the incoming token until somebody eats it.
1620 ** Otherwise emit an error message and give up.
1621 ** Although ficlParseWord could be part of the parse list, I've hard coded it
1622 ** in for robustness. ficlInitSystem adds the other default steps to the list.
1624 if (ficlParseWord(pVM
, si
))
1627 for (i
=0; i
< FICL_MAX_PARSE_STEPS
; i
++)
1629 FICL_WORD
*pFW
= pSys
->parseList
[i
];
1634 if (pFW
->code
== parseStepParen
)
1636 FICL_PARSE_STEP pStep
;
1637 pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1638 if ((*pStep
)(pVM
, si
))
1643 stackPushPtr(pVM
->pStack
, SI_PTR(si
));
1644 stackPushUNS(pVM
->pStack
, SI_COUNT(si
));
1645 ficlExecXT(pVM
, pFW
);
1646 if (stackPopINT(pVM
->pStack
))
1652 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
1654 return; /* back to inner interpreter */
1658 /**************************************************************************
1659 f i c l P a r s e W o r d
1660 ** From the standard, section 3.4
1661 ** b) Search the dictionary name space (see 3.4.2). If a definition name
1662 ** matching the string is found:
1663 ** 1.if interpreting, perform the interpretation semantics of the definition
1664 ** (see 3.4.3.2), and continue at a);
1665 ** 2.if compiling, perform the compilation semantics of the definition
1666 ** (see 3.4.3.3), and continue at a).
1668 ** c) If a definition name matching the string is not found, attempt to
1669 ** convert the string to a number (see 3.4.1.3). If successful:
1670 ** 1.if interpreting, place the number on the data stack, and continue at a);
1671 ** 2.if compiling, compile code that when executed will place the number on
1672 ** the stack (see 6.1.1780 LITERAL), and continue at a);
1674 ** d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
1676 ** (jws 4/01) Modified to be a FICL_PARSE_STEP
1677 **************************************************************************/
1678 static int ficlParseWord(FICL_VM
*pVM
, STRINGINFO si
)
1680 FICL_DICT
*dp
= vmGetDict(pVM
);
1684 dictCheck(dp
, pVM
, 0);
1685 vmCheckStack(pVM
, 0, 0);
1688 #if FICL_WANT_LOCALS
1689 if (pVM
->pSys
->nLocals
> 0)
1691 tempFW
= ficlLookupLoc(pVM
->pSys
, si
);
1695 tempFW
= dictLookup(dp
, si
);
1697 if (pVM
->state
== INTERPRET
)
1701 if (wordIsCompileOnly(tempFW
))
1703 vmThrowErr(pVM
, "Error: Compile only!");
1706 vmExecute(pVM
, tempFW
);
1707 return (int)FICL_TRUE
;
1711 else /* (pVM->state == COMPILE) */
1715 if (wordIsImmediate(tempFW
))
1717 vmExecute(pVM
, tempFW
);
1721 dictAppendCell(dp
, LVALUEtoCELL(tempFW
));
1723 return (int)FICL_TRUE
;
1732 ** Surrogate precompiled parse step for ficlParseWord (this step is hard coded in
1735 static void lookup(FICL_VM
*pVM
)
1738 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
1739 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1740 stackPushINT(pVM
->pStack
, ficlParseWord(pVM
, si
));
1745 /**************************************************************************
1746 p a r e n P a r s e S t e p
1747 ** (parse-step) ( c-addr u -- flag )
1748 ** runtime for a precompiled parse step - pop a counted string off the
1749 ** stack, run the parse step against it, and push the result flag (FICL_TRUE
1750 ** if success, FICL_FALSE otherwise).
1751 **************************************************************************/
1753 void parseStepParen(FICL_VM
*pVM
)
1756 FICL_WORD
*pFW
= pVM
->runningWord
;
1757 FICL_PARSE_STEP pStep
= (FICL_PARSE_STEP
)(pFW
->param
->fn
);
1759 SI_SETLEN(si
, stackPopINT(pVM
->pStack
));
1760 SI_SETPTR(si
, stackPopPtr(pVM
->pStack
));
1762 PUSHINT((*pStep
)(pVM
, si
));
1768 static void addParseStep(FICL_VM
*pVM
)
1771 FICL_DICT
*pd
= vmGetDict(pVM
);
1773 vmCheckStack(pVM
, 1, 0);
1775 pStep
= (FICL_WORD
*)(stackPop(pVM
->pStack
).p
);
1776 if ((pStep
!= NULL
) && isAFiclWord(pd
, pStep
))
1777 ficlAddParseStep(pVM
->pSys
, pStep
);
1782 /**************************************************************************
1783 l i t e r a l P a r e n
1785 ** This is the runtime for (literal). It assumes that it is part of a colon
1786 ** definition, and that the next CELL contains a value to be pushed on the
1787 ** parameter stack at runtime. This code is compiled by "literal".
1789 **************************************************************************/
1791 static void literalParen(FICL_VM
*pVM
)
1794 vmCheckStack(pVM
, 0, 1);
1796 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1797 vmBranchRelative(pVM
, 1);
1801 static void twoLitParen(FICL_VM
*pVM
)
1804 vmCheckStack(pVM
, 0, 2);
1806 PUSHINT(*((FICL_INT
*)(pVM
->ip
)+1));
1807 PUSHINT(*(FICL_INT
*)(pVM
->ip
));
1808 vmBranchRelative(pVM
, 2);
1813 /**************************************************************************
1816 ** IMMEDIATE code for "literal". This function gets a value from the stack
1817 ** and compiles it into the dictionary preceded by the code for "(literal)".
1819 **************************************************************************/
1821 static void literalIm(FICL_VM
*pVM
)
1823 FICL_DICT
*dp
= vmGetDict(pVM
);
1824 assert(pVM
->pSys
->pLitParen
);
1826 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLitParen
));
1827 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1833 static void twoLiteralIm(FICL_VM
*pVM
)
1835 FICL_DICT
*dp
= vmGetDict(pVM
);
1836 assert(pVM
->pSys
->pTwoLitParen
);
1838 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTwoLitParen
));
1839 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1840 dictAppendCell(dp
, stackPop(pVM
->pStack
));
1845 /**************************************************************************
1846 l o g i c a n d c o m p a r i s o n s
1848 **************************************************************************/
1850 static void zeroEquals(FICL_VM
*pVM
)
1854 vmCheckStack(pVM
, 1, 1);
1856 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) == 0);
1857 stackPush(pVM
->pStack
, c
);
1861 static void zeroLess(FICL_VM
*pVM
)
1865 vmCheckStack(pVM
, 1, 1);
1867 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) < 0);
1868 stackPush(pVM
->pStack
, c
);
1872 static void zeroGreater(FICL_VM
*pVM
)
1876 vmCheckStack(pVM
, 1, 1);
1878 c
.i
= FICL_BOOL(stackPopINT(pVM
->pStack
) > 0);
1879 stackPush(pVM
->pStack
, c
);
1883 static void isEqual(FICL_VM
*pVM
)
1888 vmCheckStack(pVM
, 2, 1);
1890 x
= stackPop(pVM
->pStack
);
1891 y
= stackPop(pVM
->pStack
);
1892 PUSHINT(FICL_BOOL(x
.i
== y
.i
));
1896 static void isLess(FICL_VM
*pVM
)
1900 vmCheckStack(pVM
, 2, 1);
1902 y
= stackPop(pVM
->pStack
);
1903 x
= stackPop(pVM
->pStack
);
1904 PUSHINT(FICL_BOOL(x
.i
< y
.i
));
1908 static void uIsLess(FICL_VM
*pVM
)
1912 vmCheckStack(pVM
, 2, 1);
1914 u2
= stackPopUNS(pVM
->pStack
);
1915 u1
= stackPopUNS(pVM
->pStack
);
1916 PUSHINT(FICL_BOOL(u1
< u2
));
1920 static void isGreater(FICL_VM
*pVM
)
1924 vmCheckStack(pVM
, 2, 1);
1926 y
= stackPop(pVM
->pStack
);
1927 x
= stackPop(pVM
->pStack
);
1928 PUSHINT(FICL_BOOL(x
.i
> y
.i
));
1932 static void uIsGreater(FICL_VM
*pVM
)
1936 vmCheckStack(pVM
, 2, 1);
1938 u2
= stackPopUNS(pVM
->pStack
);
1939 u1
= stackPopUNS(pVM
->pStack
);
1940 PUSHINT(FICL_BOOL(u1
> u2
));
1944 static void bitwiseAnd(FICL_VM
*pVM
)
1948 vmCheckStack(pVM
, 2, 1);
1950 x
= stackPop(pVM
->pStack
);
1951 y
= stackPop(pVM
->pStack
);
1956 static void bitwiseOr(FICL_VM
*pVM
)
1960 vmCheckStack(pVM
, 2, 1);
1962 x
= stackPop(pVM
->pStack
);
1963 y
= stackPop(pVM
->pStack
);
1968 static void bitwiseXor(FICL_VM
*pVM
)
1972 vmCheckStack(pVM
, 2, 1);
1974 x
= stackPop(pVM
->pStack
);
1975 y
= stackPop(pVM
->pStack
);
1980 static void bitwiseNot(FICL_VM
*pVM
)
1984 vmCheckStack(pVM
, 1, 1);
1986 x
= stackPop(pVM
->pStack
);
1992 /**************************************************************************
1994 ** do -- IMMEDIATE COMPILE ONLY
1995 ** Compiles code to initialize a loop: compile (do),
1996 ** allot space to hold the "leave" address, push a branch
1997 ** target address for the loop.
1998 ** (do) -- runtime for "do"
1999 ** pops index and limit from the p stack and moves them
2000 ** to the r stack, then skips to the loop body.
2001 ** loop -- IMMEDIATE COMPILE ONLY
2003 ** Compiles code for the test part of a loop:
2004 ** compile (loop), resolve forward branch from "do", and
2005 ** copy "here" address to the "leave" address allotted by "do"
2006 ** i,j,k -- COMPILE ONLY
2007 ** Runtime: Push loop indices on param stack (i is innermost loop...)
2008 ** Note: each loop has three values on the return stack:
2009 ** ( R: leave limit index )
2010 ** "leave" is the absolute address of the next cell after the loop
2011 ** limit and index are the loop control variables.
2012 ** leave -- COMPILE ONLY
2013 ** Runtime: pop the loop control variables, then pop the
2014 ** "leave" address and jump (absolute) there.
2015 **************************************************************************/
2017 static void doCoIm(FICL_VM
*pVM
)
2019 FICL_DICT
*dp
= vmGetDict(pVM
);
2021 assert(pVM
->pSys
->pDoParen
);
2023 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoParen
));
2025 ** Allot space for a pointer to the end
2026 ** of the loop - "leave" uses this...
2028 markBranch(dp
, pVM
, leaveTag
);
2029 dictAppendUNS(dp
, 0);
2031 ** Mark location of head of loop...
2033 markBranch(dp
, pVM
, doTag
);
2039 static void doParen(FICL_VM
*pVM
)
2043 vmCheckStack(pVM
, 2, 0);
2045 index
= stackPop(pVM
->pStack
);
2046 limit
= stackPop(pVM
->pStack
);
2048 /* copy "leave" target addr to stack */
2049 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
2050 stackPush(pVM
->rStack
, limit
);
2051 stackPush(pVM
->rStack
, index
);
2057 static void qDoCoIm(FICL_VM
*pVM
)
2059 FICL_DICT
*dp
= vmGetDict(pVM
);
2061 assert(pVM
->pSys
->pQDoParen
);
2063 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pQDoParen
));
2065 ** Allot space for a pointer to the end
2066 ** of the loop - "leave" uses this...
2068 markBranch(dp
, pVM
, leaveTag
);
2069 dictAppendUNS(dp
, 0);
2071 ** Mark location of head of loop...
2073 markBranch(dp
, pVM
, doTag
);
2079 static void qDoParen(FICL_VM
*pVM
)
2083 vmCheckStack(pVM
, 2, 0);
2085 index
= stackPop(pVM
->pStack
);
2086 limit
= stackPop(pVM
->pStack
);
2088 /* copy "leave" target addr to stack */
2089 stackPushPtr(pVM
->rStack
, *(pVM
->ip
++));
2091 if (limit
.u
== index
.u
)
2097 stackPush(pVM
->rStack
, limit
);
2098 stackPush(pVM
->rStack
, index
);
2106 ** Runtime code to break out of a do..loop construct
2107 ** Drop the loop control variables; the branch address
2108 ** past "loop" is next on the return stack.
2110 static void leaveCo(FICL_VM
*pVM
)
2113 stackDrop(pVM
->rStack
, 2);
2120 static void unloopCo(FICL_VM
*pVM
)
2122 stackDrop(pVM
->rStack
, 3);
2127 static void loopCoIm(FICL_VM
*pVM
)
2129 FICL_DICT
*dp
= vmGetDict(pVM
);
2131 assert(pVM
->pSys
->pLoopParen
);
2133 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pLoopParen
));
2134 resolveBackBranch(dp
, pVM
, doTag
);
2135 resolveAbsBranch(dp
, pVM
, leaveTag
);
2140 static void plusLoopCoIm(FICL_VM
*pVM
)
2142 FICL_DICT
*dp
= vmGetDict(pVM
);
2144 assert(pVM
->pSys
->pPLoopParen
);
2146 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pPLoopParen
));
2147 resolveBackBranch(dp
, pVM
, doTag
);
2148 resolveAbsBranch(dp
, pVM
, leaveTag
);
2153 static void loopParen(FICL_VM
*pVM
)
2155 FICL_INT index
= stackGetTop(pVM
->rStack
).i
;
2156 FICL_INT limit
= stackFetch(pVM
->rStack
, 1).i
;
2162 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
2163 vmBranchRelative(pVM
, 1); /* fall through the loop */
2166 { /* update index, branch to loop head */
2167 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
2168 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
2175 static void plusLoopParen(FICL_VM
*pVM
)
2177 FICL_INT index
,limit
,increment
;
2181 vmCheckStack(pVM
, 1, 0);
2184 index
= stackGetTop(pVM
->rStack
).i
;
2185 limit
= stackFetch(pVM
->rStack
, 1).i
;
2186 increment
= POP().i
;
2191 flag
= (index
< limit
);
2193 flag
= (index
>= limit
);
2197 stackDrop(pVM
->rStack
, 3); /* nuke the loop indices & "leave" addr */
2198 vmBranchRelative(pVM
, 1); /* fall through the loop */
2201 { /* update index, branch to loop head */
2202 stackSetTop(pVM
->rStack
, LVALUEtoCELL(index
));
2203 vmBranchRelative(pVM
, (uintptr_t)*(pVM
->ip
));
2210 static void loopICo(FICL_VM
*pVM
)
2212 CELL index
= stackGetTop(pVM
->rStack
);
2213 stackPush(pVM
->pStack
, index
);
2219 static void loopJCo(FICL_VM
*pVM
)
2221 CELL index
= stackFetch(pVM
->rStack
, 3);
2222 stackPush(pVM
->pStack
, index
);
2228 static void loopKCo(FICL_VM
*pVM
)
2230 CELL index
= stackFetch(pVM
->rStack
, 6);
2231 stackPush(pVM
->pStack
, index
);
2237 /**************************************************************************
2238 r e t u r n s t a c k
2240 **************************************************************************/
2241 static void toRStack(FICL_VM
*pVM
)
2244 vmCheckStack(pVM
, 1, 0);
2247 stackPush(pVM
->rStack
, POP());
2250 static void fromRStack(FICL_VM
*pVM
)
2253 vmCheckStack(pVM
, 0, 1);
2256 PUSH(stackPop(pVM
->rStack
));
2259 static void fetchRStack(FICL_VM
*pVM
)
2262 vmCheckStack(pVM
, 0, 1);
2265 PUSH(stackGetTop(pVM
->rStack
));
2268 static void twoToR(FICL_VM
*pVM
)
2271 vmCheckStack(pVM
, 2, 0);
2273 stackRoll(pVM
->pStack
, 1);
2274 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2275 stackPush(pVM
->rStack
, stackPop(pVM
->pStack
));
2279 static void twoRFrom(FICL_VM
*pVM
)
2282 vmCheckStack(pVM
, 0, 2);
2284 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2285 stackPush(pVM
->pStack
, stackPop(pVM
->rStack
));
2286 stackRoll(pVM
->pStack
, 1);
2290 static void twoRFetch(FICL_VM
*pVM
)
2293 vmCheckStack(pVM
, 0, 2);
2295 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 1));
2296 stackPush(pVM
->pStack
, stackFetch(pVM
->rStack
, 0));
2301 /**************************************************************************
2304 **************************************************************************/
2306 static void variableParen(FICL_VM
*pVM
)
2310 vmCheckStack(pVM
, 0, 1);
2313 fw
= pVM
->runningWord
;
2318 static void variable(FICL_VM
*pVM
)
2320 FICL_DICT
*dp
= vmGetDict(pVM
);
2321 STRINGINFO si
= vmGetWord(pVM
);
2323 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2324 dictAllotCells(dp
, 1);
2329 static void twoVariable(FICL_VM
*pVM
)
2331 FICL_DICT
*dp
= vmGetDict(pVM
);
2332 STRINGINFO si
= vmGetWord(pVM
);
2334 dictAppendWord2(dp
, si
, variableParen
, FW_DEFAULT
);
2335 dictAllotCells(dp
, 2);
2340 /**************************************************************************
2341 b a s e & f r i e n d s
2343 **************************************************************************/
2345 static void base(FICL_VM
*pVM
)
2349 vmCheckStack(pVM
, 0, 1);
2352 pBase
= (CELL
*)(&pVM
->base
);
2353 stackPush(pVM
->pStack
, LVALUEtoCELL(pBase
));
2358 static void decimal(FICL_VM
*pVM
)
2365 static void hex(FICL_VM
*pVM
)
2372 /**************************************************************************
2373 a l l o t & f r i e n d s
2375 **************************************************************************/
2377 static void allot(FICL_VM
*pVM
)
2382 vmCheckStack(pVM
, 1, 0);
2385 dp
= vmGetDict(pVM
);
2389 dictCheck(dp
, pVM
, i
);
2397 static void here(FICL_VM
*pVM
)
2401 vmCheckStack(pVM
, 0, 1);
2404 dp
= vmGetDict(pVM
);
2409 static void comma(FICL_VM
*pVM
)
2414 vmCheckStack(pVM
, 1, 0);
2417 dp
= vmGetDict(pVM
);
2419 dictAppendCell(dp
, c
);
2423 static void cComma(FICL_VM
*pVM
)
2428 vmCheckStack(pVM
, 1, 0);
2431 dp
= vmGetDict(pVM
);
2433 dictAppendChar(dp
, c
);
2437 static void cells(FICL_VM
*pVM
)
2441 vmCheckStack(pVM
, 1, 1);
2445 PUSHINT(i
* (FICL_INT
)sizeof (CELL
));
2449 static void cellPlus(FICL_VM
*pVM
)
2453 vmCheckStack(pVM
, 1, 1);
2457 PUSHPTR(cp
+ sizeof (CELL
));
2463 /**************************************************************************
2465 ** tick CORE ( "<spaces>name" -- xt )
2466 ** Skip leading space delimiters. Parse name delimited by a space. Find
2467 ** name and return xt, the execution token for name. An ambiguous condition
2468 ** exists if name is not found.
2469 **************************************************************************/
2470 void ficlTick(FICL_VM
*pVM
)
2472 FICL_WORD
*pFW
= NULL
;
2473 STRINGINFO si
= vmGetWord(pVM
);
2475 vmCheckStack(pVM
, 0, 1);
2478 pFW
= dictLookup(vmGetDict(pVM
), si
);
2481 int i
= SI_COUNT(si
);
2482 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
2489 static void bracketTickCoIm(FICL_VM
*pVM
)
2498 /**************************************************************************
2500 ** Lookup the next word in the input stream and compile code to
2501 ** insert it into definitions created by the resulting word
2502 ** (defers compilation, even of immediate words)
2503 **************************************************************************/
2505 static void postponeCoIm(FICL_VM
*pVM
)
2507 FICL_DICT
*dp
= vmGetDict(pVM
);
2509 FICL_WORD
*pComma
= ficlLookup(pVM
->pSys
, ",");
2513 pFW
= stackGetTop(pVM
->pStack
).p
;
2514 if (wordIsImmediate(pFW
))
2516 dictAppendCell(dp
, stackPop(pVM
->pStack
));
2521 dictAppendCell(dp
, LVALUEtoCELL(pComma
));
2529 /**************************************************************************
2531 ** Pop an execution token (pointer to a word) off the stack and
2533 **************************************************************************/
2535 static void execute(FICL_VM
*pVM
)
2539 vmCheckStack(pVM
, 1, 0);
2542 pFW
= stackPopPtr(pVM
->pStack
);
2543 vmExecute(pVM
, pFW
);
2549 /**************************************************************************
2551 ** Make the most recently compiled word IMMEDIATE -- it executes even
2552 ** in compile state (most often used for control compiling words
2553 ** such as IF, THEN, etc)
2554 **************************************************************************/
2556 static void immediate(FICL_VM
*pVM
)
2559 dictSetImmediate(vmGetDict(pVM
));
2564 static void compileOnly(FICL_VM
*pVM
)
2567 dictSetFlags(vmGetDict(pVM
), FW_COMPILE
, 0);
2572 static void setObjectFlag(FICL_VM
*pVM
)
2575 dictSetFlags(vmGetDict(pVM
), FW_ISOBJECT
, 0);
2579 static void isObject(FICL_VM
*pVM
)
2582 FICL_WORD
*pFW
= (FICL_WORD
*)stackPopPtr(pVM
->pStack
);
2584 flag
= ((pFW
!= NULL
) && (pFW
->flags
& FW_ISOBJECT
)) ? FICL_TRUE
: FICL_FALSE
;
2585 stackPushINT(pVM
->pStack
, flag
);
2589 static void cstringLit(FICL_VM
*pVM
)
2591 FICL_STRING
*sp
= (FICL_STRING
*)(pVM
->ip
);
2593 char *cp
= sp
->text
;
2594 cp
+= sp
->count
+ 1;
2596 pVM
->ip
= (IPTYPE
)(void *)cp
;
2598 stackPushPtr(pVM
->pStack
, sp
);
2603 static void cstringQuoteIm(FICL_VM
*pVM
)
2605 FICL_DICT
*dp
= vmGetDict(pVM
);
2607 if (pVM
->state
== INTERPRET
)
2609 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
2610 vmGetString(pVM
, sp
, '\"');
2611 stackPushPtr(pVM
->pStack
, sp
);
2612 /* move HERE past string so it doesn't get overwritten. --lch */
2613 dictAllot(dp
, sp
->count
+ sizeof(FICL_COUNT
));
2615 else /* COMPILE state */
2617 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pCStringLit
));
2618 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2625 /**************************************************************************
2627 ** IMMEDIATE word that compiles a string literal for later display
2628 ** Compile stringLit, then copy the bytes of the string from the TIB
2629 ** to the dictionary. Backpatch the count byte and align the dictionary.
2631 ** stringlit: Fetch the count from the dictionary, then push the address
2632 ** and count on the stack. Finally, update ip to point to the first
2633 ** aligned address after the string text.
2634 **************************************************************************/
2636 static void stringLit(FICL_VM
*pVM
)
2642 vmCheckStack(pVM
, 0, 2);
2645 sp
= (FICL_STRING
*)(pVM
->ip
);
2652 pVM
->ip
= (IPTYPE
)(void *)cp
;
2655 static void dotQuoteCoIm(FICL_VM
*pVM
)
2657 FICL_DICT
*dp
= vmGetDict(pVM
);
2658 FICL_WORD
*pType
= ficlLookup(pVM
->pSys
, "type");
2660 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2661 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
2663 dictAppendCell(dp
, LVALUEtoCELL(pType
));
2668 static void dotParen(FICL_VM
*pVM
)
2670 char *pSrc
= vmGetInBuf(pVM
);
2671 char *pEnd
= vmGetInBufEnd(pVM
);
2672 char *pDest
= pVM
->pad
;
2676 ** Note: the standard does not want leading spaces skipped (apparently)
2678 for (ch
= *pSrc
; (pEnd
!= pSrc
) && (ch
!= ')'); ch
= *++pSrc
)
2682 if ((pEnd
!= pSrc
) && (ch
== ')'))
2685 vmTextOut(pVM
, pVM
->pad
, 0);
2686 vmUpdateTib(pVM
, pSrc
);
2692 /**************************************************************************
2695 ** Interpretation: Interpretation semantics for this word are undefined.
2696 ** Compilation: ( c-addr1 u -- )
2697 ** Append the run-time semantics given below to the current definition.
2698 ** Run-time: ( -- c-addr2 u )
2699 ** Return c-addr2 u describing a string consisting of the characters
2700 ** specified by c-addr1 u during compilation. A program shall not alter
2701 ** the returned string.
2702 **************************************************************************/
2703 static void sLiteralCoIm(FICL_VM
*pVM
)
2710 vmCheckStack(pVM
, 2, 0);
2713 dp
= vmGetDict(pVM
);
2717 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
2718 cpDest
= (char *) dp
->here
;
2719 *cpDest
++ = (char) u
;
2727 dp
->here
= PTRtoCELL
alignPtr(cpDest
);
2732 /**************************************************************************
2734 ** Return the address of the VM's state member (must be sized the
2735 ** same as a CELL for this reason)
2736 **************************************************************************/
2737 static void state(FICL_VM
*pVM
)
2740 vmCheckStack(pVM
, 0, 1);
2742 PUSHPTR(&pVM
->state
);
2747 /**************************************************************************
2748 c r e a t e . . . d o e s >
2749 ** Make a new word in the dictionary with the run-time effect of
2750 ** a variable (push my address), but with extra space allotted
2751 ** for use by does> .
2752 **************************************************************************/
2754 static void createParen(FICL_VM
*pVM
)
2759 vmCheckStack(pVM
, 0, 1);
2762 pCell
= pVM
->runningWord
->param
;
2768 static void create(FICL_VM
*pVM
)
2770 FICL_DICT
*dp
= vmGetDict(pVM
);
2771 STRINGINFO si
= vmGetWord(pVM
);
2773 dictCheckThreshold(dp
);
2775 dictAppendWord2(dp
, si
, createParen
, FW_DEFAULT
);
2776 dictAllotCells(dp
, 1);
2781 static void doDoes(FICL_VM
*pVM
)
2786 vmCheckStack(pVM
, 0, 1);
2789 pCell
= pVM
->runningWord
->param
;
2790 tempIP
= (IPTYPE
)((*pCell
).p
);
2792 vmPushIP(pVM
, tempIP
);
2797 static void doesParen(FICL_VM
*pVM
)
2799 FICL_DICT
*dp
= vmGetDict(pVM
);
2800 dp
->smudge
->code
= doDoes
;
2801 dp
->smudge
->param
[0] = LVALUEtoCELL(pVM
->ip
);
2807 static void doesCoIm(FICL_VM
*pVM
)
2809 FICL_DICT
*dp
= vmGetDict(pVM
);
2810 #if FICL_WANT_LOCALS
2811 assert(pVM
->pSys
->pUnLinkParen
);
2812 if (pVM
->pSys
->nLocals
> 0)
2814 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
2815 dictEmpty(pLoc
, pLoc
->pForthWords
->size
);
2816 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pUnLinkParen
));
2819 pVM
->pSys
->nLocals
= 0;
2823 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pDoesParen
));
2828 /**************************************************************************
2830 ** to-body CORE ( xt -- a-addr )
2831 ** a-addr is the data-field address corresponding to xt. An ambiguous
2832 ** condition exists if xt is not for a word defined via CREATE.
2833 **************************************************************************/
2834 static void toBody(FICL_VM
*pVM
)
2837 /*#$-GUY CHANGE: Added robustness.-$#*/
2839 vmCheckStack(pVM
, 1, 1);
2843 PUSHPTR(pFW
->param
+ 1);
2849 ** from-body ficl ( a-addr -- xt )
2850 ** Reverse effect of >body
2852 static void fromBody(FICL_VM
*pVM
)
2856 vmCheckStack(pVM
, 1, 1);
2859 ptr
= (char *)POPPTR() - sizeof (FICL_WORD
);
2866 ** >name ficl ( xt -- c-addr u )
2867 ** Push the address and length of a word's name given its address
2870 static void toName(FICL_VM
*pVM
)
2874 vmCheckStack(pVM
, 1, 2);
2879 PUSHUNS(pFW
->nName
);
2884 static void getLastWord(FICL_VM
*pVM
)
2886 FICL_DICT
*pDict
= vmGetDict(pVM
);
2887 FICL_WORD
*wp
= pDict
->smudge
;
2889 vmPush(pVM
, LVALUEtoCELL(wp
));
2894 /**************************************************************************
2895 l b r a c k e t e t c
2897 **************************************************************************/
2899 static void lbracketCoIm(FICL_VM
*pVM
)
2901 pVM
->state
= INTERPRET
;
2906 static void rbracket(FICL_VM
*pVM
)
2908 pVM
->state
= COMPILE
;
2913 /**************************************************************************
2914 p i c t u r e d n u m e r i c w o r d s
2916 ** less-number-sign CORE ( -- )
2917 ** Initialize the pictured numeric output conversion process.
2919 **************************************************************************/
2920 static void lessNumberSign(FICL_VM
*pVM
)
2922 FICL_STRING
*sp
= PTRtoSTRING pVM
->pad
;
2928 ** number-sign CORE ( ud1 -- ud2 )
2929 ** Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
2930 ** n. (n is the least-significant digit of ud1.) Convert n to external form
2931 ** and add the resulting character to the beginning of the pictured numeric
2932 ** output string. An ambiguous condition exists if # executes outside of a
2933 ** <# #> delimited number conversion.
2935 static void numberSign(FICL_VM
*pVM
)
2941 vmCheckStack(pVM
, 2, 2);
2944 sp
= PTRtoSTRING pVM
->pad
;
2945 u
= u64Pop(pVM
->pStack
);
2946 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2947 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2948 u64Push(pVM
->pStack
, u
);
2953 ** number-sign-greater CORE ( xd -- c-addr u )
2954 ** Drop xd. Make the pictured numeric output string available as a character
2955 ** string. c-addr and u specify the resulting character string. A program
2956 ** may replace characters within the string.
2958 static void numberSignGreater(FICL_VM
*pVM
)
2962 vmCheckStack(pVM
, 2, 2);
2965 sp
= PTRtoSTRING pVM
->pad
;
2966 sp
->text
[sp
->count
] = 0;
2975 ** number-sign-s CORE ( ud1 -- ud2 )
2976 ** Convert one digit of ud1 according to the rule for #. Continue conversion
2977 ** until the quotient is zero. ud2 is zero. An ambiguous condition exists if
2978 ** #S executes outside of a <# #> delimited number conversion.
2979 ** TO DO: presently does not use ud1 hi cell - use it!
2981 static void numberSignS(FICL_VM
*pVM
)
2987 vmCheckStack(pVM
, 2, 2);
2990 sp
= PTRtoSTRING pVM
->pad
;
2991 u
= u64Pop(pVM
->pStack
);
2995 rem
= m64UMod(&u
, (UNS16
)(pVM
->base
));
2996 sp
->text
[sp
->count
++] = digit_to_char(rem
);
2998 while (u
.hi
|| u
.lo
);
3000 u64Push(pVM
->pStack
, u
);
3005 ** HOLD CORE ( char -- )
3006 ** Add char to the beginning of the pictured numeric output string. An ambiguous
3007 ** condition exists if HOLD executes outside of a <# #> delimited number conversion.
3009 static void hold(FICL_VM
*pVM
)
3014 vmCheckStack(pVM
, 1, 0);
3017 sp
= PTRtoSTRING pVM
->pad
;
3019 sp
->text
[sp
->count
++] = (char) i
;
3024 ** SIGN CORE ( n -- )
3025 ** If n is negative, add a minus sign to the beginning of the pictured
3026 ** numeric output string. An ambiguous condition exists if SIGN
3027 ** executes outside of a <# #> delimited number conversion.
3029 static void sign(FICL_VM
*pVM
)
3034 vmCheckStack(pVM
, 1, 0);
3037 sp
= PTRtoSTRING pVM
->pad
;
3040 sp
->text
[sp
->count
++] = '-';
3045 /**************************************************************************
3047 ** to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
3048 ** ud2 is the unsigned result of converting the characters within the
3049 ** string specified by c-addr1 u1 into digits, using the number in BASE,
3050 ** and adding each into ud1 after multiplying ud1 by the number in BASE.
3051 ** Conversion continues left-to-right until a character that is not
3052 ** convertible, including any + or -, is encountered or the string is
3053 ** entirely converted. c-addr2 is the location of the first unconverted
3054 ** character or the first character past the end of the string if the string
3055 ** was entirely converted. u2 is the number of unconverted characters in the
3056 ** string. An ambiguous condition exists if ud2 overflows during the
3058 **************************************************************************/
3059 static void toNumber(FICL_VM
*pVM
)
3064 FICL_UNS base
= pVM
->base
;
3069 vmCheckStack(pVM
,4,4);
3073 cp
= (char *)POPPTR();
3074 accum
= u64Pop(pVM
->pStack
);
3076 for (ch
= *cp
; count
> 0; ch
= *++cp
, count
--)
3084 digit
= tolower(ch
) - 'a' + 10;
3086 ** Note: following test also catches chars between 9 and a
3087 ** because 'digit' is unsigned!
3092 accum
= m64Mac(accum
, base
, digit
);
3095 u64Push(pVM
->pStack
, accum
);
3104 /**************************************************************************
3106 ** quit CORE ( -- ) ( R: i*x -- )
3107 ** Empty the return stack, store zero in SOURCE-ID if it is present, make
3108 ** the user input device the input source, and enter interpretation state.
3109 ** Do not display a message. Repeat the following:
3111 ** Accept a line from the input source into the input buffer, set >IN to
3112 ** zero, and interpret.
3113 ** Display the implementation-defined system prompt if in
3114 ** interpretation state, all processing has been completed, and no
3115 ** ambiguous condition exists.
3116 **************************************************************************/
3118 static void quit(FICL_VM
*pVM
)
3120 vmThrow(pVM
, VM_QUIT
);
3125 static void ficlAbort(FICL_VM
*pVM
)
3127 vmThrow(pVM
, VM_ABORT
);
3132 /**************************************************************************
3134 ** accept CORE ( c-addr +n1 -- +n2 )
3135 ** Receive a string of at most +n1 characters. An ambiguous condition
3136 ** exists if +n1 is zero or greater than 32,767. Display graphic characters
3137 ** as they are received. A program that depends on the presence or absence
3138 ** of non-graphic characters in the string has an environmental dependency.
3139 ** The editing functions, if any, that the system performs in order to
3140 ** construct the string are implementation-defined.
3142 ** (Although the standard text doesn't say so, I assume that the intent
3143 ** of 'accept' is to store the string at the address specified on
3145 ** Implementation: if there's more text in the TIB, use it. Otherwise
3146 ** throw out for more text. Copy characters up to the max count into the
3147 ** address given, and return the number of actual characters copied.
3149 ** Note (sobral) this may not be the behavior you'd expect if you're
3150 ** trying to get user input at load time!
3151 **************************************************************************/
3152 static void accept(FICL_VM
*pVM
)
3154 FICL_UNS count
, len
;
3159 vmCheckStack(pVM
,2,1);
3162 pBuf
= vmGetInBuf(pVM
);
3163 pEnd
= vmGetInBufEnd(pVM
);
3166 vmThrow(pVM
, VM_RESTART
);
3169 ** Now we have something in the text buffer - use it
3171 count
= stackPopINT(pVM
->pStack
);
3172 cp
= stackPopPtr(pVM
->pStack
);
3174 len
= (count
< len
) ? count
: len
;
3175 strncpy(cp
, vmGetInBuf(pVM
), len
);
3177 vmUpdateTib(pVM
, pBuf
);
3184 /**************************************************************************
3186 ** 6.1.0705 ALIGN CORE ( -- )
3187 ** If the data-space pointer is not aligned, reserve enough space to
3189 **************************************************************************/
3190 static void align(FICL_VM
*pVM
)
3192 FICL_DICT
*dp
= vmGetDict(pVM
);
3199 /**************************************************************************
3202 **************************************************************************/
3203 static void aligned(FICL_VM
*pVM
)
3207 vmCheckStack(pVM
,1,1);
3211 PUSHPTR(alignPtr(addr
));
3216 /**************************************************************************
3217 b e g i n & f r i e n d s
3218 ** Indefinite loop control structures
3221 ** : X ... BEGIN ... test UNTIL ;
3223 ** : X ... BEGIN ... test WHILE ... REPEAT ;
3224 **************************************************************************/
3225 static void beginCoIm(FICL_VM
*pVM
)
3227 FICL_DICT
*dp
= vmGetDict(pVM
);
3228 markBranch(dp
, pVM
, destTag
);
3232 static void untilCoIm(FICL_VM
*pVM
)
3234 FICL_DICT
*dp
= vmGetDict(pVM
);
3236 assert(pVM
->pSys
->pBranch0
);
3238 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
3239 resolveBackBranch(dp
, pVM
, destTag
);
3243 static void whileCoIm(FICL_VM
*pVM
)
3245 FICL_DICT
*dp
= vmGetDict(pVM
);
3247 assert(pVM
->pSys
->pBranch0
);
3249 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranch0
));
3250 markBranch(dp
, pVM
, origTag
);
3252 dictAppendUNS(dp
, 1);
3256 static void repeatCoIm(FICL_VM
*pVM
)
3258 FICL_DICT
*dp
= vmGetDict(pVM
);
3260 assert(pVM
->pSys
->pBranchParen
);
3261 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3263 /* expect "begin" branch marker */
3264 resolveBackBranch(dp
, pVM
, destTag
);
3265 /* expect "while" branch marker */
3266 resolveForwardBranch(dp
, pVM
, origTag
);
3271 static void againCoIm(FICL_VM
*pVM
)
3273 FICL_DICT
*dp
= vmGetDict(pVM
);
3275 assert(pVM
->pSys
->pBranchParen
);
3276 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pBranchParen
));
3278 /* expect "begin" branch marker */
3279 resolveBackBranch(dp
, pVM
, destTag
);
3284 /**************************************************************************
3285 c h a r & f r i e n d s
3286 ** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
3287 ** Skip leading space delimiters. Parse name delimited by a space.
3288 ** Put the value of its first character onto the stack.
3290 ** bracket-char CORE
3291 ** Interpretation: Interpretation semantics for this word are undefined.
3292 ** Compilation: ( "<spaces>name" -- )
3293 ** Skip leading space delimiters. Parse name delimited by a space.
3294 ** Append the run-time semantics given below to the current definition.
3295 ** Run-time: ( -- char )
3296 ** Place char, the value of the first character of name, on the stack.
3297 **************************************************************************/
3298 static void ficlChar(FICL_VM
*pVM
)
3302 vmCheckStack(pVM
,0,1);
3305 si
= vmGetWord(pVM
);
3306 PUSHUNS((FICL_UNS
)(si
.cp
[0]));
3310 static void charCoIm(FICL_VM
*pVM
)
3317 /**************************************************************************
3319 ** char-plus CORE ( c-addr1 -- c-addr2 )
3320 ** Add the size in address units of a character to c-addr1, giving c-addr2.
3321 **************************************************************************/
3322 static void charPlus(FICL_VM
*pVM
)
3326 vmCheckStack(pVM
,1,1);
3334 /**************************************************************************
3336 ** chars CORE ( n1 -- n2 )
3337 ** n2 is the size in address units of n1 characters.
3338 ** For most processors, this function can be a no-op. To guarantee
3339 ** portability, we'll multiply by sizeof (char).
3340 **************************************************************************/
3341 #if defined (_M_IX86)
3342 #pragma warning(disable: 4127)
3344 static void ficlChars(FICL_VM
*pVM
)
3346 if (sizeof (char) > 1)
3350 vmCheckStack(pVM
,1,1);
3353 PUSHINT(i
* sizeof (char));
3355 /* otherwise no-op! */
3358 #if defined (_M_IX86)
3359 #pragma warning(default: 4127)
3363 /**************************************************************************
3365 ** COUNT CORE ( c-addr1 -- c-addr2 u )
3366 ** Return the character string specification for the counted string stored
3367 ** at c-addr1. c-addr2 is the address of the first character after c-addr1.
3368 ** u is the contents of the character at c-addr1, which is the length in
3369 ** characters of the string at c-addr2.
3370 **************************************************************************/
3371 static void count(FICL_VM
*pVM
)
3375 vmCheckStack(pVM
,1,2);
3384 /**************************************************************************
3385 e n v i r o n m e n t ?
3386 ** environment-query CORE ( c-addr u -- false | i*x true )
3387 ** c-addr is the address of a character string and u is the string's
3388 ** character count. u may have a value in the range from zero to an
3389 ** implementation-defined maximum which shall not be less than 31. The
3390 ** character string should contain a keyword from 3.2.6 Environmental
3391 ** queries or the optional word sets to be checked for correspondence
3392 ** with an attribute of the present environment. If the system treats the
3393 ** attribute as unknown, the returned flag is false; otherwise, the flag
3394 ** is true and the i*x returned is of the type specified in the table for
3395 ** the attribute queried.
3396 **************************************************************************/
3397 static void environmentQ(FICL_VM
*pVM
)
3403 vmCheckStack(pVM
,2,1);
3406 envp
= pVM
->pSys
->envp
;
3407 si
.count
= (FICL_COUNT
)stackPopUNS(pVM
->pStack
);
3408 si
.cp
= stackPopPtr(pVM
->pStack
);
3410 pFW
= dictLookup(envp
, si
);
3414 vmExecute(pVM
, pFW
);
3419 PUSHINT(FICL_FALSE
);
3424 /**************************************************************************
3426 ** EVALUATE CORE ( i*x c-addr u -- j*x )
3427 ** Save the current input source specification. Store minus-one (-1) in
3428 ** SOURCE-ID if it is present. Make the string described by c-addr and u
3429 ** both the input source and input buffer, set >IN to zero, and interpret.
3430 ** When the parse area is empty, restore the prior input source
3431 ** specification. Other stack effects are due to the words EVALUATEd.
3433 **************************************************************************/
3434 static void evaluate(FICL_VM
*pVM
)
3441 vmCheckStack(pVM
,2,0);
3449 pVM
->sourceID
.i
= -1;
3450 result
= ficlExecC(pVM
, cp
, count
);
3452 if (result
!= VM_OUTOFTEXT
)
3453 vmThrow(pVM
, result
);
3459 /**************************************************************************
3460 s t r i n g q u o t e
3461 ** Interpreting: get string delimited by a quote from the input stream,
3462 ** copy to a scratch area, and put its count and address on the stack.
3463 ** Compiling: compile code to push the address and count of a string
3464 ** literal, compile the string from the input stream, and align the dict
3466 **************************************************************************/
3467 static void stringQuoteIm(FICL_VM
*pVM
)
3469 FICL_DICT
*dp
= vmGetDict(pVM
);
3471 if (pVM
->state
== INTERPRET
)
3473 FICL_STRING
*sp
= (FICL_STRING
*) dp
->here
;
3474 vmGetString(pVM
, sp
, '\"');
3478 else /* COMPILE state */
3480 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStringLit
));
3481 dp
->here
= PTRtoCELL
vmGetString(pVM
, (FICL_STRING
*)dp
->here
, '\"');
3489 /**************************************************************************
3491 ** Pop count and char address from stack and print the designated string.
3492 **************************************************************************/
3493 static void type(FICL_VM
*pVM
)
3495 FICL_UNS count
= stackPopUNS(pVM
->pStack
);
3496 char *cp
= stackPopPtr(pVM
->pStack
);
3497 char *pDest
= (char *)ficlMalloc(count
+ 1);
3500 ** Since we don't have an output primitive for a counted string
3501 ** (oops), make sure the string is null terminated. If not, copy
3502 ** and terminate it.
3505 vmThrowErr(pVM
, "Error: out of memory");
3507 strncpy(pDest
, cp
, count
);
3508 pDest
[count
] = '\0';
3510 vmTextOut(pVM
, pDest
, 0);
3516 /**************************************************************************
3518 ** word CORE ( char "<chars>ccc<char>" -- c-addr )
3519 ** Skip leading delimiters. Parse characters ccc delimited by char. An
3520 ** ambiguous condition exists if the length of the parsed string is greater
3521 ** than the implementation-defined length of a counted string.
3523 ** c-addr is the address of a transient region containing the parsed word
3524 ** as a counted string. If the parse area was empty or contained no
3525 ** characters other than the delimiter, the resulting string has a zero
3526 ** length. A space, not included in the length, follows the string. A
3527 ** program may replace characters within the string.
3528 ** NOTE! Ficl also NULL-terminates the dest string.
3529 **************************************************************************/
3530 static void ficlWord(FICL_VM
*pVM
)
3536 vmCheckStack(pVM
,1,1);
3539 sp
= (FICL_STRING
*)pVM
->pad
;
3540 delim
= (char)POPINT();
3541 si
= vmParseStringEx(pVM
, delim
, 1);
3543 if (SI_COUNT(si
) > nPAD
-1)
3544 SI_SETLEN(si
, nPAD
-1);
3546 sp
->count
= (FICL_COUNT
)SI_COUNT(si
);
3547 strncpy(sp
->text
, SI_PTR(si
), SI_COUNT(si
));
3548 /*#$-GUY CHANGE: I added this.-$#*/
3549 sp
->text
[sp
->count
] = 0;
3550 strcat(sp
->text
, " ");
3557 /**************************************************************************
3559 ** ficl PARSE-WORD ( <spaces>name -- c-addr u )
3560 ** Skip leading spaces and parse name delimited by a space. c-addr is the
3561 ** address within the input buffer and u is the length of the selected
3562 ** string. If the parse area is empty, the resulting string has a zero length.
3563 **************************************************************************/
3564 static void parseNoCopy(FICL_VM
*pVM
)
3568 vmCheckStack(pVM
,0,2);
3571 si
= vmGetWord0(pVM
);
3572 PUSHPTR(SI_PTR(si
));
3573 PUSHUNS(SI_COUNT(si
));
3578 /**************************************************************************
3580 ** CORE EXT ( char "ccc<char>" -- c-addr u )
3581 ** Parse ccc delimited by the delimiter char.
3582 ** c-addr is the address (within the input buffer) and u is the length of
3583 ** the parsed string. If the parse area was empty, the resulting string has
3585 ** NOTE! PARSE differs from WORD: it does not skip leading delimiters.
3586 **************************************************************************/
3587 static void parse(FICL_VM
*pVM
)
3593 vmCheckStack(pVM
,1,2);
3596 delim
= (char)POPINT();
3598 si
= vmParseStringEx(pVM
, delim
, 0);
3599 PUSHPTR(SI_PTR(si
));
3600 PUSHUNS(SI_COUNT(si
));
3605 /**************************************************************************
3607 ** CORE ( c-addr u char -- )
3608 ** If u is greater than zero, store char in each of u consecutive
3609 ** characters of memory beginning at c-addr.
3610 **************************************************************************/
3611 static void fill(FICL_VM
*pVM
)
3617 vmCheckStack(pVM
,3,0);
3619 ch
= (char)POPINT();
3621 cp
= (char *)POPPTR();
3632 /**************************************************************************
3634 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3635 ** Find the definition named in the counted string at c-addr. If the
3636 ** definition is not found, return c-addr and zero. If the definition is
3637 ** found, return its execution token xt. If the definition is immediate,
3638 ** also return one (1), otherwise also return minus-one (-1). For a given
3639 ** string, the values returned by FIND while compiling may differ from
3640 ** those returned while not compiling.
3641 **************************************************************************/
3642 static void do_find(FICL_VM
*pVM
, STRINGINFO si
, void *returnForFailure
)
3646 pFW
= dictLookup(vmGetDict(pVM
), si
);
3650 PUSHINT((wordIsImmediate(pFW
) ? 1 : -1));
3654 PUSHPTR(returnForFailure
);
3662 /**************************************************************************
3664 ** FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
3665 ** Find the definition named in the counted string at c-addr. If the
3666 ** definition is not found, return c-addr and zero. If the definition is
3667 ** found, return its execution token xt. If the definition is immediate,
3668 ** also return one (1), otherwise also return minus-one (-1). For a given
3669 ** string, the values returned by FIND while compiling may differ from
3670 ** those returned while not compiling.
3671 **************************************************************************/
3672 static void cFind(FICL_VM
*pVM
)
3678 vmCheckStack(pVM
,1,2);
3682 do_find(pVM
, si
, sp
);
3687 /**************************************************************************
3689 ** FICL ( c-addr u -- 0 0 | xt 1 | xt -1 )
3690 ** Like FIND, but takes "c-addr u" for the string.
3691 **************************************************************************/
3692 static void sFind(FICL_VM
*pVM
)
3697 vmCheckStack(pVM
,2,2);
3700 si
.count
= stackPopINT(pVM
->pStack
);
3701 si
.cp
= stackPopPtr(pVM
->pStack
);
3703 do_find(pVM
, si
, NULL
);
3708 /**************************************************************************
3710 ** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
3711 ** Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
3712 ** Input and output stack arguments are signed. An ambiguous condition
3713 ** exists if n1 is zero or if the quotient lies outside the range of a
3714 ** single-cell signed integer.
3715 **************************************************************************/
3716 static void fmSlashMod(FICL_VM
*pVM
)
3722 vmCheckStack(pVM
,3,2);
3726 d1
= i64Pop(pVM
->pStack
);
3727 qr
= m64FlooredDivI(d1
, n1
);
3734 /**************************************************************************
3736 ** s-m-slash-rem CORE ( d1 n1 -- n2 n3 )
3737 ** Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
3738 ** Input and output stack arguments are signed. An ambiguous condition
3739 ** exists if n1 is zero or if the quotient lies outside the range of a
3740 ** single-cell signed integer.
3741 **************************************************************************/
3742 static void smSlashRem(FICL_VM
*pVM
)
3748 vmCheckStack(pVM
,3,2);
3752 d1
= i64Pop(pVM
->pStack
);
3753 qr
= m64SymmetricDivI(d1
, n1
);
3760 static void ficlMod(FICL_VM
*pVM
)
3766 vmCheckStack(pVM
,2,1);
3772 qr
= m64SymmetricDivI(d1
, n1
);
3778 /**************************************************************************
3780 ** u-m-slash-mod CORE ( ud u1 -- u2 u3 )
3781 ** Divide ud by u1, giving the quotient u3 and the remainder u2.
3782 ** All values and arithmetic are unsigned. An ambiguous condition
3783 ** exists if u1 is zero or if the quotient lies outside the range of a
3784 ** single-cell unsigned integer.
3785 *************************************************************************/
3786 static void umSlashMod(FICL_VM
*pVM
)
3792 u1
= stackPopUNS(pVM
->pStack
);
3793 ud
= u64Pop(pVM
->pStack
);
3794 qr
= ficlLongDiv(ud
, u1
);
3801 /**************************************************************************
3803 ** l-shift CORE ( x1 u -- x2 )
3804 ** Perform a logical left shift of u bit-places on x1, giving x2.
3805 ** Put zeroes into the least significant bits vacated by the shift.
3806 ** An ambiguous condition exists if u is greater than or equal to the
3807 ** number of bits in a cell.
3809 ** r-shift CORE ( x1 u -- x2 )
3810 ** Perform a logical right shift of u bit-places on x1, giving x2.
3811 ** Put zeroes into the most significant bits vacated by the shift. An
3812 ** ambiguous condition exists if u is greater than or equal to the
3813 ** number of bits in a cell.
3814 **************************************************************************/
3815 static void lshift(FICL_VM
*pVM
)
3820 vmCheckStack(pVM
,2,1);
3825 PUSHUNS(x1
<< nBits
);
3830 static void rshift(FICL_VM
*pVM
)
3835 vmCheckStack(pVM
,2,1);
3841 PUSHUNS(x1
>> nBits
);
3846 /**************************************************************************
3848 ** m-star CORE ( n1 n2 -- d )
3849 ** d is the signed product of n1 times n2.
3850 **************************************************************************/
3851 static void mStar(FICL_VM
*pVM
)
3857 vmCheckStack(pVM
,2,2);
3863 d
= m64MulI(n1
, n2
);
3864 i64Push(pVM
->pStack
, d
);
3869 static void umStar(FICL_VM
*pVM
)
3875 vmCheckStack(pVM
,2,2);
3881 ud
= ficlLongMul(u1
, u2
);
3882 u64Push(pVM
->pStack
, ud
);
3887 /**************************************************************************
3890 **************************************************************************/
3891 static void ficlMax(FICL_VM
*pVM
)
3896 vmCheckStack(pVM
,2,1);
3902 PUSHINT((n1
> n2
) ? n1
: n2
);
3906 static void ficlMin(FICL_VM
*pVM
)
3911 vmCheckStack(pVM
,2,1);
3917 PUSHINT((n1
< n2
) ? n1
: n2
);
3922 /**************************************************************************
3924 ** CORE ( addr1 addr2 u -- )
3925 ** If u is greater than zero, copy the contents of u consecutive address
3926 ** units at addr1 to the u consecutive address units at addr2. After MOVE
3927 ** completes, the u consecutive address units at addr2 contain exactly
3928 ** what the u consecutive address units at addr1 contained before the move.
3929 ** NOTE! This implementation assumes that a char is the same size as
3931 **************************************************************************/
3932 static void move(FICL_VM
*pVM
)
3938 vmCheckStack(pVM
,3,0);
3948 ** Do the copy carefully, so as to be
3949 ** correct even if the two ranges overlap
3954 *addr2
++ = *addr1
++;
3961 *addr2
-- = *addr1
--;
3968 /**************************************************************************
3971 **************************************************************************/
3972 static void recurseCoIm(FICL_VM
*pVM
)
3974 FICL_DICT
*pDict
= vmGetDict(pVM
);
3977 dictAppendCell(pDict
, LVALUEtoCELL(pDict
->smudge
));
3982 /**************************************************************************
3984 ** s-to-d CORE ( n -- d )
3985 ** Convert the number n to the double-cell number d with the same
3987 **************************************************************************/
3988 static void sToD(FICL_VM
*pVM
)
3992 vmCheckStack(pVM
,1,2);
3997 /* sign extend to 64 bits.. */
3999 PUSHINT((s
< 0) ? -1 : 0);
4004 /**************************************************************************
4006 ** CORE ( -- c-addr u )
4007 ** c-addr is the address of, and u is the number of characters in, the
4009 **************************************************************************/
4010 static void source(FICL_VM
*pVM
)
4013 vmCheckStack(pVM
,0,2);
4015 PUSHPTR(pVM
->tib
.cp
);
4016 PUSHINT(vmGetInBufLen(pVM
));
4021 /**************************************************************************
4024 **************************************************************************/
4025 static void ficlVersion(FICL_VM
*pVM
)
4027 vmTextOut(pVM
, "ficl Version " FICL_VER
, 1);
4032 /**************************************************************************
4035 **************************************************************************/
4036 static void toIn(FICL_VM
*pVM
)
4039 vmCheckStack(pVM
,0,1);
4041 PUSHPTR(&pVM
->tib
.index
);
4046 /**************************************************************************
4047 c o l o n N o N a m e
4048 ** CORE EXT ( C: -- colon-sys ) ( S: -- xt )
4049 ** Create an unnamed colon definition and push its address.
4050 ** Change state to compile.
4051 **************************************************************************/
4052 static void colonNoName(FICL_VM
*pVM
)
4054 FICL_DICT
*dp
= vmGetDict(pVM
);
4059 SI_SETPTR(si
, NULL
);
4061 pVM
->state
= COMPILE
;
4062 pFW
= dictAppendWord2(dp
, si
, colonParen
, FW_DEFAULT
| FW_SMUDGE
);
4064 markControlTag(pVM
, colonTag
);
4069 /**************************************************************************
4070 u s e r V a r i a b l e
4071 ** user ( u -- ) "<spaces>name"
4072 ** Get a name from the input stream and create a user variable
4073 ** with the name and the index supplied. The run-time effect
4074 ** of a user variable is to push the address of the indexed cell
4075 ** in the running vm's user array.
4077 ** User variables are vm local cells. Each vm has an array of
4078 ** FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
4079 ** Ficl's user facility is implemented with two primitives,
4080 ** "user" and "(user)", a variable ("nUser") (in softcore.c) that
4081 ** holds the index of the next free user cell, and a redefinition
4082 ** (also in softcore) of "user" that defines a user word and increments
4084 **************************************************************************/
4086 static void userParen(FICL_VM
*pVM
)
4088 FICL_INT i
= pVM
->runningWord
->param
[0].i
;
4089 PUSHPTR(&pVM
->user
[i
]);
4094 static void userVariable(FICL_VM
*pVM
)
4096 FICL_DICT
*dp
= vmGetDict(pVM
);
4097 STRINGINFO si
= vmGetWord(pVM
);
4100 c
= stackPop(pVM
->pStack
);
4101 if (c
.i
>= FICL_USER_CELLS
)
4103 vmThrowErr(pVM
, "Error - out of user space");
4106 dictAppendWord2(dp
, si
, userParen
, FW_DEFAULT
);
4107 dictAppendCell(dp
, c
);
4113 /**************************************************************************
4116 ** Interpretation: ( x "<spaces>name" -- )
4117 ** Skip leading spaces and parse name delimited by a space. Store x in
4118 ** name. An ambiguous condition exists if name was not defined by VALUE.
4119 ** NOTE: In ficl, VALUE is an alias of CONSTANT
4120 **************************************************************************/
4121 static void toValue(FICL_VM
*pVM
)
4123 STRINGINFO si
= vmGetWord(pVM
);
4124 FICL_DICT
*dp
= vmGetDict(pVM
);
4127 #if FICL_WANT_LOCALS
4128 if ((pVM
->pSys
->nLocals
> 0) && (pVM
->state
== COMPILE
))
4130 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4131 pFW
= dictLookup(pLoc
, si
);
4132 if (pFW
&& (pFW
->code
== doLocalIm
))
4134 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
4135 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
4138 else if (pFW
&& pFW
->code
== do2LocalIm
)
4140 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
4141 dictAppendCell(dp
, LVALUEtoCELL(pFW
->param
[0]));
4147 assert(pVM
->pSys
->pStore
);
4149 pFW
= dictLookup(dp
, si
);
4152 int i
= SI_COUNT(si
);
4153 vmThrowErr(pVM
, "%.*s not found", i
, SI_PTR(si
));
4156 if (pVM
->state
== INTERPRET
)
4157 pFW
->param
[0] = stackPop(pVM
->pStack
);
4158 else /* compile code to store to word's param */
4160 PUSHPTR(&pFW
->param
[0]);
4162 dictAppendCell(dp
, LVALUEtoCELL(pVM
->pSys
->pStore
));
4168 #if FICL_WANT_LOCALS
4169 /**************************************************************************
4172 ** Link a frame on the return stack, reserving nCells of space for
4173 ** locals - the value of nCells is the next cell in the instruction
4175 **************************************************************************/
4176 static void linkParen(FICL_VM
*pVM
)
4178 FICL_INT nLink
= *(FICL_INT
*)(pVM
->ip
);
4179 vmBranchRelative(pVM
, 1);
4180 stackLink(pVM
->rStack
, nLink
);
4185 static void unlinkParen(FICL_VM
*pVM
)
4187 stackUnlink(pVM
->rStack
);
4192 /**************************************************************************
4194 ** Immediate - cfa of a local while compiling - when executed, compiles
4195 ** code to fetch the value of a local given the local's index in the
4197 **************************************************************************/
4198 static void getLocalParen(FICL_VM
*pVM
)
4200 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4201 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4206 static void toLocalParen(FICL_VM
*pVM
)
4208 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4209 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
4214 static void getLocal0(FICL_VM
*pVM
)
4216 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[0]);
4221 static void toLocal0(FICL_VM
*pVM
)
4223 pVM
->rStack
->pFrame
[0] = stackPop(pVM
->pStack
);
4228 static void getLocal1(FICL_VM
*pVM
)
4230 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[1]);
4235 static void toLocal1(FICL_VM
*pVM
)
4237 pVM
->rStack
->pFrame
[1] = stackPop(pVM
->pStack
);
4243 ** Each local is recorded in a private locals dictionary as a
4244 ** word that does doLocalIm at runtime. DoLocalIm compiles code
4245 ** into the client definition to fetch the value of the
4246 ** corresponding local variable from the return stack.
4247 ** The private dictionary gets initialized at the end of each block
4248 ** that uses locals (in ; and does> for example).
4250 static void doLocalIm(FICL_VM
*pVM
)
4252 FICL_DICT
*pDict
= vmGetDict(pVM
);
4253 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4255 if (pVM
->state
== INTERPRET
)
4257 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4264 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal0
));
4266 else if (nLocal
== 1)
4268 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocal1
));
4272 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGetLocalParen
));
4273 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4280 /**************************************************************************
4282 ** paren-local-paren LOCAL
4283 ** Interpretation: Interpretation semantics for this word are undefined.
4284 ** Execution: ( c-addr u -- )
4285 ** When executed during compilation, (LOCAL) passes a message to the
4286 ** system that has one of two meanings. If u is non-zero,
4287 ** the message identifies a new local whose definition name is given by
4288 ** the string of characters identified by c-addr u. If u is zero,
4289 ** the message is last local and c-addr has no significance.
4291 ** The result of executing (LOCAL) during compilation of a definition is
4292 ** to create a set of named local identifiers, each of which is
4293 ** a definition name, that only have execution semantics within the scope
4294 ** of that definition's source.
4296 ** local Execution: ( -- x )
4298 ** Push the local's value, x, onto the stack. The local's value is
4299 ** initialized as described in 13.3.3 Processing locals and may be
4300 ** changed by preceding the local's name with TO. An ambiguous condition
4301 ** exists when local is executed while in interpretation state.
4302 **************************************************************************/
4303 static void localParen(FICL_VM
*pVM
)
4308 vmCheckStack(pVM
,2,0);
4311 pDict
= vmGetDict(pVM
);
4312 SI_SETLEN(si
, POPUNS());
4313 SI_SETPTR(si
, (char *)POPPTR());
4315 if (SI_COUNT(si
) > 0)
4316 { /* add a local to the **locals** dict and update nLocals */
4317 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4318 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4320 vmThrowErr(pVM
, "Error: out of local space");
4323 dictAppendWord2(pLoc
, si
, doLocalIm
, FW_COMPIMMED
);
4324 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4326 if (pVM
->pSys
->nLocals
== 0)
4327 { /* compile code to create a local stack frame */
4328 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4329 /* save location in dictionary for #locals */
4330 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4331 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4332 /* compile code to initialize first local */
4333 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal0
));
4335 else if (pVM
->pSys
->nLocals
== 1)
4337 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocal1
));
4341 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pToLocalParen
));
4342 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4345 (pVM
->pSys
->nLocals
)++;
4347 else if (pVM
->pSys
->nLocals
> 0)
4348 { /* write nLocals to (link) param area in dictionary */
4349 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4356 static void get2LocalParen(FICL_VM
*pVM
)
4358 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4359 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4360 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4365 static void do2LocalIm(FICL_VM
*pVM
)
4367 FICL_DICT
*pDict
= vmGetDict(pVM
);
4368 FICL_INT nLocal
= pVM
->runningWord
->param
[0].i
;
4370 if (pVM
->state
== INTERPRET
)
4372 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
]);
4373 stackPush(pVM
->pStack
, pVM
->rStack
->pFrame
[nLocal
+1]);
4377 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pGet2LocalParen
));
4378 dictAppendCell(pDict
, LVALUEtoCELL(nLocal
));
4384 static void to2LocalParen(FICL_VM
*pVM
)
4386 FICL_INT nLocal
= *(FICL_INT
*)(pVM
->ip
++);
4387 pVM
->rStack
->pFrame
[nLocal
+1] = stackPop(pVM
->pStack
);
4388 pVM
->rStack
->pFrame
[nLocal
] = stackPop(pVM
->pStack
);
4393 static void twoLocalParen(FICL_VM
*pVM
)
4395 FICL_DICT
*pDict
= vmGetDict(pVM
);
4397 SI_SETLEN(si
, stackPopUNS(pVM
->pStack
));
4398 SI_SETPTR(si
, (char *)stackPopPtr(pVM
->pStack
));
4400 if (SI_COUNT(si
) > 0)
4401 { /* add a local to the **locals** dict and update nLocals */
4402 FICL_DICT
*pLoc
= ficlGetLoc(pVM
->pSys
);
4403 if (pVM
->pSys
->nLocals
>= FICL_MAX_LOCALS
)
4405 vmThrowErr(pVM
, "Error: out of local space");
4408 dictAppendWord2(pLoc
, si
, do2LocalIm
, FW_COMPIMMED
);
4409 dictAppendCell(pLoc
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4411 if (pVM
->pSys
->nLocals
== 0)
4412 { /* compile code to create a local stack frame */
4413 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pLinkParen
));
4414 /* save location in dictionary for #locals */
4415 pVM
->pSys
->pMarkLocals
= pDict
->here
;
4416 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4419 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->pTo2LocalParen
));
4420 dictAppendCell(pDict
, LVALUEtoCELL(pVM
->pSys
->nLocals
));
4422 pVM
->pSys
->nLocals
+= 2;
4424 else if (pVM
->pSys
->nLocals
> 0)
4425 { /* write nLocals to (link) param area in dictionary */
4426 *(FICL_INT
*)(pVM
->pSys
->pMarkLocals
) = pVM
->pSys
->nLocals
;
4434 /**************************************************************************
4436 ** STRING ( c-addr1 u1 c-addr2 u2 -- n )
4437 ** Compare the string specified by c-addr1 u1 to the string specified by
4438 ** c-addr2 u2. The strings are compared, beginning at the given addresses,
4439 ** character by character, up to the length of the shorter string or until a
4440 ** difference is found. If the two strings are identical, n is zero. If the two
4441 ** strings are identical up to the length of the shorter string, n is minus-one
4442 ** (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not
4443 ** identical up to the length of the shorter string, n is minus-one (-1) if the
4444 ** first non-matching character in the string specified by c-addr1 u1 has a
4445 ** lesser numeric value than the corresponding character in the string specified
4446 ** by c-addr2 u2 and one (1) otherwise.
4447 **************************************************************************/
4448 static void compareInternal(FICL_VM
*pVM
, int caseInsensitive
)
4451 FICL_UNS u1
, u2
, uMin
;
4454 vmCheckStack(pVM
, 4, 1);
4455 u2
= stackPopUNS(pVM
->pStack
);
4456 cp2
= (char *)stackPopPtr(pVM
->pStack
);
4457 u1
= stackPopUNS(pVM
->pStack
);
4458 cp1
= (char *)stackPopPtr(pVM
->pStack
);
4460 uMin
= (u1
< u2
)? u1
: u2
;
4461 for ( ; (uMin
> 0) && (n
== 0); uMin
--)
4465 if (caseInsensitive
)
4467 c1
= (char)tolower(c1
);
4468 c2
= (char)tolower(c2
);
4486 static void compareString(FICL_VM
*pVM
)
4488 compareInternal(pVM
, FALSE
);
4492 static void compareStringInsensitive(FICL_VM
*pVM
)
4494 compareInternal(pVM
, TRUE
);
4498 /**************************************************************************
4500 ** CORE EXT ( -- c-addr )
4501 ** c-addr is the address of a transient region that can be used to hold
4502 ** data for intermediate processing.
4503 **************************************************************************/
4504 static void pad(FICL_VM
*pVM
)
4506 stackPushPtr(pVM
->pStack
, pVM
->pad
);
4510 /**************************************************************************
4512 ** CORE EXT, FILE ( -- 0 | -1 | fileid )
4513 ** Identifies the input source as follows:
4515 ** SOURCE-ID Input source
4516 ** --------- ------------
4517 ** fileid Text file fileid
4518 ** -1 String (via EVALUATE)
4519 ** 0 User input device
4520 **************************************************************************/
4521 static void sourceid(FICL_VM
*pVM
)
4523 PUSHINT(pVM
->sourceID
.i
);
4528 /**************************************************************************
4530 ** CORE EXT ( -- flag )
4531 ** Attempt to fill the input buffer from the input source, returning a true
4532 ** flag if successful.
4533 ** When the input source is the user input device, attempt to receive input
4534 ** into the terminal input buffer. If successful, make the result the input
4535 ** buffer, set >IN to zero, and return true. Receipt of a line containing no
4536 ** characters is considered successful. If there is no input available from
4537 ** the current input source, return false.
4538 ** When the input source is a string from EVALUATE, return false and
4539 ** perform no other action.
4540 **************************************************************************/
4541 static void refill(FICL_VM
*pVM
)
4543 FICL_INT ret
= (pVM
->sourceID
.i
== -1) ? FICL_FALSE
: FICL_TRUE
;
4544 if (ret
&& (pVM
->fRestart
== 0))
4545 vmThrow(pVM
, VM_RESTART
);
4552 /**************************************************************************
4553 freebsd exception handling words
4554 ** Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
4555 ** the word in ToS. If an exception happens, restore the state to what
4556 ** it was before, and pushes the exception value on the stack. If not,
4559 ** Notice that Catch implements an inner interpreter. This is ugly,
4560 ** but given how ficl works, it cannot be helped. The problem is that
4561 ** colon definitions will be executed *after* the function returns,
4562 ** while "code" definitions will be executed immediately. I considered
4563 ** other solutions to this problem, but all of them shared the same
4564 ** basic problem (with added disadvantages): if ficl ever changes it's
4565 ** inner thread modus operandi, one would have to fix this word.
4567 ** More comments can be found throughout catch's code.
4569 ** Daniel C. Sobral Jan 09/1999
4570 ** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
4571 **************************************************************************/
4573 static void ficlCatch(FICL_VM
*pVM
)
4583 assert(pVM
->pSys
->pExitInner
);
4588 ** We need this *before* we save the stack pointer, or
4589 ** we'll have to pop one element out of the stack after
4590 ** an exception. I prefer to get done with it up front. :-)
4593 vmCheckStack(pVM
, 1, 0);
4595 pFW
= stackPopPtr(pVM
->pStack
);
4598 ** Save vm's state -- a catch will not back out environmental
4601 ** We are *not* saving dictionary state, since it is
4602 ** global instead of per vm, and we are not saving
4603 ** stack contents, since we are not required to (and,
4604 ** thus, it would be useless). We save pVM, and pVM
4605 ** "stacks" (a structure containing general information
4606 ** about it, including the current stack pointer).
4608 memcpy((void*)&VM
, (void*)pVM
, sizeof(FICL_VM
));
4609 memcpy((void*)&pStack
, (void*)pVM
->pStack
, sizeof(FICL_STACK
));
4610 memcpy((void*)&rStack
, (void*)pVM
->rStack
, sizeof(FICL_STACK
));
4613 ** Give pVM a jmp_buf
4615 pVM
->pState
= &vmState
;
4620 except
= setjmp(vmState
);
4625 ** Setup condition - push poison pill so that the VM throws
4626 ** VM_INNEREXIT if the XT terminates normally, then execute
4630 vmPushIP(pVM
, &(pVM
->pSys
->pExitInner
)); /* Open mouth, insert emetic */
4631 vmExecute(pVM
, pFW
);
4636 ** Normal exit from XT - lose the poison pill,
4637 ** restore old setjmp vector and push a zero.
4640 vmPopIP(pVM
); /* Gack - hurl poison pill */
4641 pVM
->pState
= VM
.pState
; /* Restore just the setjmp vector */
4642 PUSHINT(0); /* Push 0 -- everything is ok */
4646 ** Some other exception got thrown - restore pre-existing VM state
4647 ** and push the exception code
4650 /* Restore vm's state */
4651 memcpy((void*)pVM
, (void*)&VM
, sizeof(FICL_VM
));
4652 memcpy((void*)pVM
->pStack
, (void*)&pStack
, sizeof(FICL_STACK
));
4653 memcpy((void*)pVM
->rStack
, (void*)&rStack
, sizeof(FICL_STACK
));
4655 PUSHINT(except
);/* Push error */
4660 /**************************************************************************
4663 ** Throw -- From ANS Forth standard.
4665 ** Throw takes the ToS and, if that's different from zero,
4666 ** returns to the last executed catch context. Further throws will
4667 ** unstack previously executed "catches", in LIFO mode.
4669 ** Daniel C. Sobral Jan 09/1999
4670 **************************************************************************/
4671 static void ficlThrow(FICL_VM
*pVM
)
4675 except
= stackPopINT(pVM
->pStack
);
4678 vmThrow(pVM
, except
);
4682 /**************************************************************************
4685 **************************************************************************/
4686 static void ansAllocate(FICL_VM
*pVM
)
4691 size
= stackPopINT(pVM
->pStack
);
4692 p
= ficlMalloc(size
);
4701 /**************************************************************************
4704 **************************************************************************/
4705 static void ansFree(FICL_VM
*pVM
)
4709 p
= stackPopPtr(pVM
->pStack
);
4715 /**************************************************************************
4718 **************************************************************************/
4719 static void ansResize(FICL_VM
*pVM
)
4724 size
= stackPopINT(pVM
->pStack
);
4725 old
= stackPopPtr(pVM
->pStack
);
4726 new = ficlRealloc(old
, size
);
4740 /**************************************************************************
4741 ** e x i t - i n n e r
4742 ** Signals execXT that an inner loop has completed
4743 **************************************************************************/
4744 static void ficlExitInner(FICL_VM
*pVM
)
4746 vmThrow(pVM
, VM_INNEREXIT
);
4750 /**************************************************************************
4752 ** DOUBLE ( d1 -- d2 )
4753 ** d2 is the negation of d1.
4754 **************************************************************************/
4755 static void dnegate(FICL_VM
*pVM
)
4757 DPINT i
= i64Pop(pVM
->pStack
);
4759 i64Push(pVM
->pStack
, i
);
4766 /**************************************************************************
4769 **************************************************************************/
4770 static void funcname(FICL_VM
*pVM
)
4778 /**************************************************************************
4779 f i c l W o r d C l a s s i f y
4780 ** This public function helps to classify word types for SEE
4781 ** and the deugger in tools.c. Given a pointer to a word, it returns
4783 **************************************************************************/
4784 WORDKIND
ficlWordClassify(FICL_WORD
*pFW
)
4792 static CODEtoKIND codeMap
[] =
4794 {BRANCH
, branchParen
},
4795 {COLON
, colonParen
},
4796 {CONSTANT
, constantParen
},
4797 {CREATE
, createParen
},
4801 {LITERAL
, literalParen
},
4804 {PLOOP
, plusLoopParen
},
4806 {CSTRINGLIT
, cstringLit
},
4807 {STRINGLIT
, stringLit
},
4811 {VARIABLE
, variableParen
},
4814 #define nMAP (sizeof(codeMap) / sizeof(CODEtoKIND))
4816 FICL_CODE code
= pFW
->code
;
4819 for (i
=0; i
< nMAP
; i
++)
4821 if (codeMap
[i
].code
== code
)
4822 return codeMap
[i
].kind
;
4830 /**************************************************************************
4833 **************************************************************************/
4834 static void ficlRandom(FICL_VM
*pVM
)
4840 /**************************************************************************
4841 ** s e e d - r a n d o m
4843 **************************************************************************/
4844 static void ficlSeedRandom(FICL_VM
*pVM
)
4851 /**************************************************************************
4852 f i c l C o m p i l e C o r e
4853 ** Builds the primitive wordset and the environment-query namespace.
4854 **************************************************************************/
4856 void ficlCompileCore(FICL_SYSTEM
*pSys
)
4858 FICL_DICT
*dp
= pSys
->dp
;
4864 ** see softcore.c for definitions of: abs bl space spaces abort"
4867 dictAppendWord(dp
, "!", store
, FW_DEFAULT
);
4868 dictAppendWord(dp
, "#", numberSign
, FW_DEFAULT
);
4869 dictAppendWord(dp
, "#>", numberSignGreater
,FW_DEFAULT
);
4870 dictAppendWord(dp
, "#s", numberSignS
, FW_DEFAULT
);
4871 dictAppendWord(dp
, "\'", ficlTick
, FW_DEFAULT
);
4872 dictAppendWord(dp
, "(", commentHang
, FW_IMMEDIATE
);
4873 dictAppendWord(dp
, "*", mul
, FW_DEFAULT
);
4874 dictAppendWord(dp
, "*/", mulDiv
, FW_DEFAULT
);
4875 dictAppendWord(dp
, "*/mod", mulDivRem
, FW_DEFAULT
);
4876 dictAppendWord(dp
, "+", add
, FW_DEFAULT
);
4877 dictAppendWord(dp
, "+!", plusStore
, FW_DEFAULT
);
4878 dictAppendWord(dp
, "+loop", plusLoopCoIm
, FW_COMPIMMED
);
4879 dictAppendWord(dp
, ",", comma
, FW_DEFAULT
);
4880 dictAppendWord(dp
, "-", sub
, FW_DEFAULT
);
4881 dictAppendWord(dp
, ".", displayCell
, FW_DEFAULT
);
4882 dictAppendWord(dp
, ".\"", dotQuoteCoIm
, FW_COMPIMMED
);
4883 dictAppendWord(dp
, "/", ficlDiv
, FW_DEFAULT
);
4884 dictAppendWord(dp
, "/mod", slashMod
, FW_DEFAULT
);
4885 dictAppendWord(dp
, "0<", zeroLess
, FW_DEFAULT
);
4886 dictAppendWord(dp
, "0=", zeroEquals
, FW_DEFAULT
);
4887 dictAppendWord(dp
, "1+", onePlus
, FW_DEFAULT
);
4888 dictAppendWord(dp
, "1-", oneMinus
, FW_DEFAULT
);
4889 dictAppendWord(dp
, "2!", twoStore
, FW_DEFAULT
);
4890 dictAppendWord(dp
, "2*", twoMul
, FW_DEFAULT
);
4891 dictAppendWord(dp
, "2/", twoDiv
, FW_DEFAULT
);
4892 dictAppendWord(dp
, "2@", twoFetch
, FW_DEFAULT
);
4893 dictAppendWord(dp
, "2drop", twoDrop
, FW_DEFAULT
);
4894 dictAppendWord(dp
, "2dup", twoDup
, FW_DEFAULT
);
4895 dictAppendWord(dp
, "2over", twoOver
, FW_DEFAULT
);
4896 dictAppendWord(dp
, "2swap", twoSwap
, FW_DEFAULT
);
4897 dictAppendWord(dp
, ":", colon
, FW_DEFAULT
);
4898 dictAppendWord(dp
, ";", semicolonCoIm
, FW_COMPIMMED
);
4899 dictAppendWord(dp
, "<", isLess
, FW_DEFAULT
);
4900 dictAppendWord(dp
, "<#", lessNumberSign
, FW_DEFAULT
);
4901 dictAppendWord(dp
, "=", isEqual
, FW_DEFAULT
);
4902 dictAppendWord(dp
, ">", isGreater
, FW_DEFAULT
);
4903 dictAppendWord(dp
, ">body", toBody
, FW_DEFAULT
);
4904 dictAppendWord(dp
, ">in", toIn
, FW_DEFAULT
);
4905 dictAppendWord(dp
, ">number", toNumber
, FW_DEFAULT
);
4906 dictAppendWord(dp
, ">r", toRStack
, FW_COMPILE
);
4907 dictAppendWord(dp
, "?dup", questionDup
, FW_DEFAULT
);
4908 dictAppendWord(dp
, "@", fetch
, FW_DEFAULT
);
4909 dictAppendWord(dp
, "abort", ficlAbort
, FW_DEFAULT
);
4910 dictAppendWord(dp
, "accept", accept
, FW_DEFAULT
);
4911 dictAppendWord(dp
, "align", align
, FW_DEFAULT
);
4912 dictAppendWord(dp
, "aligned", aligned
, FW_DEFAULT
);
4913 dictAppendWord(dp
, "allot", allot
, FW_DEFAULT
);
4914 dictAppendWord(dp
, "and", bitwiseAnd
, FW_DEFAULT
);
4915 dictAppendWord(dp
, "base", base
, FW_DEFAULT
);
4916 dictAppendWord(dp
, "begin", beginCoIm
, FW_COMPIMMED
);
4917 dictAppendWord(dp
, "c!", cStore
, FW_DEFAULT
);
4918 dictAppendWord(dp
, "c,", cComma
, FW_DEFAULT
);
4919 dictAppendWord(dp
, "c@", cFetch
, FW_DEFAULT
);
4920 dictAppendWord(dp
, "case", caseCoIm
, FW_COMPIMMED
);
4921 dictAppendWord(dp
, "cell+", cellPlus
, FW_DEFAULT
);
4922 dictAppendWord(dp
, "cells", cells
, FW_DEFAULT
);
4923 dictAppendWord(dp
, "char", ficlChar
, FW_DEFAULT
);
4924 dictAppendWord(dp
, "char+", charPlus
, FW_DEFAULT
);
4925 dictAppendWord(dp
, "chars", ficlChars
, FW_DEFAULT
);
4926 dictAppendWord(dp
, "constant", constant
, FW_DEFAULT
);
4927 dictAppendWord(dp
, "count", count
, FW_DEFAULT
);
4928 dictAppendWord(dp
, "cr", cr
, FW_DEFAULT
);
4929 dictAppendWord(dp
, "create", create
, FW_DEFAULT
);
4930 dictAppendWord(dp
, "decimal", decimal
, FW_DEFAULT
);
4931 dictAppendWord(dp
, "depth", depth
, FW_DEFAULT
);
4932 dictAppendWord(dp
, "do", doCoIm
, FW_COMPIMMED
);
4933 dictAppendWord(dp
, "does>", doesCoIm
, FW_COMPIMMED
);
4935 dictAppendWord(dp
, "drop", drop
, FW_DEFAULT
);
4936 dictAppendWord(dp
, "dup", dup
, FW_DEFAULT
);
4937 dictAppendWord(dp
, "else", elseCoIm
, FW_COMPIMMED
);
4938 dictAppendWord(dp
, "emit", emit
, FW_DEFAULT
);
4939 dictAppendWord(dp
, "endcase", endcaseCoIm
, FW_COMPIMMED
);
4940 dictAppendWord(dp
, "endof", endofCoIm
, FW_COMPIMMED
);
4941 dictAppendWord(dp
, "environment?", environmentQ
,FW_DEFAULT
);
4942 dictAppendWord(dp
, "evaluate", evaluate
, FW_DEFAULT
);
4943 dictAppendWord(dp
, "execute", execute
, FW_DEFAULT
);
4944 dictAppendWord(dp
, "exit", exitCoIm
, FW_COMPIMMED
);
4945 dictAppendWord(dp
, "fallthrough",fallthroughCoIm
,FW_COMPIMMED
);
4946 dictAppendWord(dp
, "fill", fill
, FW_DEFAULT
);
4947 dictAppendWord(dp
, "find", cFind
, FW_DEFAULT
);
4948 dictAppendWord(dp
, "fm/mod", fmSlashMod
, FW_DEFAULT
);
4949 dictAppendWord(dp
, "here", here
, FW_DEFAULT
);
4950 dictAppendWord(dp
, "hold", hold
, FW_DEFAULT
);
4951 dictAppendWord(dp
, "i", loopICo
, FW_COMPILE
);
4952 dictAppendWord(dp
, "if", ifCoIm
, FW_COMPIMMED
);
4953 dictAppendWord(dp
, "immediate", immediate
, FW_DEFAULT
);
4954 dictAppendWord(dp
, "invert", bitwiseNot
, FW_DEFAULT
);
4955 dictAppendWord(dp
, "j", loopJCo
, FW_COMPILE
);
4956 dictAppendWord(dp
, "k", loopKCo
, FW_COMPILE
);
4957 dictAppendWord(dp
, "leave", leaveCo
, FW_COMPILE
);
4958 dictAppendWord(dp
, "literal", literalIm
, FW_IMMEDIATE
);
4959 dictAppendWord(dp
, "loop", loopCoIm
, FW_COMPIMMED
);
4960 dictAppendWord(dp
, "lshift", lshift
, FW_DEFAULT
);
4961 dictAppendWord(dp
, "m*", mStar
, FW_DEFAULT
);
4962 dictAppendWord(dp
, "max", ficlMax
, FW_DEFAULT
);
4963 dictAppendWord(dp
, "min", ficlMin
, FW_DEFAULT
);
4964 dictAppendWord(dp
, "mod", ficlMod
, FW_DEFAULT
);
4965 dictAppendWord(dp
, "move", move
, FW_DEFAULT
);
4966 dictAppendWord(dp
, "negate", negate
, FW_DEFAULT
);
4967 dictAppendWord(dp
, "of", ofCoIm
, FW_COMPIMMED
);
4968 dictAppendWord(dp
, "or", bitwiseOr
, FW_DEFAULT
);
4969 dictAppendWord(dp
, "over", over
, FW_DEFAULT
);
4970 dictAppendWord(dp
, "postpone", postponeCoIm
, FW_COMPIMMED
);
4971 dictAppendWord(dp
, "quit", quit
, FW_DEFAULT
);
4972 dictAppendWord(dp
, "r>", fromRStack
, FW_COMPILE
);
4973 dictAppendWord(dp
, "r@", fetchRStack
, FW_COMPILE
);
4974 dictAppendWord(dp
, "recurse", recurseCoIm
, FW_COMPIMMED
);
4975 dictAppendWord(dp
, "repeat", repeatCoIm
, FW_COMPIMMED
);
4976 dictAppendWord(dp
, "rot", rot
, FW_DEFAULT
);
4977 dictAppendWord(dp
, "rshift", rshift
, FW_DEFAULT
);
4978 dictAppendWord(dp
, "s\"", stringQuoteIm
, FW_IMMEDIATE
);
4979 dictAppendWord(dp
, "s>d", sToD
, FW_DEFAULT
);
4980 dictAppendWord(dp
, "sign", sign
, FW_DEFAULT
);
4981 dictAppendWord(dp
, "sm/rem", smSlashRem
, FW_DEFAULT
);
4982 dictAppendWord(dp
, "source", source
, FW_DEFAULT
);
4983 dictAppendWord(dp
, "state", state
, FW_DEFAULT
);
4984 dictAppendWord(dp
, "swap", swap
, FW_DEFAULT
);
4985 dictAppendWord(dp
, "then", endifCoIm
, FW_COMPIMMED
);
4986 dictAppendWord(dp
, "type", type
, FW_DEFAULT
);
4987 dictAppendWord(dp
, "u.", uDot
, FW_DEFAULT
);
4988 dictAppendWord(dp
, "u<", uIsLess
, FW_DEFAULT
);
4989 dictAppendWord(dp
, "u>", uIsGreater
, FW_DEFAULT
);
4990 dictAppendWord(dp
, "um*", umStar
, FW_DEFAULT
);
4991 dictAppendWord(dp
, "um/mod", umSlashMod
, FW_DEFAULT
);
4992 dictAppendWord(dp
, "unloop", unloopCo
, FW_COMPILE
);
4993 dictAppendWord(dp
, "until", untilCoIm
, FW_COMPIMMED
);
4994 dictAppendWord(dp
, "variable", variable
, FW_DEFAULT
);
4995 dictAppendWord(dp
, "while", whileCoIm
, FW_COMPIMMED
);
4996 dictAppendWord(dp
, "word", ficlWord
, FW_DEFAULT
);
4997 dictAppendWord(dp
, "xor", bitwiseXor
, FW_DEFAULT
);
4998 dictAppendWord(dp
, "[", lbracketCoIm
, FW_COMPIMMED
);
4999 dictAppendWord(dp
, "[\']", bracketTickCoIm
,FW_COMPIMMED
);
5000 dictAppendWord(dp
, "[char]", charCoIm
, FW_COMPIMMED
);
5001 dictAppendWord(dp
, "]", rbracket
, FW_DEFAULT
);
5003 ** CORE EXT word set...
5004 ** see softcore.fr for other definitions
5007 dictAppendWord(dp
, ".(", dotParen
, FW_IMMEDIATE
);
5009 dictAppendWord(dp
, "0>", zeroGreater
, FW_DEFAULT
);
5010 dictAppendWord(dp
, "2>r", twoToR
, FW_COMPILE
);
5011 dictAppendWord(dp
, "2r>", twoRFrom
, FW_COMPILE
);
5012 dictAppendWord(dp
, "2r@", twoRFetch
, FW_COMPILE
);
5013 dictAppendWord(dp
, ":noname", colonNoName
, FW_DEFAULT
);
5014 dictAppendWord(dp
, "?do", qDoCoIm
, FW_COMPIMMED
);
5015 dictAppendWord(dp
, "again", againCoIm
, FW_COMPIMMED
);
5016 dictAppendWord(dp
, "c\"", cstringQuoteIm
, FW_IMMEDIATE
);
5017 dictAppendWord(dp
, "hex", hex
, FW_DEFAULT
);
5018 dictAppendWord(dp
, "pad", pad
, FW_DEFAULT
);
5019 dictAppendWord(dp
, "parse", parse
, FW_DEFAULT
);
5020 dictAppendWord(dp
, "pick", pick
, FW_DEFAULT
);
5021 /* query restore-input save-input tib u.r u> unused [compile] */
5022 dictAppendWord(dp
, "roll", roll
, FW_DEFAULT
);
5023 dictAppendWord(dp
, "refill", refill
, FW_DEFAULT
);
5024 dictAppendWord(dp
, "source-id", sourceid
, FW_DEFAULT
);
5025 dictAppendWord(dp
, "to", toValue
, FW_IMMEDIATE
);
5026 dictAppendWord(dp
, "value", constant
, FW_DEFAULT
);
5027 dictAppendWord(dp
, "\\", commentLine
, FW_IMMEDIATE
);
5031 ** Set CORE environment query values
5033 ficlSetEnv(pSys
, "/counted-string", FICL_STRING_MAX
);
5034 ficlSetEnv(pSys
, "/hold", nPAD
);
5035 ficlSetEnv(pSys
, "/pad", nPAD
);
5036 ficlSetEnv(pSys
, "address-unit-bits", 8);
5037 ficlSetEnv(pSys
, "core", FICL_TRUE
);
5038 ficlSetEnv(pSys
, "core-ext", FICL_FALSE
);
5039 ficlSetEnv(pSys
, "floored", FICL_FALSE
);
5040 ficlSetEnv(pSys
, "max-char", UCHAR_MAX
);
5041 ficlSetEnvD(pSys
,"max-d", 0x7fffffff, 0xffffffff);
5042 ficlSetEnv(pSys
, "max-n", 0x7fffffff);
5043 ficlSetEnv(pSys
, "max-u", 0xffffffff);
5044 ficlSetEnvD(pSys
,"max-ud", 0xffffffff, 0xffffffff);
5045 ficlSetEnv(pSys
, "return-stack-cells",FICL_DEFAULT_STACK
);
5046 ficlSetEnv(pSys
, "stack-cells", FICL_DEFAULT_STACK
);
5049 ** DOUBLE word set (partial)
5051 dictAppendWord(dp
, "2constant", twoConstant
, FW_IMMEDIATE
);
5052 dictAppendWord(dp
, "2literal", twoLiteralIm
, FW_IMMEDIATE
);
5053 dictAppendWord(dp
, "2variable", twoVariable
, FW_IMMEDIATE
);
5054 dictAppendWord(dp
, "dnegate", dnegate
, FW_DEFAULT
);
5058 ** EXCEPTION word set
5060 dictAppendWord(dp
, "catch", ficlCatch
, FW_DEFAULT
);
5061 dictAppendWord(dp
, "throw", ficlThrow
, FW_DEFAULT
);
5063 ficlSetEnv(pSys
, "exception", FICL_TRUE
);
5064 ficlSetEnv(pSys
, "exception-ext", FICL_TRUE
);
5067 ** LOCAL and LOCAL EXT
5068 ** see softcore.c for implementation of locals|
5070 #if FICL_WANT_LOCALS
5072 dictAppendWord(dp
, "(link)", linkParen
, FW_COMPILE
);
5073 pSys
->pUnLinkParen
=
5074 dictAppendWord(dp
, "(unlink)", unlinkParen
, FW_COMPILE
);
5075 dictAppendWord(dp
, "doLocal", doLocalIm
, FW_COMPIMMED
);
5076 pSys
->pGetLocalParen
=
5077 dictAppendWord(dp
, "(@local)", getLocalParen
, FW_COMPILE
);
5078 pSys
->pToLocalParen
=
5079 dictAppendWord(dp
, "(toLocal)", toLocalParen
, FW_COMPILE
);
5081 dictAppendWord(dp
, "(@local0)", getLocal0
, FW_COMPILE
);
5083 dictAppendWord(dp
, "(toLocal0)",toLocal0
, FW_COMPILE
);
5085 dictAppendWord(dp
, "(@local1)", getLocal1
, FW_COMPILE
);
5087 dictAppendWord(dp
, "(toLocal1)",toLocal1
, FW_COMPILE
);
5088 dictAppendWord(dp
, "(local)", localParen
, FW_COMPILE
);
5090 pSys
->pGet2LocalParen
=
5091 dictAppendWord(dp
, "(@2local)", get2LocalParen
, FW_COMPILE
);
5092 pSys
->pTo2LocalParen
=
5093 dictAppendWord(dp
, "(to2Local)",to2LocalParen
, FW_COMPILE
);
5094 dictAppendWord(dp
, "(2local)", twoLocalParen
, FW_COMPILE
);
5096 ficlSetEnv(pSys
, "locals", FICL_TRUE
);
5097 ficlSetEnv(pSys
, "locals-ext", FICL_TRUE
);
5098 ficlSetEnv(pSys
, "#locals", FICL_MAX_LOCALS
);
5102 ** Optional MEMORY-ALLOC word set
5105 dictAppendWord(dp
, "allocate", ansAllocate
, FW_DEFAULT
);
5106 dictAppendWord(dp
, "free", ansFree
, FW_DEFAULT
);
5107 dictAppendWord(dp
, "resize", ansResize
, FW_DEFAULT
);
5109 ficlSetEnv(pSys
, "memory-alloc", FICL_TRUE
);
5112 ** optional SEARCH-ORDER word set
5114 ficlCompileSearch(pSys
);
5117 ** TOOLS and TOOLS EXT
5119 ficlCompileTools(pSys
);
5122 ** FILE and FILE EXT
5125 ficlCompileFile(pSys
);
5132 dictAppendWord(dp
, ".hash", dictHashSummary
,FW_DEFAULT
);
5134 dictAppendWord(dp
, ".ver", ficlVersion
, FW_DEFAULT
);
5135 dictAppendWord(dp
, "-roll", minusRoll
, FW_DEFAULT
);
5136 dictAppendWord(dp
, ">name", toName
, FW_DEFAULT
);
5137 dictAppendWord(dp
, "add-parse-step",
5138 addParseStep
, FW_DEFAULT
);
5139 dictAppendWord(dp
, "body>", fromBody
, FW_DEFAULT
);
5140 dictAppendWord(dp
, "compare", compareString
, FW_DEFAULT
); /* STRING */
5141 dictAppendWord(dp
, "compare-insensitive", compareStringInsensitive
, FW_DEFAULT
); /* STRING */
5142 dictAppendWord(dp
, "compile-only",
5143 compileOnly
, FW_DEFAULT
);
5144 dictAppendWord(dp
, "endif", endifCoIm
, FW_COMPIMMED
);
5145 dictAppendWord(dp
, "last-word", getLastWord
, FW_DEFAULT
);
5146 dictAppendWord(dp
, "hash", hash
, FW_DEFAULT
);
5147 dictAppendWord(dp
, "objectify", setObjectFlag
, FW_DEFAULT
);
5148 dictAppendWord(dp
, "?object", isObject
, FW_DEFAULT
);
5149 dictAppendWord(dp
, "parse-word",parseNoCopy
, FW_DEFAULT
);
5150 dictAppendWord(dp
, "sfind", sFind
, FW_DEFAULT
);
5151 dictAppendWord(dp
, "sliteral", sLiteralCoIm
, FW_COMPIMMED
); /* STRING */
5152 dictAppendWord(dp
, "sprintf", ficlSprintf
, FW_DEFAULT
);
5153 dictAppendWord(dp
, "strlen", ficlStrlen
, FW_DEFAULT
);
5154 dictAppendWord(dp
, "q@", quadFetch
, FW_DEFAULT
);
5155 dictAppendWord(dp
, "q!", quadStore
, FW_DEFAULT
);
5156 dictAppendWord(dp
, "w@", wFetch
, FW_DEFAULT
);
5157 dictAppendWord(dp
, "w!", wStore
, FW_DEFAULT
);
5158 dictAppendWord(dp
, "x.", hexDot
, FW_DEFAULT
);
5160 dictAppendWord(dp
, "(user)", userParen
, FW_DEFAULT
);
5161 dictAppendWord(dp
, "user", userVariable
, FW_DEFAULT
);
5164 dictAppendWord(dp
, "random", ficlRandom
, FW_DEFAULT
);
5165 dictAppendWord(dp
, "seed-random",ficlSeedRandom
,FW_DEFAULT
);
5169 ** internal support words
5171 dictAppendWord(dp
, "(create)", createParen
, FW_COMPILE
);
5173 dictAppendWord(dp
, "(exit)", exitParen
, FW_COMPILE
);
5175 dictAppendWord(dp
, "(;)", semiParen
, FW_COMPILE
);
5177 dictAppendWord(dp
, "(literal)", literalParen
, FW_COMPILE
);
5178 pSys
->pTwoLitParen
=
5179 dictAppendWord(dp
, "(2literal)",twoLitParen
, FW_COMPILE
);
5181 dictAppendWord(dp
, "(.\")", stringLit
, FW_COMPILE
);
5183 dictAppendWord(dp
, "(c\")", cstringLit
, FW_COMPILE
);
5185 dictAppendWord(dp
, "(branch0)", branch0
, FW_COMPILE
);
5186 pSys
->pBranchParen
=
5187 dictAppendWord(dp
, "(branch)", branchParen
, FW_COMPILE
);
5189 dictAppendWord(dp
, "(do)", doParen
, FW_COMPILE
);
5191 dictAppendWord(dp
, "(does>)", doesParen
, FW_COMPILE
);
5193 dictAppendWord(dp
, "(?do)", qDoParen
, FW_COMPILE
);
5195 dictAppendWord(dp
, "(loop)", loopParen
, FW_COMPILE
);
5197 dictAppendWord(dp
, "(+loop)", plusLoopParen
, FW_COMPILE
);
5199 dictAppendWord(dp
, "interpret", interpret
, FW_DEFAULT
);
5200 dictAppendWord(dp
, "lookup", lookup
, FW_DEFAULT
);
5202 dictAppendWord(dp
, "(of)", ofParen
, FW_DEFAULT
);
5203 dictAppendWord(dp
, "(variable)",variableParen
, FW_COMPILE
);
5204 dictAppendWord(dp
, "(constant)",constantParen
, FW_COMPILE
);
5205 dictAppendWord(dp
, "(parse-step)",
5206 parseStepParen
, FW_DEFAULT
);
5208 dictAppendWord(dp
, "exit-inner",ficlExitInner
, FW_DEFAULT
);
5211 ** Set up system's outer interpreter loop - maybe this should be in initSystem?
5213 pSys
->pInterp
[0] = pSys
->pInterpret
;
5214 pSys
->pInterp
[1] = pSys
->pBranchParen
;
5215 pSys
->pInterp
[2] = (FICL_WORD
*)(void *)(-2);
5217 assert(dictCellsAvail(dp
) > 0);