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: primitives.c,v 1.4 2010/09/13 18:43:04 asau Exp $
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
48 * Control structure building words use these
49 * strings' addresses as markers on the stack to
50 * check for structure completion.
52 static char doTag
[] = "do";
53 static char colonTag
[] = "colon";
54 static char leaveTag
[] = "leave";
56 static char destTag
[] = "target";
57 static char origTag
[] = "origin";
59 static char caseTag
[] = "case";
60 static char ofTag
[] = "of";
61 static char fallthroughTag
[] = "fallthrough";
64 * C O N T R O L S T R U C T U R E B U I L D E R S
66 * Push current dictionary location for later branch resolution.
67 * The location may be either a branch target or a patch address...
70 markBranch(ficlDictionary
*dictionary
, ficlVm
*vm
, char *tag
)
72 ficlStackPushPointer(vm
->dataStack
, dictionary
->here
);
73 ficlStackPushPointer(vm
->dataStack
, tag
);
77 markControlTag(ficlVm
*vm
, char *tag
)
79 ficlStackPushPointer(vm
->dataStack
, tag
);
83 matchControlTag(ficlVm
*vm
, char *wantTag
)
87 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
89 tag
= (char *)ficlStackPopPointer(vm
->dataStack
);
92 * Changed the code below to compare the pointers first
95 if ((tag
!= wantTag
) && strcmp(tag
, wantTag
)) {
97 "Error -- unmatched control structure \"%s\"", wantTag
);
102 * Expect a branch target address on the param stack,
103 * FICL_VM_STATE_COMPILE a literal offset from the current dictionary location
104 * to the target address
107 resolveBackBranch(ficlDictionary
*dictionary
, ficlVm
*vm
, char *tag
)
109 ficlCell
*patchAddr
, c
;
111 matchControlTag(vm
, tag
);
113 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
115 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
116 c
.i
= patchAddr
- dictionary
->here
;
118 ficlDictionaryAppendCell(dictionary
, c
);
122 * Expect a branch patch address on the param stack,
123 * FICL_VM_STATE_COMPILE a literal offset from the patch location
124 * to the current dictionary location
127 resolveForwardBranch(ficlDictionary
*dictionary
, ficlVm
*vm
, char *tag
)
132 matchControlTag(vm
, tag
);
134 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
136 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
137 offset
= dictionary
->here
- patchAddr
;
138 (*patchAddr
).i
= offset
;
142 * Match the tag to the top of the stack. If success,
143 * sopy "here" address into the ficlCell whose address is next
144 * on the stack. Used by do..leave..loop.
147 resolveAbsBranch(ficlDictionary
*dictionary
, ficlVm
*vm
, char *wantTag
)
152 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
154 tag
= ficlStackPopPointer(vm
->dataStack
);
157 * Changed the comparison below to compare the pointers first
158 * (by popular demand)
160 if ((tag
!= wantTag
) && strcmp(tag
, wantTag
)) {
161 ficlVmTextOut(vm
, "Warning -- Unmatched control word: ");
162 ficlVmTextOut(vm
, wantTag
);
163 ficlVmTextOut(vm
, "\n");
166 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
167 (*patchAddr
).p
= dictionary
->here
;
171 * c o l o n d e f i n i t i o n s
172 * Code to begin compiling a colon definition
173 * This function sets the state to FICL_VM_STATE_COMPILE, then creates a
174 * new word whose name is the next word in the input stream
175 * and whose code is colonParen.
178 ficlPrimitiveColon(ficlVm
*vm
)
180 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
181 ficlString name
= ficlVmGetWord(vm
);
183 vm
->state
= FICL_VM_STATE_COMPILE
;
184 markControlTag(vm
, colonTag
);
185 ficlDictionaryAppendWord(dictionary
, name
,
186 (ficlPrimitive
)ficlInstructionColonParen
,
187 FICL_WORD_DEFAULT
| FICL_WORD_SMUDGED
);
190 vm
->callback
.system
->localsCount
= 0;
195 ficlPrimitiveSemicolonCoIm(ficlVm
*vm
)
197 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
199 matchControlTag(vm
, colonTag
);
202 if (vm
->callback
.system
->localsCount
> 0) {
203 ficlDictionary
*locals
;
204 locals
= ficlSystemGetLocals(vm
->callback
.system
);
205 ficlDictionaryEmpty(locals
, locals
->forthWordlist
->size
);
206 ficlDictionaryAppendUnsigned(dictionary
,
207 ficlInstructionUnlinkParen
);
209 vm
->callback
.system
->localsCount
= 0;
212 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionSemiParen
);
213 vm
->state
= FICL_VM_STATE_INTERPRET
;
214 ficlDictionaryUnsmudge(dictionary
);
220 * This function simply pops the previous instruction
221 * pointer and returns to the "next" loop. Used for exiting from within
222 * a definition. Note that exitParen is identical to semiParen - they
223 * are in two different functions so that "see" can correctly identify
224 * the end of a colon definition, even if it uses "exit".
227 ficlPrimitiveExitCoIm(ficlVm
*vm
)
229 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
233 if (vm
->callback
.system
->localsCount
> 0) {
234 ficlDictionaryAppendUnsigned(dictionary
,
235 ficlInstructionUnlinkParen
);
238 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionExitParen
);
244 * Compiles a constant into the dictionary. Constants return their
245 * value when invoked. Expects a value on top of the parm stack.
248 ficlPrimitiveConstant(ficlVm
*vm
)
250 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
251 ficlString name
= ficlVmGetWord(vm
);
253 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
255 ficlDictionaryAppendConstantInstruction(dictionary
, name
,
256 ficlInstructionConstantParen
, ficlStackPopInteger(vm
->dataStack
));
260 ficlPrimitive2Constant(ficlVm
*vm
)
262 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
263 ficlString name
= ficlVmGetWord(vm
);
265 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
267 ficlDictionaryAppend2ConstantInstruction(dictionary
, name
,
268 ficlInstruction2ConstantParen
, ficlStackPop2Integer(vm
->dataStack
));
272 * d i s p l a y C e l l
273 * Drop and print the contents of the ficlCell at the top of the param
277 ficlPrimitiveDot(ficlVm
*vm
)
281 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
283 c
= ficlStackPop(vm
->dataStack
);
284 ficlLtoa((c
).i
, vm
->pad
, vm
->base
);
285 strcat(vm
->pad
, " ");
286 ficlVmTextOut(vm
, vm
->pad
);
290 ficlPrimitiveUDot(ficlVm
*vm
)
294 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
296 u
= ficlStackPopUnsigned(vm
->dataStack
);
297 ficlUltoa(u
, vm
->pad
, vm
->base
);
298 strcat(vm
->pad
, " ");
299 ficlVmTextOut(vm
, vm
->pad
);
303 ficlPrimitiveHexDot(ficlVm
*vm
)
307 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
309 u
= ficlStackPopUnsigned(vm
->dataStack
);
310 ficlUltoa(u
, vm
->pad
, 16);
311 strcat(vm
->pad
, " ");
312 ficlVmTextOut(vm
, vm
->pad
);
317 * Ficl ( c-string -- length )
319 * Returns the length of a C-style (zero-terminated) string.
324 ficlPrimitiveStrlen(ficlVm
*vm
)
326 char *address
= (char *)ficlStackPopPointer(vm
->dataStack
);
327 ficlStackPushInteger(vm
->dataStack
, strlen(address
));
332 * Ficl ( i*x c-addr-fmt u-fmt c-addr-buffer u-buffer --
333 * c-addr-buffer u-written success-flag )
334 * Similar to the C sprintf() function. It formats into a buffer based on
335 * a "format" string. Each character in the format string is copied verbatim
336 * to the output buffer, until SPRINTF encounters a percent sign ("%").
337 * SPRINTF then skips the percent sign, and examines the next character
338 * (the "format character"). Here are the valid format characters:
339 * s - read a C-ADDR U-LENGTH string from the stack and copy it to
341 * d - read a ficlCell from the stack, format it as a string (base-10,
342 * signed), and copy it to the buffer
343 * x - same as d, except in base-16
344 * u - same as d, but unsigned
345 * % - output a literal percent-sign to the buffer
346 * SPRINTF returns the c-addr-buffer argument unchanged, the number of bytes
347 * written, and a flag indicating whether or not it ran out of space while
348 * writing to the output buffer (FICL_TRUE if it ran out of space).
350 * If SPRINTF runs out of space in the buffer to store the formatted string,
351 * it still continues parsing, in an effort to preserve your stack (otherwise
352 * it might leave uneaten arguments behind).
357 ficlPrimitiveSprintf(ficlVm
*vm
)
359 int bufferLength
= ficlStackPopInteger(vm
->dataStack
);
360 char *buffer
= (char *)ficlStackPopPointer(vm
->dataStack
);
361 char *bufferStart
= buffer
;
363 int formatLength
= ficlStackPopInteger(vm
->dataStack
);
364 char *format
= (char *)ficlStackPopPointer(vm
->dataStack
);
365 char *formatStop
= format
+ formatLength
;
368 int unsignedInteger
= 0; /* false */
370 int append
= 1; /* true */
372 while (format
< formatStop
) {
379 if (*format
!= '%') {
381 actualLength
= desiredLength
= 1;
385 if (format
== formatStop
)
388 leadingZeroes
= (*format
== '0');
391 if (format
== formatStop
)
395 desiredLength
= isdigit((unsigned char)*format
);
397 desiredLength
= strtoul(format
, &format
, 10);
398 if (format
== formatStop
)
400 } else if (*format
== '*') {
402 ficlStackPopInteger(vm
->dataStack
);
405 if (format
== formatStop
)
413 ficlStackPopInteger(vm
->dataStack
);
415 ficlStackPopPointer(vm
->dataStack
);
422 unsignedInteger
= 1; /* true */
426 integer
= ficlStackPopInteger(vm
->dataStack
);
428 ficlUltoa(integer
, scratch
, base
);
430 ficlLtoa(integer
, scratch
, base
);
432 unsignedInteger
= 0; /* false */
434 actualLength
= strlen(scratch
);
447 desiredLength
= actualLength
;
448 if (desiredLength
> bufferLength
) {
449 append
= 0; /* false */
450 desiredLength
= bufferLength
;
452 while (desiredLength
> actualLength
) {
453 *buffer
++ = (char)((leadingZeroes
) ? '0' : ' ');
457 memcpy(buffer
, source
, actualLength
);
458 buffer
+= actualLength
;
459 bufferLength
-= actualLength
;
465 ficlStackPushPointer(vm
->dataStack
, bufferStart
);
466 ficlStackPushInteger(vm
->dataStack
, buffer
- bufferStart
);
467 ficlStackPushInteger(vm
->dataStack
, FICL_BOOL(!append
));
471 * d u p & f r i e n d s
474 ficlPrimitiveDepth(ficlVm
*vm
)
478 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
480 i
= ficlStackDepth(vm
->dataStack
);
481 ficlStackPushInteger(vm
->dataStack
, i
);
485 * e m i t & f r i e n d s
488 ficlPrimitiveEmit(ficlVm
*vm
)
493 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
495 i
= ficlStackPopInteger(vm
->dataStack
);
498 ficlVmTextOut(vm
, buffer
);
502 ficlPrimitiveCR(ficlVm
*vm
)
504 ficlVmTextOut(vm
, "\n");
508 ficlPrimitiveBackslash(ficlVm
*vm
)
510 char *trace
= ficlVmGetInBuf(vm
);
511 char *stop
= ficlVmGetInBufEnd(vm
);
514 while ((trace
!= stop
) && (c
!= '\r') && (c
!= '\n')) {
519 * Cope with DOS or UNIX-style EOLs -
520 * Check for /r, /n, /r/n, or /n/r end-of-line sequences,
521 * and point trace to next char. If EOL is \0, we're done.
526 if ((trace
!= stop
) && (c
!= *trace
) &&
527 ((*trace
== '\r') || (*trace
== '\n')))
531 ficlVmUpdateTib(vm
, trace
);
536 * Compilation: Perform the execution semantics given below.
537 * Execution: ( "ccc<paren>" -- )
538 * Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
539 * The number of characters in ccc may be zero to the number of characters
543 ficlPrimitiveParenthesis(ficlVm
*vm
)
545 ficlVmParseStringEx(vm
, ')', 0);
549 * F E T C H & S T O R E
555 * Compiles code for a conditional branch into the dictionary
556 * and pushes the branch patch address on the stack for later
557 * patching by ELSE or THEN/ENDIF.
560 ficlPrimitiveIfCoIm(ficlVm
*vm
)
562 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
564 ficlDictionaryAppendUnsigned(dictionary
,
565 ficlInstructionBranch0ParenWithCheck
);
566 markBranch(dictionary
, vm
, origTag
);
567 ficlDictionaryAppendUnsigned(dictionary
, 1);
573 * IMMEDIATE -- compiles an "else"...
574 * 1) FICL_VM_STATE_COMPILE a branch and a patch address;
575 * the address gets patched
576 * by "endif" to point past the "else" code.
577 * 2) Pop the the "if" patch address
578 * 3) Patch the "if" branch to point to the current FICL_VM_STATE_COMPILE
580 * 4) Push the "else" patch address. ("endif" patches this to jump past
584 ficlPrimitiveElseCoIm(ficlVm
*vm
)
588 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
590 /* (1) FICL_VM_STATE_COMPILE branch runtime */
591 ficlDictionaryAppendUnsigned(dictionary
,
592 ficlInstructionBranchParenWithCheck
);
594 matchControlTag(vm
, origTag
);
595 /* (2) pop "if" patch addr */
596 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
597 markBranch(dictionary
, vm
, origTag
); /* (4) push "else" patch addr */
599 /* (1) FICL_VM_STATE_COMPILE patch placeholder */
600 ficlDictionaryAppendUnsigned(dictionary
, 1);
601 offset
= dictionary
->here
- patchAddr
;
602 (*patchAddr
).i
= offset
; /* (3) Patch "if" */
609 ficlPrimitiveEndifCoIm(ficlVm
*vm
)
611 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
612 resolveForwardBranch(dictionary
, vm
, origTag
);
617 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
620 * At FICL_VM_STATE_COMPILE-time, a CASE-SYS (see DPANS94 6.2.0873) looks
623 * and an OF-SYS (see DPANS94 6.2.1950) looks like this:
624 * i*addr i caseTag addr ofTag
625 * The integer under caseTag is the count of fixup addresses that branch
629 ficlPrimitiveCaseCoIm(ficlVm
*vm
)
631 FICL_STACK_CHECK(vm
->dataStack
, 0, 2);
633 ficlStackPushUnsigned(vm
->dataStack
, 0);
634 markControlTag(vm
, caseTag
);
638 * e n d c a s eC o I m
639 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
642 ficlPrimitiveEndcaseCoIm(ficlVm
*vm
)
644 ficlUnsigned fixupCount
;
645 ficlDictionary
*dictionary
;
650 * if the last OF ended with FALLTHROUGH,
651 * just add the FALLTHROUGH fixup to the
654 if (ficlStackGetTop(vm
->dataStack
).p
== fallthroughTag
) {
655 matchControlTag(vm
, fallthroughTag
);
656 patchAddr
= ficlStackPopPointer(vm
->dataStack
);
657 matchControlTag(vm
, caseTag
);
658 fixupCount
= ficlStackPopUnsigned(vm
->dataStack
);
659 ficlStackPushPointer(vm
->dataStack
, patchAddr
);
660 ficlStackPushUnsigned(vm
->dataStack
, fixupCount
+ 1);
661 markControlTag(vm
, caseTag
);
664 matchControlTag(vm
, caseTag
);
666 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
668 fixupCount
= ficlStackPopUnsigned(vm
->dataStack
);
669 FICL_STACK_CHECK(vm
->dataStack
, fixupCount
, 0);
671 dictionary
= ficlVmGetDictionary(vm
);
673 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionDrop
);
675 while (fixupCount
--) {
676 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
677 offset
= dictionary
->here
- patchAddr
;
678 (*patchAddr
).i
= offset
;
684 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
687 ficlPrimitiveOfCoIm(ficlVm
*vm
)
689 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
690 ficlCell
*fallthroughFixup
= NULL
;
692 FICL_STACK_CHECK(vm
->dataStack
, 1, 3);
694 if (ficlStackGetTop(vm
->dataStack
).p
== fallthroughTag
) {
695 matchControlTag(vm
, fallthroughTag
);
696 fallthroughFixup
= ficlStackPopPointer(vm
->dataStack
);
699 matchControlTag(vm
, caseTag
);
701 markControlTag(vm
, caseTag
);
703 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionOfParen
);
704 markBranch(dictionary
, vm
, ofTag
);
705 ficlDictionaryAppendUnsigned(dictionary
, 2);
707 if (fallthroughFixup
!= NULL
) {
708 ficlInteger offset
= dictionary
->here
- fallthroughFixup
;
709 (*fallthroughFixup
).i
= offset
;
715 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
718 ficlPrimitiveEndofCoIm(ficlVm
*vm
)
721 ficlUnsigned fixupCount
;
723 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
725 FICL_STACK_CHECK(vm
->dataStack
, 4, 3);
727 /* ensure we're in an OF, */
728 matchControlTag(vm
, ofTag
);
730 /* grab the address of the branch location after the OF */
731 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
732 /* ensure we're also in a "case" */
733 matchControlTag(vm
, caseTag
);
734 /* grab the current number of ENDOF fixups */
735 fixupCount
= ficlStackPopUnsigned(vm
->dataStack
);
737 /* FICL_VM_STATE_COMPILE branch runtime */
738 ficlDictionaryAppendUnsigned(dictionary
,
739 ficlInstructionBranchParenWithCheck
);
742 * push a new ENDOF fixup, the updated count of ENDOF fixups,
745 ficlStackPushPointer(vm
->dataStack
, dictionary
->here
);
746 ficlStackPushUnsigned(vm
->dataStack
, fixupCount
+ 1);
747 markControlTag(vm
, caseTag
);
749 /* reserve space for the ENDOF fixup */
750 ficlDictionaryAppendUnsigned(dictionary
, 2);
752 /* and patch the original OF */
753 offset
= dictionary
->here
- patchAddr
;
754 (*patchAddr
).i
= offset
;
758 * f a l l t h r o u g h C o I m
759 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
762 ficlPrimitiveFallthroughCoIm(ficlVm
*vm
)
766 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
768 FICL_STACK_CHECK(vm
->dataStack
, 4, 3);
770 /* ensure we're in an OF, */
771 matchControlTag(vm
, ofTag
);
772 /* grab the address of the branch location after the OF */
773 patchAddr
= (ficlCell
*)ficlStackPopPointer(vm
->dataStack
);
774 /* ensure we're also in a "case" */
775 matchControlTag(vm
, caseTag
);
777 /* okay, here we go. put the case tag back. */
778 markControlTag(vm
, caseTag
);
780 /* FICL_VM_STATE_COMPILE branch runtime */
781 ficlDictionaryAppendUnsigned(dictionary
,
782 ficlInstructionBranchParenWithCheck
);
784 /* push a new FALLTHROUGH fixup and the fallthroughTag */
785 ficlStackPushPointer(vm
->dataStack
, dictionary
->here
);
786 markControlTag(vm
, fallthroughTag
);
788 /* reserve space for the FALLTHROUGH fixup */
789 ficlDictionaryAppendUnsigned(dictionary
, 2);
791 /* and patch the original OF */
792 offset
= dictionary
->here
- patchAddr
;
793 (*patchAddr
).i
= offset
;
798 * hash ( c-addr u -- code)
799 * calculates hashcode of specified string and leaves it on the stack
802 ficlPrimitiveHash(ficlVm
*vm
)
806 FICL_STRING_SET_LENGTH(s
, ficlStackPopUnsigned(vm
->dataStack
));
807 FICL_STRING_SET_POINTER(s
, ficlStackPopPointer(vm
->dataStack
));
808 ficlStackPushUnsigned(vm
->dataStack
, ficlHashCode(s
));
813 * This is the "user interface" of a Forth. It does the following:
814 * while there are words in the VM's Text Input Buffer
815 * Copy next word into the pad (ficlVmGetWord)
816 * Attempt to find the word in the dictionary (ficlDictionaryLookup)
817 * If successful, execute the word.
818 * Otherwise, attempt to convert the word to a number (isNumber)
819 * If successful, push the number onto the parameter stack.
820 * Otherwise, print an error message and exit loop...
823 * From the standard, section 3.4
824 * Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
825 * repeat the following steps until either the parse area is empty or an
826 * ambiguous condition exists:
827 * a) Skip leading spaces and parse a name (see 3.4.1);
830 ficlPrimitiveInterpret(ficlVm
*vm
)
836 FICL_VM_ASSERT(vm
, vm
);
838 system
= vm
->callback
.system
;
839 s
= ficlVmGetWord0(vm
);
842 * Get next word...if out of text, we're done.
845 ficlVmThrow(vm
, FICL_VM_STATUS_OUT_OF_TEXT
);
849 * Run the parse chain against the incoming token until somebody
850 * eats it. Otherwise emit an error message and give up.
852 for (i
= 0; i
< FICL_MAX_PARSE_STEPS
; i
++) {
853 ficlWord
*word
= system
->parseList
[i
];
858 if (word
->code
== ficlPrimitiveParseStepParen
) {
860 pStep
= (ficlParseStep
)(word
->param
->fn
);
864 ficlStackPushPointer(vm
->dataStack
,
865 FICL_STRING_GET_POINTER(s
));
866 ficlStackPushUnsigned(vm
->dataStack
,
867 FICL_STRING_GET_LENGTH(s
));
868 ficlVmExecuteXT(vm
, word
);
869 if (ficlStackPopInteger(vm
->dataStack
))
874 ficlVmThrowError(vm
, "%.*s not found", FICL_STRING_GET_LENGTH(s
),
875 FICL_STRING_GET_POINTER(s
));
876 /* back to inner interpreter */
880 * Surrogate precompiled parse step for ficlParseWord
881 * (this step is hard coded in FICL_VM_STATE_INTERPRET)
884 ficlPrimitiveLookup(ficlVm
*vm
)
887 FICL_STRING_SET_LENGTH(name
, ficlStackPopUnsigned(vm
->dataStack
));
888 FICL_STRING_SET_POINTER(name
, ficlStackPopPointer(vm
->dataStack
));
889 ficlStackPushInteger(vm
->dataStack
, ficlVmParseWord(vm
, name
));
893 * p a r e n P a r s e S t e p
894 * (parse-step) ( c-addr u -- flag )
895 * runtime for a precompiled parse step - pop a counted string off the
896 * stack, run the parse step against it, and push the result flag (FICL_TRUE
897 * if success, FICL_FALSE otherwise).
900 ficlPrimitiveParseStepParen(ficlVm
*vm
)
903 ficlWord
*word
= vm
->runningWord
;
904 ficlParseStep pStep
= (ficlParseStep
)(word
->param
->fn
);
906 FICL_STRING_SET_LENGTH(s
, ficlStackPopInteger(vm
->dataStack
));
907 FICL_STRING_SET_POINTER(s
, ficlStackPopPointer(vm
->dataStack
));
909 ficlStackPushInteger(vm
->dataStack
, (*pStep
)(vm
, s
));
913 ficlPrimitiveAddParseStep(ficlVm
*vm
)
916 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
918 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
920 pStep
= (ficlWord
*)(ficlStackPop(vm
->dataStack
).p
);
921 if ((pStep
!= NULL
) && ficlDictionaryIsAWord(dictionary
, pStep
))
922 ficlSystemAddParseStep(vm
->callback
.system
, pStep
);
928 * IMMEDIATE code for "literal". This function gets a value from the stack
929 * and compiles it into the dictionary preceded by the code for "(literal)".
933 ficlPrimitiveLiteralIm(ficlVm
*vm
)
935 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
938 value
= ficlStackPopInteger(vm
->dataStack
);
957 ficlDictionaryAppendUnsigned(dictionary
, value
);
977 ficlDictionaryAppendUnsigned(dictionary
,
978 ficlInstruction0
- value
);
982 ficlDictionaryAppendUnsigned(dictionary
,
983 ficlInstructionLiteralParen
);
984 ficlDictionaryAppendUnsigned(dictionary
, value
);
990 ficlPrimitive2LiteralIm(ficlVm
*vm
)
992 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
994 ficlDictionaryAppendUnsigned(dictionary
, ficlInstruction2LiteralParen
);
995 ficlDictionaryAppendCell(dictionary
, ficlStackPop(vm
->dataStack
));
996 ficlDictionaryAppendCell(dictionary
, ficlStackPop(vm
->dataStack
));
1001 * do -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY
1002 * Compiles code to initialize a loop: FICL_VM_STATE_COMPILE (do),
1003 * allot space to hold the "leave" address, push a branch
1004 * target address for the loop.
1005 * (do) -- runtime for "do"
1006 * pops index and limit from the p stack and moves them
1007 * to the r stack, then skips to the loop body.
1008 * loop -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY
1010 * Compiles code for the test part of a loop:
1011 * FICL_VM_STATE_COMPILE (loop), resolve forward branch from "do", and
1012 * copy "here" address to the "leave" address allotted by "do"
1013 * i,j,k -- FICL_VM_STATE_COMPILE ONLY
1014 * Runtime: Push loop indices on param stack (i is innermost loop...)
1015 * Note: each loop has three values on the return stack:
1016 * ( R: leave limit index )
1017 * "leave" is the absolute address of the next ficlCell after the loop
1018 * limit and index are the loop control variables.
1019 * leave -- FICL_VM_STATE_COMPILE ONLY
1020 * Runtime: pop the loop control variables, then pop the
1021 * "leave" address and jump (absolute) there.
1024 ficlPrimitiveDoCoIm(ficlVm
*vm
)
1026 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1028 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionDoParen
);
1030 * Allot space for a pointer to the end
1031 * of the loop - "leave" uses this...
1033 markBranch(dictionary
, vm
, leaveTag
);
1034 ficlDictionaryAppendUnsigned(dictionary
, 0);
1036 * Mark location of head of loop...
1038 markBranch(dictionary
, vm
, doTag
);
1042 ficlPrimitiveQDoCoIm(ficlVm
*vm
)
1044 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1046 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionQDoParen
);
1048 * Allot space for a pointer to the end
1049 * of the loop - "leave" uses this...
1051 markBranch(dictionary
, vm
, leaveTag
);
1052 ficlDictionaryAppendUnsigned(dictionary
, 0);
1054 * Mark location of head of loop...
1056 markBranch(dictionary
, vm
, doTag
);
1061 ficlPrimitiveLoopCoIm(ficlVm
*vm
)
1063 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1065 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionLoopParen
);
1066 resolveBackBranch(dictionary
, vm
, doTag
);
1067 resolveAbsBranch(dictionary
, vm
, leaveTag
);
1071 ficlPrimitivePlusLoopCoIm(ficlVm
*vm
)
1073 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1075 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionPlusLoopParen
);
1076 resolveBackBranch(dictionary
, vm
, doTag
);
1077 resolveAbsBranch(dictionary
, vm
, leaveTag
);
1084 ficlPrimitiveVariable(ficlVm
*vm
)
1086 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1087 ficlString name
= ficlVmGetWord(vm
);
1089 ficlDictionaryAppendWord(dictionary
, name
,
1090 (ficlPrimitive
)ficlInstructionVariableParen
, FICL_WORD_DEFAULT
);
1091 ficlVmDictionaryAllotCells(vm
, dictionary
, 1);
1095 ficlPrimitive2Variable(ficlVm
*vm
)
1097 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1098 ficlString name
= ficlVmGetWord(vm
);
1100 ficlDictionaryAppendWord(dictionary
, name
,
1101 (ficlPrimitive
)ficlInstructionVariableParen
, FICL_WORD_DEFAULT
);
1102 ficlVmDictionaryAllotCells(vm
, dictionary
, 2);
1106 * b a s e & f r i e n d s
1109 ficlPrimitiveBase(ficlVm
*vm
)
1113 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
1115 pBase
= (ficlCell
*)(&vm
->base
);
1117 ficlStackPush(vm
->dataStack
, c
);
1121 ficlPrimitiveDecimal(ficlVm
*vm
)
1128 ficlPrimitiveHex(ficlVm
*vm
)
1134 * a l l o t & f r i e n d s
1137 ficlPrimitiveAllot(ficlVm
*vm
)
1139 ficlDictionary
*dictionary
;
1142 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
1144 dictionary
= ficlVmGetDictionary(vm
);
1145 i
= ficlStackPopInteger(vm
->dataStack
);
1147 FICL_VM_DICTIONARY_CHECK(vm
, dictionary
, i
);
1149 ficlVmDictionaryAllot(vm
, dictionary
, i
);
1153 ficlPrimitiveHere(ficlVm
*vm
)
1155 ficlDictionary
*dictionary
;
1157 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
1159 dictionary
= ficlVmGetDictionary(vm
);
1160 ficlStackPushPointer(vm
->dataStack
, dictionary
->here
);
1165 * tick CORE ( "<spaces>name" -- xt )
1166 * Skip leading space delimiters. Parse name delimited by a space. Find
1167 * name and return xt, the execution token for name. An ambiguous condition
1168 * exists if name is not found.
1171 ficlPrimitiveTick(ficlVm
*vm
)
1173 ficlWord
*word
= NULL
;
1174 ficlString name
= ficlVmGetWord(vm
);
1176 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
1178 word
= ficlDictionaryLookup(ficlVmGetDictionary(vm
), name
);
1180 ficlVmThrowError(vm
, "%.*s not found",
1181 FICL_STRING_GET_LENGTH(name
),
1182 FICL_STRING_GET_POINTER(name
));
1183 ficlStackPushPointer(vm
->dataStack
, word
);
1187 ficlPrimitiveBracketTickCoIm(ficlVm
*vm
)
1189 ficlPrimitiveTick(vm
);
1190 ficlPrimitiveLiteralIm(vm
);
1195 * Lookup the next word in the input stream and FICL_VM_STATE_COMPILE code to
1196 * insert it into definitions created by the resulting word
1197 * (defers compilation, even of immediate words)
1200 ficlPrimitivePostponeCoIm(ficlVm
*vm
)
1202 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1204 ficlWord
*pComma
= ficlSystemLookup(vm
->callback
.system
, ",");
1207 FICL_VM_ASSERT(vm
, pComma
);
1209 ficlPrimitiveTick(vm
);
1210 word
= ficlStackGetTop(vm
->dataStack
).p
;
1211 if (ficlWordIsImmediate(word
)) {
1212 ficlDictionaryAppendCell(dictionary
,
1213 ficlStackPop(vm
->dataStack
));
1215 ficlPrimitiveLiteralIm(vm
);
1217 ficlDictionaryAppendCell(dictionary
, c
);
1223 * Pop an execution token (pointer to a word) off the stack and
1227 ficlPrimitiveExecute(ficlVm
*vm
)
1231 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
1233 word
= ficlStackPopPointer(vm
->dataStack
);
1234 ficlVmExecuteWord(vm
, word
);
1239 * Make the most recently compiled word IMMEDIATE -- it executes even
1240 * in FICL_VM_STATE_COMPILE state (most often used for control compiling words
1241 * such as IF, THEN, etc)
1244 ficlPrimitiveImmediate(ficlVm
*vm
)
1247 ficlDictionarySetImmediate(ficlVmGetDictionary(vm
));
1251 ficlPrimitiveCompileOnly(ficlVm
*vm
)
1254 ficlDictionarySetFlags(ficlVmGetDictionary(vm
), FICL_WORD_COMPILE_ONLY
);
1258 ficlPrimitiveSetObjectFlag(ficlVm
*vm
)
1261 ficlDictionarySetFlags(ficlVmGetDictionary(vm
), FICL_WORD_OBJECT
);
1265 ficlPrimitiveIsObject(ficlVm
*vm
)
1268 ficlWord
*word
= (ficlWord
*)ficlStackPopPointer(vm
->dataStack
);
1270 flag
= ((word
!= NULL
) && (word
->flags
& FICL_WORD_OBJECT
))?
1271 FICL_TRUE
: FICL_FALSE
;
1273 ficlStackPushInteger(vm
->dataStack
, flag
);
1277 ficlPrimitiveCountedStringQuoteIm(ficlVm
*vm
)
1279 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1281 if (vm
->state
== FICL_VM_STATE_INTERPRET
) {
1282 ficlCountedString
*counted
= (ficlCountedString
*)
1285 ficlVmGetString(vm
, counted
, '\"');
1286 ficlStackPushPointer(vm
->dataStack
, counted
);
1289 * move HERE past string so it doesn't get overwritten. --lch
1291 ficlVmDictionaryAllot(vm
, dictionary
,
1292 counted
->length
+ sizeof (ficlUnsigned8
));
1293 } else { /* FICL_VM_STATE_COMPILE state */
1294 ficlDictionaryAppendUnsigned(dictionary
,
1295 ficlInstructionCStringLiteralParen
);
1297 FICL_POINTER_TO_CELL(ficlVmGetString(vm
,
1298 (ficlCountedString
*)dictionary
->here
, '\"'));
1299 ficlDictionaryAlign(dictionary
);
1305 * IMMEDIATE word that compiles a string literal for later display
1306 * FICL_VM_STATE_COMPILE fiStringLiteralParen, then copy the bytes of the
1308 * TIB to the dictionary. Backpatch the count byte and align the dictionary.
1311 ficlPrimitiveDotQuoteCoIm(ficlVm
*vm
)
1313 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1314 ficlWord
*pType
= ficlSystemLookup(vm
->callback
.system
, "type");
1317 FICL_VM_ASSERT(vm
, pType
);
1319 ficlDictionaryAppendUnsigned(dictionary
,
1320 ficlInstructionStringLiteralParen
);
1322 FICL_POINTER_TO_CELL(ficlVmGetString(vm
,
1323 (ficlCountedString
*)dictionary
->here
, '\"'));
1324 ficlDictionaryAlign(dictionary
);
1326 ficlDictionaryAppendCell(dictionary
, c
);
1330 ficlPrimitiveDotParen(ficlVm
*vm
)
1332 char *from
= ficlVmGetInBuf(vm
);
1333 char *stop
= ficlVmGetInBufEnd(vm
);
1338 * Note: the standard does not want leading spaces skipped.
1340 for (c
= *from
; (from
!= stop
) && (c
!= ')'); c
= *++from
)
1344 if ((from
!= stop
) && (c
== ')'))
1347 ficlVmTextOut(vm
, vm
->pad
);
1348 ficlVmUpdateTib(vm
, from
);
1354 * Interpretation: Interpretation semantics for this word are undefined.
1355 * Compilation: ( c-addr1 u -- )
1356 * Append the run-time semantics given below to the current definition.
1357 * Run-time: ( -- c-addr2 u )
1358 * Return c-addr2 u describing a string consisting of the characters
1359 * specified by c-addr1 u during compilation. A program shall not alter
1360 * the returned string.
1362 static void ficlPrimitiveSLiteralCoIm(ficlVm
*vm
)
1364 ficlDictionary
*dictionary
;
1367 ficlUnsigned length
;
1369 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
1371 dictionary
= ficlVmGetDictionary(vm
);
1372 length
= ficlStackPopUnsigned(vm
->dataStack
);
1373 from
= ficlStackPopPointer(vm
->dataStack
);
1375 ficlDictionaryAppendUnsigned(dictionary
,
1376 ficlInstructionStringLiteralParen
);
1377 to
= (char *)dictionary
->here
;
1378 *to
++ = (char)length
;
1380 for (; length
> 0; --length
) {
1385 dictionary
->here
= FICL_POINTER_TO_CELL(ficlAlignPointer(to
));
1390 * Return the address of the VM's state member (must be sized the
1391 * same as a ficlCell for this reason)
1393 static void ficlPrimitiveState(ficlVm
*vm
)
1395 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
1396 ficlStackPushPointer(vm
->dataStack
, &vm
->state
);
1400 * c r e a t e . . . d o e s >
1401 * Make a new word in the dictionary with the run-time effect of
1402 * a variable (push my address), but with extra space allotted
1403 * for use by does> .
1406 ficlPrimitiveCreate(ficlVm
*vm
)
1408 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1409 ficlString name
= ficlVmGetWord(vm
);
1411 ficlDictionaryAppendWord(dictionary
, name
,
1412 (ficlPrimitive
)ficlInstructionCreateParen
, FICL_WORD_DEFAULT
);
1413 ficlVmDictionaryAllotCells(vm
, dictionary
, 1);
1417 ficlPrimitiveDoesCoIm(ficlVm
*vm
)
1419 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1420 #if FICL_WANT_LOCALS
1421 if (vm
->callback
.system
->localsCount
> 0) {
1422 ficlDictionary
*locals
=
1423 ficlSystemGetLocals(vm
->callback
.system
);
1424 ficlDictionaryEmpty(locals
, locals
->forthWordlist
->size
);
1425 ficlDictionaryAppendUnsigned(dictionary
,
1426 ficlInstructionUnlinkParen
);
1429 vm
->callback
.system
->localsCount
= 0;
1433 ficlDictionaryAppendUnsigned(dictionary
, ficlInstructionDoesParen
);
1438 * to-body CORE ( xt -- a-addr )
1439 * a-addr is the data-field address corresponding to xt. An ambiguous
1440 * condition exists if xt is not for a word defined via CREATE.
1443 ficlPrimitiveToBody(ficlVm
*vm
)
1446 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
1448 word
= ficlStackPopPointer(vm
->dataStack
);
1449 ficlStackPushPointer(vm
->dataStack
, word
->param
+ 1);
1453 * from-body Ficl ( a-addr -- xt )
1454 * Reverse effect of >body
1457 ficlPrimitiveFromBody(ficlVm
*vm
)
1460 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
1462 ptr
= (char *)ficlStackPopPointer(vm
->dataStack
) - sizeof (ficlWord
);
1463 ficlStackPushPointer(vm
->dataStack
, ptr
);
1467 * >name Ficl ( xt -- c-addr u )
1468 * Push the address and length of a word's name given its address
1472 ficlPrimitiveToName(ficlVm
*vm
)
1476 FICL_STACK_CHECK(vm
->dataStack
, 1, 2);
1478 word
= ficlStackPopPointer(vm
->dataStack
);
1479 ficlStackPushPointer(vm
->dataStack
, word
->name
);
1480 ficlStackPushUnsigned(vm
->dataStack
, word
->length
);
1484 ficlPrimitiveLastWord(ficlVm
*vm
)
1486 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1487 ficlWord
*wp
= dictionary
->smudge
;
1490 FICL_VM_ASSERT(vm
, wp
);
1497 * l b r a c k e t e t c
1500 ficlPrimitiveLeftBracketCoIm(ficlVm
*vm
)
1502 vm
->state
= FICL_VM_STATE_INTERPRET
;
1506 ficlPrimitiveRightBracket(ficlVm
*vm
)
1508 vm
->state
= FICL_VM_STATE_COMPILE
;
1512 * p i c t u r e d n u m e r i c w o r d s
1514 * less-number-sign CORE ( -- )
1515 * Initialize the pictured numeric output conversion process.
1519 ficlPrimitiveLessNumberSign(ficlVm
*vm
)
1521 ficlCountedString
*counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1522 counted
->length
= 0;
1526 * number-sign CORE ( ud1 -- ud2 )
1527 * Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
1528 * n. (n is the least-significant digit of ud1.) Convert n to external form
1529 * and add the resulting character to the beginning of the pictured numeric
1530 * output string. An ambiguous condition exists if # executes outside of a
1531 * <# #> delimited number conversion.
1534 ficlPrimitiveNumberSign(ficlVm
*vm
)
1536 ficlCountedString
*counted
;
1538 ficl2UnsignedQR uqr
;
1540 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
1542 counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1543 u
= ficlStackPop2Unsigned(vm
->dataStack
);
1544 uqr
= ficl2UnsignedDivide(u
, (ficlUnsigned16
)(vm
->base
));
1545 counted
->text
[counted
->length
++] = ficlDigitToCharacter(uqr
.remainder
);
1546 ficlStackPush2Unsigned(vm
->dataStack
, uqr
.quotient
);
1550 * number-sign-greater CORE ( xd -- c-addr u )
1551 * Drop xd. Make the pictured numeric output string available as a character
1552 * string. c-addr and u specify the resulting character string. A program
1553 * may replace characters within the string.
1556 ficlPrimitiveNumberSignGreater(ficlVm
*vm
)
1558 ficlCountedString
*counted
;
1560 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
1562 counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1563 counted
->text
[counted
->length
] = 0;
1564 ficlStringReverse(counted
->text
);
1565 ficlStackDrop(vm
->dataStack
, 2);
1566 ficlStackPushPointer(vm
->dataStack
, counted
->text
);
1567 ficlStackPushUnsigned(vm
->dataStack
, counted
->length
);
1571 * number-sign-s CORE ( ud1 -- ud2 )
1572 * Convert one digit of ud1 according to the rule for #. Continue conversion
1573 * until the quotient is zero. ud2 is zero. An ambiguous condition exists if
1574 * #S executes outside of a <# #> delimited number conversion.
1575 * TO DO: presently does not use ud1 hi ficlCell - use it!
1578 ficlPrimitiveNumberSignS(ficlVm
*vm
)
1580 ficlCountedString
*counted
;
1582 ficl2UnsignedQR uqr
;
1584 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
1586 counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1587 u
= ficlStackPop2Unsigned(vm
->dataStack
);
1590 uqr
= ficl2UnsignedDivide(u
, (ficlUnsigned16
)(vm
->base
));
1591 counted
->text
[counted
->length
++] =
1592 ficlDigitToCharacter(uqr
.remainder
);
1594 } while (FICL_2UNSIGNED_NOT_ZERO(u
));
1596 ficlStackPush2Unsigned(vm
->dataStack
, u
);
1600 * HOLD CORE ( char -- )
1601 * Add char to the beginning of the pictured numeric output string.
1602 * An ambiguous condition exists if HOLD executes outside of a <# #>
1603 * delimited number conversion.
1606 ficlPrimitiveHold(ficlVm
*vm
)
1608 ficlCountedString
*counted
;
1611 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
1613 counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1614 i
= ficlStackPopInteger(vm
->dataStack
);
1615 counted
->text
[counted
->length
++] = (char)i
;
1619 * SIGN CORE ( n -- )
1620 * If n is negative, add a minus sign to the beginning of the pictured
1621 * numeric output string. An ambiguous condition exists if SIGN
1622 * executes outside of a <# #> delimited number conversion.
1625 ficlPrimitiveSign(ficlVm
*vm
)
1627 ficlCountedString
*counted
;
1630 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
1632 counted
= FICL_POINTER_TO_COUNTED_STRING(vm
->pad
);
1633 i
= ficlStackPopInteger(vm
->dataStack
);
1635 counted
->text
[counted
->length
++] = '-';
1640 * to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
1641 * ud2 is the unsigned result of converting the characters within the
1642 * string specified by c-addr1 u1 into digits, using the number in BASE,
1643 * and adding each into ud1 after multiplying ud1 by the number in BASE.
1644 * Conversion continues left-to-right until a character that is not
1645 * convertible, including any + or -, is encountered or the string is
1646 * entirely converted. c-addr2 is the location of the first unconverted
1647 * character or the first character past the end of the string if the string
1648 * was entirely converted. u2 is the number of unconverted characters in the
1649 * string. An ambiguous condition exists if ud2 overflows during the
1653 ficlPrimitiveToNumber(ficlVm
*vm
)
1655 ficlUnsigned length
;
1657 ficl2Unsigned accumulator
;
1658 ficlUnsigned base
= vm
->base
;
1662 FICL_STACK_CHECK(vm
->dataStack
, 4, 4);
1664 length
= ficlStackPopUnsigned(vm
->dataStack
);
1665 trace
= (char *)ficlStackPopPointer(vm
->dataStack
);
1666 accumulator
= ficlStackPop2Unsigned(vm
->dataStack
);
1668 for (c
= *trace
; length
> 0; c
= *++trace
, length
--) {
1675 digit
= tolower(c
) - 'a' + 10;
1677 * Note: following test also catches chars between 9 and a
1678 * because 'digit' is unsigned!
1683 accumulator
= ficl2UnsignedMultiplyAccumulate(accumulator
,
1687 ficlStackPush2Unsigned(vm
->dataStack
, accumulator
);
1688 ficlStackPushPointer(vm
->dataStack
, trace
);
1689 ficlStackPushUnsigned(vm
->dataStack
, length
);
1693 * q u i t & a b o r t
1694 * quit CORE ( -- ) ( R: i*x -- )
1695 * Empty the return stack, store zero in SOURCE-ID if it is present, make
1696 * the user input device the input source, and enter interpretation state.
1697 * Do not display a message. Repeat the following:
1699 * Accept a line from the input source into the input buffer, set >IN to
1700 * zero, and FICL_VM_STATE_INTERPRET.
1701 * Display the implementation-defined system prompt if in
1702 * interpretation state, all processing has been completed, and no
1703 * ambiguous condition exists.
1706 ficlPrimitiveQuit(ficlVm
*vm
)
1708 ficlVmThrow(vm
, FICL_VM_STATUS_QUIT
);
1712 ficlPrimitiveAbort(ficlVm
*vm
)
1714 ficlVmThrow(vm
, FICL_VM_STATUS_ABORT
);
1719 * accept CORE ( c-addr +n1 -- +n2 )
1720 * Receive a string of at most +n1 characters. An ambiguous condition
1721 * exists if +n1 is zero or greater than 32,767. Display graphic characters
1722 * as they are received. A program that depends on the presence or absence
1723 * of non-graphic characters in the string has an environmental dependency.
1724 * The editing functions, if any, that the system performs in order to
1725 * construct the string are implementation-defined.
1727 * (Although the standard text doesn't say so, I assume that the intent
1728 * of 'accept' is to store the string at the address specified on
1731 * NOTE: getchar() is used there as its present both in loader and
1732 * userland; however, the more correct solution would be to set
1733 * terminal to raw mode for userland.
1736 ficlPrimitiveAccept(ficlVm
*vm
)
1741 ficlUnsigned length
= 0;
1743 FICL_STACK_CHECK(vm
->dataStack
, 2, 1);
1745 size
= ficlStackPopInteger(vm
->dataStack
);
1746 address
= ficlStackPopPointer(vm
->dataStack
);
1748 while (size
!= length
) {
1750 if (c
== '\n' || c
== '\r')
1752 address
[length
++] = c
;
1754 ficlStackPushInteger(vm
->dataStack
, length
);
1759 * 6.1.0705 ALIGN CORE ( -- )
1760 * If the data-space pointer is not aligned, reserve enough space to
1764 ficlPrimitiveAlign(ficlVm
*vm
)
1766 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1768 ficlDictionaryAlign(dictionary
);
1775 ficlPrimitiveAligned(ficlVm
*vm
)
1779 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
1781 addr
= ficlStackPopPointer(vm
->dataStack
);
1782 ficlStackPushPointer(vm
->dataStack
, ficlAlignPointer(addr
));
1786 * b e g i n & f r i e n d s
1787 * Indefinite loop control structures
1790 * : X ... BEGIN ... test UNTIL ;
1792 * : X ... BEGIN ... test WHILE ... REPEAT ;
1795 ficlPrimitiveBeginCoIm(ficlVm
*vm
)
1797 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1798 markBranch(dictionary
, vm
, destTag
);
1802 ficlPrimitiveUntilCoIm(ficlVm
*vm
)
1804 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1806 ficlDictionaryAppendUnsigned(dictionary
,
1807 ficlInstructionBranch0ParenWithCheck
);
1808 resolveBackBranch(dictionary
, vm
, destTag
);
1812 ficlPrimitiveWhileCoIm(ficlVm
*vm
)
1814 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1816 FICL_STACK_CHECK(vm
->dataStack
, 2, 5);
1818 ficlDictionaryAppendUnsigned(dictionary
,
1819 ficlInstructionBranch0ParenWithCheck
);
1820 markBranch(dictionary
, vm
, origTag
);
1822 /* equivalent to 2swap */
1823 ficlStackRoll(vm
->dataStack
, 3);
1824 ficlStackRoll(vm
->dataStack
, 3);
1826 ficlDictionaryAppendUnsigned(dictionary
, 1);
1830 ficlPrimitiveRepeatCoIm(ficlVm
*vm
)
1832 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1834 ficlDictionaryAppendUnsigned(dictionary
,
1835 ficlInstructionBranchParenWithCheck
);
1836 /* expect "begin" branch marker */
1837 resolveBackBranch(dictionary
, vm
, destTag
);
1838 /* expect "while" branch marker */
1839 resolveForwardBranch(dictionary
, vm
, origTag
);
1843 ficlPrimitiveAgainCoIm(ficlVm
*vm
)
1845 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
1847 ficlDictionaryAppendUnsigned(dictionary
,
1848 ficlInstructionBranchParenWithCheck
);
1849 /* expect "begin" branch marker */
1850 resolveBackBranch(dictionary
, vm
, destTag
);
1854 * c h a r & f r i e n d s
1855 * 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
1856 * Skip leading space delimiters. Parse name delimited by a space.
1857 * Put the value of its first character onto the stack.
1860 * Interpretation: Interpretation semantics for this word are undefined.
1861 * Compilation: ( "<spaces>name" -- )
1862 * Skip leading space delimiters. Parse name delimited by a space.
1863 * Append the run-time semantics given below to the current definition.
1864 * Run-time: ( -- char )
1865 * Place char, the value of the first character of name, on the stack.
1868 ficlPrimitiveChar(ficlVm
*vm
)
1872 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
1874 s
= ficlVmGetWord(vm
);
1875 ficlStackPushUnsigned(vm
->dataStack
, (ficlUnsigned
)(s
.text
[0]));
1879 ficlPrimitiveCharCoIm(ficlVm
*vm
)
1881 ficlPrimitiveChar(vm
);
1882 ficlPrimitiveLiteralIm(vm
);
1887 * char-plus CORE ( c-addr1 -- c-addr2 )
1888 * Add the size in address units of a character to c-addr1, giving c-addr2.
1891 ficlPrimitiveCharPlus(ficlVm
*vm
)
1895 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
1897 p
= ficlStackPopPointer(vm
->dataStack
);
1898 ficlStackPushPointer(vm
->dataStack
, p
+ 1);
1903 * chars CORE ( n1 -- n2 )
1904 * n2 is the size in address units of n1 characters.
1905 * For most processors, this function can be a no-op. To guarantee
1906 * portability, we'll multiply by sizeof (char).
1908 #if defined(_M_IX86)
1909 #pragma warning(disable: 4127)
1912 ficlPrimitiveChars(ficlVm
*vm
)
1914 if (sizeof (char) > 1) {
1917 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
1919 i
= ficlStackPopInteger(vm
->dataStack
);
1920 ficlStackPushInteger(vm
->dataStack
, i
* sizeof (char));
1922 /* otherwise no-op! */
1924 #if defined(_M_IX86)
1925 #pragma warning(default: 4127)
1930 * COUNT CORE ( c-addr1 -- c-addr2 u )
1931 * Return the character string specification for the counted string stored
1932 * at c-addr1. c-addr2 is the address of the first character after c-addr1.
1933 * u is the contents of the character at c-addr1, which is the length in
1934 * characters of the string at c-addr2.
1937 ficlPrimitiveCount(ficlVm
*vm
)
1939 ficlCountedString
*counted
;
1941 FICL_STACK_CHECK(vm
->dataStack
, 1, 2);
1943 counted
= ficlStackPopPointer(vm
->dataStack
);
1944 ficlStackPushPointer(vm
->dataStack
, counted
->text
);
1945 ficlStackPushUnsigned(vm
->dataStack
, counted
->length
);
1949 * e n v i r o n m e n t ?
1950 * environment-query CORE ( c-addr u -- FICL_FALSE | i*x FICL_TRUE )
1951 * c-addr is the address of a character string and u is the string's
1952 * character count. u may have a value in the range from zero to an
1953 * implementation-defined maximum which shall not be less than 31. The
1954 * character string should contain a keyword from 3.2.6 Environmental
1955 * queries or the optional word sets to be checked for correspondence
1956 * with an attribute of the present environment. If the system treats the
1957 * attribute as unknown, the returned flag is FICL_FALSE; otherwise, the flag
1958 * is FICL_TRUE and the i*x returned is of the type specified in the table for
1959 * the attribute queried.
1962 ficlPrimitiveEnvironmentQ(ficlVm
*vm
)
1964 ficlDictionary
*environment
;
1968 FICL_STACK_CHECK(vm
->dataStack
, 2, 1);
1970 environment
= vm
->callback
.system
->environment
;
1971 name
.length
= ficlStackPopUnsigned(vm
->dataStack
);
1972 name
.text
= ficlStackPopPointer(vm
->dataStack
);
1974 word
= ficlDictionaryLookup(environment
, name
);
1977 ficlVmExecuteWord(vm
, word
);
1978 ficlStackPushInteger(vm
->dataStack
, FICL_TRUE
);
1980 ficlStackPushInteger(vm
->dataStack
, FICL_FALSE
);
1986 * EVALUATE CORE ( i*x c-addr u -- j*x )
1987 * Save the current input source specification. Store minus-one (-1) in
1988 * SOURCE-ID if it is present. Make the string described by c-addr and u
1989 * both the input source and input buffer, set >IN to zero, and
1990 * FICL_VM_STATE_INTERPRET.
1991 * When the parse area is empty, restore the prior input source
1992 * specification. Other stack effects are due to the words EVALUATEd.
1995 ficlPrimitiveEvaluate(ficlVm
*vm
)
2001 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
2003 FICL_STRING_SET_LENGTH(string
, ficlStackPopUnsigned(vm
->dataStack
));
2004 FICL_STRING_SET_POINTER(string
, ficlStackPopPointer(vm
->dataStack
));
2007 vm
->sourceId
.i
= -1;
2008 result
= ficlVmExecuteString(vm
, string
);
2010 if (result
!= FICL_VM_STATUS_OUT_OF_TEXT
)
2011 ficlVmThrow(vm
, result
);
2015 * s t r i n g q u o t e
2016 * Interpreting: get string delimited by a quote from the input stream,
2017 * copy to a scratch area, and put its count and address on the stack.
2018 * Compiling: FICL_VM_STATE_COMPILE code to push the address and count
2019 * of a string literal, FICL_VM_STATE_COMPILE the string from the input
2020 * stream, and align the dictionary pointer.
2023 ficlPrimitiveStringQuoteIm(ficlVm
*vm
)
2025 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2027 if (vm
->state
== FICL_VM_STATE_INTERPRET
) {
2028 ficlCountedString
*counted
;
2029 counted
= (ficlCountedString
*)dictionary
->here
;
2030 ficlVmGetString(vm
, counted
, '\"');
2031 ficlStackPushPointer(vm
->dataStack
, counted
->text
);
2032 ficlStackPushUnsigned(vm
->dataStack
, counted
->length
);
2033 } else { /* FICL_VM_STATE_COMPILE state */
2034 ficlDictionaryAppendUnsigned(dictionary
,
2035 ficlInstructionStringLiteralParen
);
2036 dictionary
->here
= FICL_POINTER_TO_CELL(
2037 ficlVmGetString(vm
, (ficlCountedString
*)dictionary
->here
,
2039 ficlDictionaryAlign(dictionary
);
2045 * Pop count and char address from stack and print the designated string.
2048 ficlPrimitiveType(ficlVm
*vm
)
2050 ficlUnsigned length
;
2053 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
2055 length
= ficlStackPopUnsigned(vm
->dataStack
);
2056 s
= ficlStackPopPointer(vm
->dataStack
);
2058 if ((s
== NULL
) || (length
== 0))
2062 * Since we don't have an output primitive for a counted string
2063 * (oops), make sure the string is null terminated. If not, copy
2066 if (s
[length
] != 0) {
2067 char *here
= (char *)ficlVmGetDictionary(vm
)->here
;
2069 strncpy(here
, s
, length
);
2071 here
[length
] = '\0';
2075 ficlVmTextOut(vm
, s
);
2080 * word CORE ( char "<chars>ccc<char>" -- c-addr )
2081 * Skip leading delimiters. Parse characters ccc delimited by char. An
2082 * ambiguous condition exists if the length of the parsed string is greater
2083 * than the implementation-defined length of a counted string.
2085 * c-addr is the address of a transient region containing the parsed word
2086 * as a counted string. If the parse area was empty or contained no
2087 * characters other than the delimiter, the resulting string has a zero
2088 * length. A space, not included in the length, follows the string. A
2089 * program may replace characters within the string.
2090 * NOTE! Ficl also NULL-terminates the dest string.
2093 ficlPrimitiveWord(ficlVm
*vm
)
2095 ficlCountedString
*counted
;
2099 FICL_STACK_CHECK(vm
->dataStack
, 1, 1);
2101 counted
= (ficlCountedString
*)vm
->pad
;
2102 delim
= (char)ficlStackPopInteger(vm
->dataStack
);
2103 name
= ficlVmParseStringEx(vm
, delim
, 1);
2105 if (FICL_STRING_GET_LENGTH(name
) > FICL_PAD_SIZE
- 1)
2106 FICL_STRING_SET_LENGTH(name
, FICL_PAD_SIZE
- 1);
2108 counted
->length
= (ficlUnsigned8
)FICL_STRING_GET_LENGTH(name
);
2109 strncpy(counted
->text
, FICL_STRING_GET_POINTER(name
),
2110 FICL_STRING_GET_LENGTH(name
));
2113 * store an extra space at the end of the primitive...
2114 * why? dunno yet. Guy Carver did it.
2116 counted
->text
[counted
->length
] = ' ';
2117 counted
->text
[counted
->length
+ 1] = 0;
2119 ficlStackPushPointer(vm
->dataStack
, counted
);
2123 * p a r s e - w o r d
2124 * Ficl PARSE-WORD ( <spaces>name -- c-addr u )
2125 * Skip leading spaces and parse name delimited by a space. c-addr is the
2126 * address within the input buffer and u is the length of the selected
2127 * string. If the parse area is empty, the resulting string has a zero length.
2129 static void ficlPrimitiveParseNoCopy(ficlVm
*vm
)
2133 FICL_STACK_CHECK(vm
->dataStack
, 0, 2);
2135 s
= ficlVmGetWord0(vm
);
2136 ficlStackPushPointer(vm
->dataStack
, FICL_STRING_GET_POINTER(s
));
2137 ficlStackPushUnsigned(vm
->dataStack
, FICL_STRING_GET_LENGTH(s
));
2142 * CORE EXT ( char "ccc<char>" -- c-addr u )
2143 * Parse ccc delimited by the delimiter char.
2144 * c-addr is the address (within the input buffer) and u is the length of
2145 * the parsed string. If the parse area was empty, the resulting string has
2147 * NOTE! PARSE differs from WORD: it does not skip leading delimiters.
2150 ficlPrimitiveParse(ficlVm
*vm
)
2155 FICL_STACK_CHECK(vm
->dataStack
, 1, 2);
2157 delim
= (char)ficlStackPopInteger(vm
->dataStack
);
2159 s
= ficlVmParseStringEx(vm
, delim
, 0);
2160 ficlStackPushPointer(vm
->dataStack
, FICL_STRING_GET_POINTER(s
));
2161 ficlStackPushUnsigned(vm
->dataStack
, FICL_STRING_GET_LENGTH(s
));
2166 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
2167 * Find the definition named in the counted string at c-addr. If the
2168 * definition is not found, return c-addr and zero. If the definition is
2169 * found, return its execution token xt. If the definition is immediate,
2170 * also return one (1), otherwise also return minus-one (-1). For a given
2171 * string, the values returned by FIND while compiling may differ from
2172 * those returned while not compiling.
2175 do_find(ficlVm
*vm
, ficlString name
, void *returnForFailure
)
2179 word
= ficlDictionaryLookup(ficlVmGetDictionary(vm
), name
);
2181 ficlStackPushPointer(vm
->dataStack
, word
);
2182 ficlStackPushInteger(vm
->dataStack
,
2183 (ficlWordIsImmediate(word
) ? 1 : -1));
2185 ficlStackPushPointer(vm
->dataStack
, returnForFailure
);
2186 ficlStackPushUnsigned(vm
->dataStack
, 0);
2192 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
2193 * Find the definition named in the counted string at c-addr. If the
2194 * definition is not found, return c-addr and zero. If the definition is
2195 * found, return its execution token xt. If the definition is immediate,
2196 * also return one (1), otherwise also return minus-one (-1). For a given
2197 * string, the values returned by FIND while compiling may differ from
2198 * those returned while not compiling.
2201 ficlPrimitiveCFind(ficlVm
*vm
)
2203 ficlCountedString
*counted
;
2206 FICL_STACK_CHECK(vm
->dataStack
, 1, 2);
2208 counted
= ficlStackPopPointer(vm
->dataStack
);
2209 FICL_STRING_SET_FROM_COUNTED_STRING(name
, *counted
);
2210 do_find(vm
, name
, counted
);
2215 * Ficl ( c-addr u -- 0 0 | xt 1 | xt -1 )
2216 * Like FIND, but takes "c-addr u" for the string.
2219 ficlPrimitiveSFind(ficlVm
*vm
)
2223 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
2225 name
.length
= ficlStackPopInteger(vm
->dataStack
);
2226 name
.text
= ficlStackPopPointer(vm
->dataStack
);
2228 do_find(vm
, name
, NULL
);
2235 ficlPrimitiveRecurseCoIm(ficlVm
*vm
)
2237 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2241 c
.p
= dictionary
->smudge
;
2242 ficlDictionaryAppendCell(dictionary
, c
);
2247 * CORE ( -- c-addr u )
2248 * c-addr is the address of, and u is the number of characters in, the
2252 ficlPrimitiveSource(ficlVm
*vm
)
2254 FICL_STACK_CHECK(vm
->dataStack
, 0, 2);
2256 ficlStackPushPointer(vm
->dataStack
, vm
->tib
.text
);
2257 ficlStackPushInteger(vm
->dataStack
, ficlVmGetInBufLen(vm
));
2265 ficlPrimitiveVersion(ficlVm
*vm
)
2267 ficlVmTextOut(vm
, "Ficl version " FICL_VERSION
"\n");
2275 ficlPrimitiveToIn(ficlVm
*vm
)
2277 FICL_STACK_CHECK(vm
->dataStack
, 0, 1);
2279 ficlStackPushPointer(vm
->dataStack
, &vm
->tib
.index
);
2283 * c o l o n N o N a m e
2284 * CORE EXT ( C: -- colon-sys ) ( S: -- xt )
2285 * Create an unnamed colon definition and push its address.
2286 * Change state to FICL_VM_STATE_COMPILE.
2289 ficlPrimitiveColonNoName(ficlVm
*vm
)
2291 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2295 FICL_STRING_SET_LENGTH(name
, 0);
2296 FICL_STRING_SET_POINTER(name
, NULL
);
2298 vm
->state
= FICL_VM_STATE_COMPILE
;
2299 word
= ficlDictionaryAppendWord(dictionary
, name
,
2300 (ficlPrimitive
)ficlInstructionColonParen
,
2301 FICL_WORD_DEFAULT
| FICL_WORD_SMUDGED
);
2303 ficlStackPushPointer(vm
->dataStack
, word
);
2304 markControlTag(vm
, colonTag
);
2308 * u s e r V a r i a b l e
2309 * user ( u -- ) "<spaces>name"
2310 * Get a name from the input stream and create a user variable
2311 * with the name and the index supplied. The run-time effect
2312 * of a user variable is to push the address of the indexed ficlCell
2313 * in the running vm's user array.
2315 * User variables are vm local cells. Each vm has an array of
2316 * FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
2317 * Ficl's user facility is implemented with two primitives,
2318 * "user" and "(user)", a variable ("nUser") (in softcore.c) that
2319 * holds the index of the next free user ficlCell, and a redefinition
2320 * (also in softcore) of "user" that defines a user word and increments
2325 ficlPrimitiveUser(ficlVm
*vm
)
2327 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2328 ficlString name
= ficlVmGetWord(vm
);
2331 c
= ficlStackPop(vm
->dataStack
);
2332 if (c
.i
>= FICL_USER_CELLS
) {
2333 ficlVmThrowError(vm
, "Error - out of user space");
2336 ficlDictionaryAppendWord(dictionary
, name
,
2337 (ficlPrimitive
)ficlInstructionUserParen
, FICL_WORD_DEFAULT
);
2338 ficlDictionaryAppendCell(dictionary
, c
);
2342 #if FICL_WANT_LOCALS
2344 * Each local is recorded in a private locals dictionary as a
2345 * word that does doLocalIm at runtime. DoLocalIm compiles code
2346 * into the client definition to fetch the value of the
2347 * corresponding local variable from the return stack.
2348 * The private dictionary gets initialized at the end of each block
2349 * that uses locals (in ; and does> for example).
2352 ficlLocalParenIm(ficlVm
*vm
, int isDouble
, int isFloat
)
2354 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2355 ficlInteger nLocal
= vm
->runningWord
->param
[0].i
;
2357 #if !FICL_WANT_FLOAT
2358 FICL_VM_ASSERT(vm
, !isFloat
);
2359 /* get rid of unused parameter warning */
2361 #endif /* FICL_WANT_FLOAT */
2363 if (vm
->state
== FICL_VM_STATE_INTERPRET
) {
2367 stack
= vm
->floatStack
;
2369 #endif /* FICL_WANT_FLOAT */
2370 stack
= vm
->dataStack
;
2372 ficlStackPush(stack
, vm
->returnStack
->frame
[nLocal
]);
2374 ficlStackPush(stack
, vm
->returnStack
->frame
[nLocal
+1]);
2376 ficlInstruction instruction
;
2377 ficlInteger appendLocalOffset
;
2381 (isDouble
) ? ficlInstructionGetF2LocalParen
:
2382 ficlInstructionGetFLocalParen
;
2383 appendLocalOffset
= FICL_TRUE
;
2385 #endif /* FICL_WANT_FLOAT */
2387 instruction
= (isDouble
) ? ficlInstructionGet2Local0
:
2388 ficlInstructionGetLocal0
;
2389 appendLocalOffset
= FICL_FALSE
;
2390 } else if ((nLocal
== 1) && !isDouble
) {
2391 instruction
= ficlInstructionGetLocal1
;
2392 appendLocalOffset
= FICL_FALSE
;
2395 (isDouble
) ? ficlInstructionGet2LocalParen
:
2396 ficlInstructionGetLocalParen
;
2397 appendLocalOffset
= FICL_TRUE
;
2400 ficlDictionaryAppendUnsigned(dictionary
, instruction
);
2401 if (appendLocalOffset
)
2402 ficlDictionaryAppendUnsigned(dictionary
, nLocal
);
2407 ficlPrimitiveDoLocalIm(ficlVm
*vm
)
2409 ficlLocalParenIm(vm
, 0, 0);
2413 ficlPrimitiveDo2LocalIm(ficlVm
*vm
)
2415 ficlLocalParenIm(vm
, 1, 0);
2420 ficlPrimitiveDoFLocalIm(ficlVm
*vm
)
2422 ficlLocalParenIm(vm
, 0, 1);
2426 ficlPrimitiveDoF2LocalIm(ficlVm
*vm
)
2428 ficlLocalParenIm(vm
, 1, 1);
2430 #endif /* FICL_WANT_FLOAT */
2433 * l o c a l P a r e n
2434 * paren-local-paren LOCAL
2435 * Interpretation: Interpretation semantics for this word are undefined.
2436 * Execution: ( c-addr u -- )
2437 * When executed during compilation, (LOCAL) passes a message to the
2438 * system that has one of two meanings. If u is non-zero,
2439 * the message identifies a new local whose definition name is given by
2440 * the string of characters identified by c-addr u. If u is zero,
2441 * the message is last local and c-addr has no significance.
2443 * The result of executing (LOCAL) during compilation of a definition is
2444 * to create a set of named local identifiers, each of which is
2445 * a definition name, that only have execution semantics within the scope
2446 * of that definition's source.
2448 * local Execution: ( -- x )
2450 * Push the local's value, x, onto the stack. The local's value is
2451 * initialized as described in 13.3.3 Processing locals and may be
2452 * changed by preceding the local's name with TO. An ambiguous condition
2453 * exists when local is executed while in interpretation state.
2456 ficlLocalParen(ficlVm
*vm
, int isDouble
, int isFloat
)
2458 ficlDictionary
*dictionary
;
2461 FICL_STACK_CHECK(vm
->dataStack
, 2, 0);
2463 dictionary
= ficlVmGetDictionary(vm
);
2464 FICL_STRING_SET_LENGTH(name
, ficlStackPopUnsigned(vm
->dataStack
));
2465 FICL_STRING_SET_POINTER(name
,
2466 (char *)ficlStackPopPointer(vm
->dataStack
));
2468 if (FICL_STRING_GET_LENGTH(name
) > 0) {
2470 * add a local to the **locals** dictionary and
2471 * update localsCount
2474 ficlInstruction instruction
;
2475 ficlDictionary
*locals
;
2477 locals
= ficlSystemGetLocals(vm
->callback
.system
);
2478 if (vm
->callback
.system
->localsCount
>= FICL_MAX_LOCALS
) {
2479 ficlVmThrowError(vm
, "Error: out of local space");
2482 #if !FICL_WANT_FLOAT
2483 FICL_VM_ASSERT(vm
, !isFloat
);
2484 /* get rid of unused parameter warning */
2486 #else /* FICL_WANT_FLOAT */
2489 code
= ficlPrimitiveDoF2LocalIm
;
2490 instruction
= ficlInstructionToF2LocalParen
;
2492 code
= ficlPrimitiveDoFLocalIm
;
2493 instruction
= ficlInstructionToFLocalParen
;
2496 #endif /* FICL_WANT_FLOAT */
2498 code
= ficlPrimitiveDo2LocalIm
;
2499 instruction
= ficlInstructionTo2LocalParen
;
2501 code
= ficlPrimitiveDoLocalIm
;
2502 instruction
= ficlInstructionToLocalParen
;
2505 ficlDictionaryAppendWord(locals
, name
, code
,
2506 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
2507 ficlDictionaryAppendUnsigned(locals
,
2508 vm
->callback
.system
->localsCount
);
2510 if (vm
->callback
.system
->localsCount
== 0) {
2512 * FICL_VM_STATE_COMPILE code to create a local
2515 ficlDictionaryAppendUnsigned(dictionary
,
2516 ficlInstructionLinkParen
);
2518 /* save location in dictionary for #locals */
2519 vm
->callback
.system
->localsFixup
= dictionary
->here
;
2520 ficlDictionaryAppendUnsigned(dictionary
,
2521 vm
->callback
.system
->localsCount
);
2524 ficlDictionaryAppendUnsigned(dictionary
, instruction
);
2525 ficlDictionaryAppendUnsigned(dictionary
,
2526 vm
->callback
.system
->localsCount
);
2528 vm
->callback
.system
->localsCount
+= (isDouble
) ? 2 : 1;
2529 } else if (vm
->callback
.system
->localsCount
> 0) {
2530 /* write localsCount to (link) param area in dictionary */
2531 *(ficlInteger
*)(vm
->callback
.system
->localsFixup
) =
2532 vm
->callback
.system
->localsCount
;
2537 ficlPrimitiveLocalParen(ficlVm
*vm
)
2539 ficlLocalParen(vm
, 0, 0);
2543 ficlPrimitive2LocalParen(ficlVm
*vm
)
2545 ficlLocalParen(vm
, 1, 0);
2547 #endif /* FICL_WANT_LOCALS */
2552 * Interpretation: ( x "<spaces>name" -- )
2553 * Skip leading spaces and parse name delimited by a space. Store x in
2554 * name. An ambiguous condition exists if name was not defined by VALUE.
2555 * NOTE: In Ficl, VALUE is an alias of CONSTANT
2558 ficlPrimitiveToValue(ficlVm
*vm
)
2560 ficlString name
= ficlVmGetWord(vm
);
2561 ficlDictionary
*dictionary
= ficlVmGetDictionary(vm
);
2563 ficlInstruction instruction
= 0;
2565 ficlInteger isDouble
;
2566 #if FICL_WANT_LOCALS
2568 ficlInteger appendLocalOffset
;
2569 ficlInteger isFloat
;
2570 #endif /* FICL_WANT_LOCALS */
2572 #if FICL_WANT_LOCALS
2573 if ((vm
->callback
.system
->localsCount
> 0) &&
2574 (vm
->state
== FICL_VM_STATE_COMPILE
)) {
2575 ficlDictionary
*locals
;
2577 locals
= ficlSystemGetLocals(vm
->callback
.system
);
2578 word
= ficlDictionaryLookup(locals
, name
);
2582 if (word
->code
== ficlPrimitiveDoLocalIm
) {
2583 instruction
= ficlInstructionToLocalParen
;
2584 isDouble
= isFloat
= FICL_FALSE
;
2585 } else if (word
->code
== ficlPrimitiveDo2LocalIm
) {
2586 instruction
= ficlInstructionTo2LocalParen
;
2587 isDouble
= FICL_TRUE
;
2588 isFloat
= FICL_FALSE
;
2591 else if (word
->code
== ficlPrimitiveDoFLocalIm
) {
2592 instruction
= ficlInstructionToFLocalParen
;
2593 isDouble
= FICL_FALSE
;
2594 isFloat
= FICL_TRUE
;
2595 } else if (word
->code
== ficlPrimitiveDoF2LocalIm
) {
2596 instruction
= ficlInstructionToF2LocalParen
;
2597 isDouble
= isFloat
= FICL_TRUE
;
2599 #endif /* FICL_WANT_FLOAT */
2601 ficlVmThrowError(vm
,
2602 "to %.*s : local is of unknown type",
2603 FICL_STRING_GET_LENGTH(name
),
2604 FICL_STRING_GET_POINTER(name
));
2608 nLocal
= word
->param
[0].i
;
2609 appendLocalOffset
= FICL_TRUE
;
2613 #endif /* FICL_WANT_FLOAT */
2616 (isDouble
) ? ficlInstructionTo2Local0
:
2617 ficlInstructionToLocal0
;
2618 appendLocalOffset
= FICL_FALSE
;
2619 } else if ((nLocal
== 1) && !isDouble
) {
2620 instruction
= ficlInstructionToLocal1
;
2621 appendLocalOffset
= FICL_FALSE
;
2625 #endif /* FICL_WANT_FLOAT */
2627 ficlDictionaryAppendUnsigned(dictionary
, instruction
);
2628 if (appendLocalOffset
)
2629 ficlDictionaryAppendUnsigned(dictionary
, nLocal
);
2634 #if FICL_WANT_LOCALS
2636 #endif /* FICL_WANT_LOCALS */
2637 word
= ficlDictionaryLookup(dictionary
, name
);
2639 ficlVmThrowError(vm
, "%.*s not found",
2640 FICL_STRING_GET_LENGTH(name
),
2641 FICL_STRING_GET_POINTER(name
));
2643 switch ((ficlInstruction
)word
->code
) {
2644 case ficlInstructionConstantParen
:
2645 instruction
= ficlInstructionStore
;
2646 stack
= vm
->dataStack
;
2647 isDouble
= FICL_FALSE
;
2649 case ficlInstruction2ConstantParen
:
2650 instruction
= ficlInstruction2Store
;
2651 stack
= vm
->dataStack
;
2652 isDouble
= FICL_TRUE
;
2655 case ficlInstructionFConstantParen
:
2656 instruction
= ficlInstructionFStore
;
2657 stack
= vm
->floatStack
;
2658 isDouble
= FICL_FALSE
;
2660 case ficlInstructionF2ConstantParen
:
2661 instruction
= ficlInstructionF2Store
;
2662 stack
= vm
->floatStack
;
2663 isDouble
= FICL_TRUE
;
2665 #endif /* FICL_WANT_FLOAT */
2667 ficlVmThrowError(vm
,
2668 "to %.*s : value/constant is of unknown type",
2669 FICL_STRING_GET_LENGTH(name
),
2670 FICL_STRING_GET_POINTER(name
));
2674 if (vm
->state
== FICL_VM_STATE_INTERPRET
) {
2675 word
->param
[0] = ficlStackPop(stack
);
2677 word
->param
[1] = ficlStackPop(stack
);
2679 /* FICL_VM_STATE_COMPILE code to store to word's param */
2680 ficlStackPushPointer(vm
->dataStack
, &word
->param
[0]);
2681 ficlPrimitiveLiteralIm(vm
);
2682 ficlDictionaryAppendUnsigned(dictionary
, instruction
);
2687 * f m S l a s h M o d
2688 * f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
2689 * Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
2690 * Input and output stack arguments are signed. An ambiguous condition
2691 * exists if n1 is zero or if the quotient lies outside the range of a
2692 * single-ficlCell signed integer.
2695 ficlPrimitiveFMSlashMod(ficlVm
*vm
)
2701 FICL_STACK_CHECK(vm
->dataStack
, 3, 2);
2703 n1
= ficlStackPopInteger(vm
->dataStack
);
2704 d1
= ficlStackPop2Integer(vm
->dataStack
);
2705 qr
= ficl2IntegerDivideFloored(d1
, n1
);
2706 ficlStackPushInteger(vm
->dataStack
, qr
.remainder
);
2707 ficlStackPushInteger(vm
->dataStack
,
2708 FICL_2UNSIGNED_GET_LOW(qr
.quotient
));
2712 * s m S l a s h R e m
2713 * s-m-slash-remainder CORE ( d1 n1 -- n2 n3 )
2714 * Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
2715 * Input and output stack arguments are signed. An ambiguous condition
2716 * exists if n1 is zero or if the quotient lies outside the range of a
2717 * single-ficlCell signed integer.
2720 ficlPrimitiveSMSlashRem(ficlVm
*vm
)
2726 FICL_STACK_CHECK(vm
->dataStack
, 3, 2);
2728 n1
= ficlStackPopInteger(vm
->dataStack
);
2729 d1
= ficlStackPop2Integer(vm
->dataStack
);
2730 qr
= ficl2IntegerDivideSymmetric(d1
, n1
);
2731 ficlStackPushInteger(vm
->dataStack
, qr
.remainder
);
2732 ficlStackPushInteger(vm
->dataStack
,
2733 FICL_2UNSIGNED_GET_LOW(qr
.quotient
));
2737 ficlPrimitiveMod(ficlVm
*vm
)
2743 FICL_STACK_CHECK(vm
->dataStack
, 2, 1);
2745 n1
= ficlStackPopInteger(vm
->dataStack
);
2746 i
= ficlStackPopInteger(vm
->dataStack
);
2747 FICL_INTEGER_TO_2INTEGER(i
, d1
);
2748 qr
= ficl2IntegerDivideSymmetric(d1
, n1
);
2749 ficlStackPushInteger(vm
->dataStack
, qr
.remainder
);
2753 * u m S l a s h M o d
2754 * u-m-slash-mod CORE ( ud u1 -- u2 u3 )
2755 * Divide ud by u1, giving the quotient u3 and the remainder u2.
2756 * All values and arithmetic are unsigned. An ambiguous condition
2757 * exists if u1 is zero or if the quotient lies outside the range of a
2758 * single-ficlCell unsigned integer.
2761 ficlPrimitiveUMSlashMod(ficlVm
*vm
)
2765 ficl2UnsignedQR uqr
;
2767 u1
= ficlStackPopUnsigned(vm
->dataStack
);
2768 ud
= ficlStackPop2Unsigned(vm
->dataStack
);
2769 uqr
= ficl2UnsignedDivide(ud
, u1
);
2770 ficlStackPushUnsigned(vm
->dataStack
, uqr
.remainder
);
2771 ficlStackPushUnsigned(vm
->dataStack
,
2772 FICL_2UNSIGNED_GET_LOW(uqr
.quotient
));
2777 * m-star CORE ( n1 n2 -- d )
2778 * d is the signed product of n1 times n2.
2781 ficlPrimitiveMStar(ficlVm
*vm
)
2786 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
2788 n2
= ficlStackPopInteger(vm
->dataStack
);
2789 n1
= ficlStackPopInteger(vm
->dataStack
);
2791 d
= ficl2IntegerMultiply(n1
, n2
);
2792 ficlStackPush2Integer(vm
->dataStack
, d
);
2796 ficlPrimitiveUMStar(ficlVm
*vm
)
2801 FICL_STACK_CHECK(vm
->dataStack
, 2, 2);
2803 u2
= ficlStackPopUnsigned(vm
->dataStack
);
2804 u1
= ficlStackPopUnsigned(vm
->dataStack
);
2806 ud
= ficl2UnsignedMultiply(u1
, u2
);
2807 ficlStackPush2Unsigned(vm
->dataStack
, ud
);
2812 * DOUBLE ( d1 d2 d3 -- d2 d3 d1 )
2815 ficlPrimitive2Rot(ficlVm
*vm
)
2817 ficl2Integer d1
, d2
, d3
;
2818 FICL_STACK_CHECK(vm
->dataStack
, 6, 6);
2820 d3
= ficlStackPop2Integer(vm
->dataStack
);
2821 d2
= ficlStackPop2Integer(vm
->dataStack
);
2822 d1
= ficlStackPop2Integer(vm
->dataStack
);
2823 ficlStackPush2Integer(vm
->dataStack
, d2
);
2824 ficlStackPush2Integer(vm
->dataStack
, d3
);
2825 ficlStackPush2Integer(vm
->dataStack
, d1
);
2830 * CORE EXT ( -- c-addr )
2831 * c-addr is the address of a transient region that can be used to hold
2832 * data for intermediate processing.
2835 ficlPrimitivePad(ficlVm
*vm
)
2837 ficlStackPushPointer(vm
->dataStack
, vm
->pad
);
2842 * CORE EXT, FILE ( -- 0 | -1 | fileid )
2843 * Identifies the input source as follows:
2845 * SOURCE-ID Input source
2846 * --------- ------------
2847 * fileid Text file fileid
2848 * -1 String (via EVALUATE)
2849 * 0 User input device
2852 ficlPrimitiveSourceID(ficlVm
*vm
)
2854 ficlStackPushInteger(vm
->dataStack
, vm
->sourceId
.i
);
2859 * CORE EXT ( -- flag )
2860 * Attempt to fill the input buffer from the input source, returning
2861 * a FICL_TRUE flag if successful.
2862 * When the input source is the user input device, attempt to receive input
2863 * into the terminal input buffer. If successful, make the result the input
2864 * buffer, set >IN to zero, and return FICL_TRUE. Receipt of a line containing
2865 * no characters is considered successful. If there is no input available from
2866 * the current input source, return FICL_FALSE.
2867 * When the input source is a string from EVALUATE, return FICL_FALSE and
2868 * perform no other action.
2871 ficlPrimitiveRefill(ficlVm
*vm
)
2873 ficlInteger ret
= (vm
->sourceId
.i
== -1) ? FICL_FALSE
: FICL_TRUE
;
2874 if (ret
&& (vm
->restart
== 0))
2875 ficlVmThrow(vm
, FICL_VM_STATUS_RESTART
);
2877 ficlStackPushInteger(vm
->dataStack
, ret
);
2881 * freebsd exception handling words
2882 * Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
2883 * the word in ToS. If an exception happens, restore the state to what
2884 * it was before, and pushes the exception value on the stack. If not,
2887 * Notice that Catch implements an inner interpreter. This is ugly,
2888 * but given how Ficl works, it cannot be helped. The problem is that
2889 * colon definitions will be executed *after* the function returns,
2890 * while "code" definitions will be executed immediately. I considered
2891 * other solutions to this problem, but all of them shared the same
2892 * basic problem (with added disadvantages): if Ficl ever changes it's
2893 * inner thread modus operandi, one would have to fix this word.
2895 * More comments can be found throughout catch's code.
2897 * Daniel C. Sobral Jan 09/1999
2898 * sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
2901 ficlPrimitiveCatch(ficlVm
*vm
)
2906 ficlStack dataStackCopy
;
2907 ficlStack returnStackCopy
;
2910 FICL_VM_ASSERT(vm
, vm
);
2911 FICL_VM_ASSERT(vm
, vm
->callback
.system
->exitInnerWord
);
2915 * We need this *before* we save the stack pointer, or
2916 * we'll have to pop one element out of the stack after
2917 * an exception. I prefer to get done with it up front. :-)
2920 FICL_STACK_CHECK(vm
->dataStack
, 1, 0);
2922 word
= ficlStackPopPointer(vm
->dataStack
);
2925 * Save vm's state -- a catch will not back out environmental
2928 * We are *not* saving dictionary state, since it is
2929 * global instead of per vm, and we are not saving
2930 * stack contents, since we are not required to (and,
2931 * thus, it would be useless). We save vm, and vm
2932 * "stacks" (a structure containing general information
2933 * about it, including the current stack pointer).
2935 memcpy((void*)&vmCopy
, (void*)vm
, sizeof (ficlVm
));
2936 memcpy((void*)&dataStackCopy
, (void*)vm
->dataStack
, sizeof (ficlStack
));
2937 memcpy((void*)&returnStackCopy
, (void*)vm
->returnStack
,
2938 sizeof (ficlStack
));
2943 vm
->exceptionHandler
= &vmState
;
2948 except
= setjmp(vmState
);
2952 * Setup condition - push poison pill so that the VM throws
2953 * VM_INNEREXIT if the XT terminates normally, then execute
2957 /* Open mouth, insert emetic */
2958 ficlVmPushIP(vm
, &(vm
->callback
.system
->exitInnerWord
));
2959 ficlVmExecuteWord(vm
, word
);
2960 ficlVmInnerLoop(vm
, 0);
2964 * Normal exit from XT - lose the poison pill,
2965 * restore old setjmp vector and push a zero.
2967 case FICL_VM_STATUS_INNER_EXIT
:
2968 ficlVmPopIP(vm
); /* Gack - hurl poison pill */
2969 /* Restore just the setjmp vector */
2970 vm
->exceptionHandler
= vmCopy
.exceptionHandler
;
2971 /* Push 0 -- everything is ok */
2972 ficlStackPushInteger(vm
->dataStack
, 0);
2976 * Some other exception got thrown - restore pre-existing VM state
2977 * and push the exception code
2980 /* Restore vm's state */
2981 memcpy((void*)vm
, (void*)&vmCopy
, sizeof (ficlVm
));
2982 memcpy((void*)vm
->dataStack
, (void*)&dataStackCopy
,
2983 sizeof (ficlStack
));
2984 memcpy((void*)vm
->returnStack
, (void*)&returnStackCopy
,
2985 sizeof (ficlStack
));
2987 ficlStackPushInteger(vm
->dataStack
, except
); /* Push error */
2995 * Throw -- From ANS Forth standard.
2997 * Throw takes the ToS and, if that's different from zero,
2998 * returns to the last executed catch context. Further throws will
2999 * unstack previously executed "catches", in LIFO mode.
3001 * Daniel C. Sobral Jan 09/1999
3004 ficlPrimitiveThrow(ficlVm
*vm
)
3008 except
= ficlStackPopInteger(vm
->dataStack
);
3011 ficlVmThrow(vm
, except
);
3019 ficlPrimitiveAllocate(ficlVm
*vm
)
3024 size
= ficlStackPopInteger(vm
->dataStack
);
3025 p
= ficlMalloc(size
);
3026 ficlStackPushPointer(vm
->dataStack
, p
);
3028 ficlStackPushInteger(vm
->dataStack
, 0);
3030 ficlStackPushInteger(vm
->dataStack
, 1);
3038 ficlPrimitiveFree(ficlVm
*vm
)
3042 p
= ficlStackPopPointer(vm
->dataStack
);
3044 ficlStackPushInteger(vm
->dataStack
, 0);
3052 ficlPrimitiveResize(ficlVm
*vm
)
3057 size
= ficlStackPopInteger(vm
->dataStack
);
3058 old
= ficlStackPopPointer(vm
->dataStack
);
3059 new = ficlRealloc(old
, size
);
3062 ficlStackPushPointer(vm
->dataStack
, new);
3063 ficlStackPushInteger(vm
->dataStack
, 0);
3065 ficlStackPushPointer(vm
->dataStack
, old
);
3066 ficlStackPushInteger(vm
->dataStack
, 1);
3071 * e x i t - i n n e r
3072 * Signals execXT that an inner loop has completed
3075 ficlPrimitiveExitInner(ficlVm
*vm
)
3077 ficlVmThrow(vm
, FICL_VM_STATUS_INNER_EXIT
);
3082 ficlPrimitiveName(ficlVm
*vm
)
3089 * f i c l C o m p i l e C o r e
3090 * Builds the primitive wordset and the environment-query namespace.
3093 ficlSystemCompileCore(ficlSystem
*system
)
3095 ficlWord
*interpret
;
3096 ficlDictionary
*dictionary
= ficlSystemGetDictionary(system
);
3097 ficlDictionary
*environment
= ficlSystemGetEnvironment(system
);
3099 FICL_SYSTEM_ASSERT(system
, dictionary
);
3100 FICL_SYSTEM_ASSERT(system
, environment
);
3102 #define FICL_TOKEN(token, description)
3103 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \
3104 ficlDictionarySetInstruction(dictionary, description, token, flags);
3105 #include "ficltokens.h"
3107 #undef FICL_INSTRUCTION_TOKEN
3111 * see softcore.c for definitions of: abs bl space spaces abort"
3113 ficlDictionarySetPrimitive(dictionary
, "#", ficlPrimitiveNumberSign
,
3115 ficlDictionarySetPrimitive(dictionary
, "#>",
3116 ficlPrimitiveNumberSignGreater
, FICL_WORD_DEFAULT
);
3117 ficlDictionarySetPrimitive(dictionary
, "#s", ficlPrimitiveNumberSignS
,
3119 ficlDictionarySetPrimitive(dictionary
, "\'", ficlPrimitiveTick
,
3121 ficlDictionarySetPrimitive(dictionary
, "(", ficlPrimitiveParenthesis
,
3122 FICL_WORD_IMMEDIATE
);
3123 ficlDictionarySetPrimitive(dictionary
, "+loop",
3124 ficlPrimitivePlusLoopCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3125 ficlDictionarySetPrimitive(dictionary
, ".", ficlPrimitiveDot
,
3127 ficlDictionarySetPrimitive(dictionary
, ".\"",
3128 ficlPrimitiveDotQuoteCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3129 ficlDictionarySetPrimitive(dictionary
, ":", ficlPrimitiveColon
,
3131 ficlDictionarySetPrimitive(dictionary
, ";", ficlPrimitiveSemicolonCoIm
,
3132 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3133 ficlDictionarySetPrimitive(dictionary
, "<#",
3134 ficlPrimitiveLessNumberSign
, FICL_WORD_DEFAULT
);
3135 ficlDictionarySetPrimitive(dictionary
, ">body", ficlPrimitiveToBody
,
3137 ficlDictionarySetPrimitive(dictionary
, ">in", ficlPrimitiveToIn
,
3139 ficlDictionarySetPrimitive(dictionary
, ">number", ficlPrimitiveToNumber
,
3141 ficlDictionarySetPrimitive(dictionary
, "abort", ficlPrimitiveAbort
,
3143 ficlDictionarySetPrimitive(dictionary
, "accept", ficlPrimitiveAccept
,
3145 ficlDictionarySetPrimitive(dictionary
, "align", ficlPrimitiveAlign
,
3147 ficlDictionarySetPrimitive(dictionary
, "aligned", ficlPrimitiveAligned
,
3149 ficlDictionarySetPrimitive(dictionary
, "allot", ficlPrimitiveAllot
,
3151 ficlDictionarySetPrimitive(dictionary
, "base", ficlPrimitiveBase
,
3153 ficlDictionarySetPrimitive(dictionary
, "begin", ficlPrimitiveBeginCoIm
,
3154 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3155 ficlDictionarySetPrimitive(dictionary
, "case", ficlPrimitiveCaseCoIm
,
3156 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3157 ficlDictionarySetPrimitive(dictionary
, "char", ficlPrimitiveChar
,
3159 ficlDictionarySetPrimitive(dictionary
, "char+", ficlPrimitiveCharPlus
,
3161 ficlDictionarySetPrimitive(dictionary
, "chars", ficlPrimitiveChars
,
3163 ficlDictionarySetPrimitive(dictionary
, "constant",
3164 ficlPrimitiveConstant
, FICL_WORD_DEFAULT
);
3165 ficlDictionarySetPrimitive(dictionary
, "count", ficlPrimitiveCount
,
3167 ficlDictionarySetPrimitive(dictionary
, "cr", ficlPrimitiveCR
,
3169 ficlDictionarySetPrimitive(dictionary
, "create", ficlPrimitiveCreate
,
3171 ficlDictionarySetPrimitive(dictionary
, "decimal", ficlPrimitiveDecimal
,
3173 ficlDictionarySetPrimitive(dictionary
, "depth", ficlPrimitiveDepth
,
3175 ficlDictionarySetPrimitive(dictionary
, "do", ficlPrimitiveDoCoIm
,
3176 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3177 ficlDictionarySetPrimitive(dictionary
, "does>", ficlPrimitiveDoesCoIm
,
3178 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3179 ficlDictionarySetPrimitive(dictionary
, "else", ficlPrimitiveElseCoIm
,
3180 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3181 ficlDictionarySetPrimitive(dictionary
, "emit", ficlPrimitiveEmit
,
3183 ficlDictionarySetPrimitive(dictionary
, "endcase",
3184 ficlPrimitiveEndcaseCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3185 ficlDictionarySetPrimitive(dictionary
, "endof", ficlPrimitiveEndofCoIm
,
3186 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3187 ficlDictionarySetPrimitive(dictionary
, "environment?",
3188 ficlPrimitiveEnvironmentQ
, FICL_WORD_DEFAULT
);
3189 ficlDictionarySetPrimitive(dictionary
, "evaluate",
3190 ficlPrimitiveEvaluate
, FICL_WORD_DEFAULT
);
3191 ficlDictionarySetPrimitive(dictionary
, "execute", ficlPrimitiveExecute
,
3193 ficlDictionarySetPrimitive(dictionary
, "exit", ficlPrimitiveExitCoIm
,
3194 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3195 ficlDictionarySetPrimitive(dictionary
, "fallthrough",
3196 ficlPrimitiveFallthroughCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3197 ficlDictionarySetPrimitive(dictionary
, "find", ficlPrimitiveCFind
,
3199 ficlDictionarySetPrimitive(dictionary
, "fm/mod",
3200 ficlPrimitiveFMSlashMod
, FICL_WORD_DEFAULT
);
3201 ficlDictionarySetPrimitive(dictionary
, "here", ficlPrimitiveHere
,
3203 ficlDictionarySetPrimitive(dictionary
, "hold", ficlPrimitiveHold
,
3205 ficlDictionarySetPrimitive(dictionary
, "if", ficlPrimitiveIfCoIm
,
3206 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3207 ficlDictionarySetPrimitive(dictionary
, "immediate",
3208 ficlPrimitiveImmediate
, FICL_WORD_DEFAULT
);
3209 ficlDictionarySetPrimitive(dictionary
, "literal",
3210 ficlPrimitiveLiteralIm
, FICL_WORD_IMMEDIATE
);
3211 ficlDictionarySetPrimitive(dictionary
, "loop", ficlPrimitiveLoopCoIm
,
3212 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3213 ficlDictionarySetPrimitive(dictionary
, "m*", ficlPrimitiveMStar
,
3215 ficlDictionarySetPrimitive(dictionary
, "mod", ficlPrimitiveMod
,
3217 ficlDictionarySetPrimitive(dictionary
, "of", ficlPrimitiveOfCoIm
,
3218 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3219 ficlDictionarySetPrimitive(dictionary
, "postpone",
3220 ficlPrimitivePostponeCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3221 ficlDictionarySetPrimitive(dictionary
, "quit", ficlPrimitiveQuit
,
3223 ficlDictionarySetPrimitive(dictionary
, "recurse",
3224 ficlPrimitiveRecurseCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3225 ficlDictionarySetPrimitive(dictionary
, "repeat",
3226 ficlPrimitiveRepeatCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3227 ficlDictionarySetPrimitive(dictionary
, "s\"",
3228 ficlPrimitiveStringQuoteIm
, FICL_WORD_IMMEDIATE
);
3229 ficlDictionarySetPrimitive(dictionary
, "sign", ficlPrimitiveSign
,
3231 ficlDictionarySetPrimitive(dictionary
, "sm/rem",
3232 ficlPrimitiveSMSlashRem
, FICL_WORD_DEFAULT
);
3233 ficlDictionarySetPrimitive(dictionary
, "source", ficlPrimitiveSource
,
3235 ficlDictionarySetPrimitive(dictionary
, "state", ficlPrimitiveState
,
3237 ficlDictionarySetPrimitive(dictionary
, "then", ficlPrimitiveEndifCoIm
,
3238 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3239 ficlDictionarySetPrimitive(dictionary
, "type", ficlPrimitiveType
,
3241 ficlDictionarySetPrimitive(dictionary
, "u.", ficlPrimitiveUDot
,
3243 ficlDictionarySetPrimitive(dictionary
, "um*", ficlPrimitiveUMStar
,
3245 ficlDictionarySetPrimitive(dictionary
, "um/mod",
3246 ficlPrimitiveUMSlashMod
, FICL_WORD_DEFAULT
);
3247 ficlDictionarySetPrimitive(dictionary
, "until",
3248 ficlPrimitiveUntilCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3249 ficlDictionarySetPrimitive(dictionary
, "variable",
3250 ficlPrimitiveVariable
, FICL_WORD_DEFAULT
);
3251 ficlDictionarySetPrimitive(dictionary
, "while",
3252 ficlPrimitiveWhileCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3253 ficlDictionarySetPrimitive(dictionary
, "word", ficlPrimitiveWord
,
3255 ficlDictionarySetPrimitive(dictionary
, "[",
3256 ficlPrimitiveLeftBracketCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3257 ficlDictionarySetPrimitive(dictionary
, "[\']",
3258 ficlPrimitiveBracketTickCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3259 ficlDictionarySetPrimitive(dictionary
, "[char]", ficlPrimitiveCharCoIm
,
3260 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3261 ficlDictionarySetPrimitive(dictionary
, "]", ficlPrimitiveRightBracket
,
3264 * The Core Extensions word set...
3265 * see softcore.fr for other definitions
3268 ficlDictionarySetPrimitive(dictionary
, ".(", ficlPrimitiveDotParen
,
3269 FICL_WORD_IMMEDIATE
);
3270 /* ".r" is in softcore */
3271 ficlDictionarySetPrimitive(dictionary
, ":noname",
3272 ficlPrimitiveColonNoName
, FICL_WORD_DEFAULT
);
3273 ficlDictionarySetPrimitive(dictionary
, "?do", ficlPrimitiveQDoCoIm
,
3274 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3275 ficlDictionarySetPrimitive(dictionary
, "again", ficlPrimitiveAgainCoIm
,
3276 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3277 ficlDictionarySetPrimitive(dictionary
, "c\"",
3278 ficlPrimitiveCountedStringQuoteIm
, FICL_WORD_IMMEDIATE
);
3279 ficlDictionarySetPrimitive(dictionary
, "hex", ficlPrimitiveHex
,
3281 ficlDictionarySetPrimitive(dictionary
, "pad", ficlPrimitivePad
,
3283 ficlDictionarySetPrimitive(dictionary
, "parse", ficlPrimitiveParse
,
3287 * query restore-input save-input tib u.r u> unused
3288 * [FICL_VM_STATE_COMPILE]
3290 ficlDictionarySetPrimitive(dictionary
, "refill", ficlPrimitiveRefill
,
3292 ficlDictionarySetPrimitive(dictionary
, "source-id",
3293 ficlPrimitiveSourceID
, FICL_WORD_DEFAULT
);
3294 ficlDictionarySetPrimitive(dictionary
, "to", ficlPrimitiveToValue
,
3295 FICL_WORD_IMMEDIATE
);
3296 ficlDictionarySetPrimitive(dictionary
, "value", ficlPrimitiveConstant
,
3298 ficlDictionarySetPrimitive(dictionary
, "\\", ficlPrimitiveBackslash
,
3299 FICL_WORD_IMMEDIATE
);
3302 * Environment query values for the Core word set
3304 ficlDictionarySetConstant(environment
, "/counted-string",
3305 FICL_COUNTED_STRING_MAX
);
3306 ficlDictionarySetConstant(environment
, "/hold", FICL_PAD_SIZE
);
3307 ficlDictionarySetConstant(environment
, "/pad", FICL_PAD_SIZE
);
3308 ficlDictionarySetConstant(environment
, "address-unit-bits", 8);
3309 ficlDictionarySetConstant(environment
, "core", FICL_TRUE
);
3310 ficlDictionarySetConstant(environment
, "core-ext", FICL_FALSE
);
3311 ficlDictionarySetConstant(environment
, "floored", FICL_FALSE
);
3312 ficlDictionarySetConstant(environment
, "max-char", UCHAR_MAX
);
3313 ficlDictionarySetConstant(environment
, "max-n", LONG_MAX
);
3314 ficlDictionarySetConstant(environment
, "max-u", ULONG_MAX
);
3318 ficlInteger low
, high
;
3322 FICL_2INTEGER_SET(high
, low
, id
);
3323 ficlDictionarySet2Constant(environment
, "max-d", id
);
3325 FICL_2INTEGER_SET(high
, low
, id
);
3326 ficlDictionarySet2Constant(environment
, "max-ud", id
);
3329 ficlDictionarySetConstant(environment
, "return-stack-cells",
3330 FICL_DEFAULT_STACK_SIZE
);
3331 ficlDictionarySetConstant(environment
, "stack-cells",
3332 FICL_DEFAULT_STACK_SIZE
);
3335 * The optional Double-Number word set (partial)
3337 ficlDictionarySetPrimitive(dictionary
, "2constant",
3338 ficlPrimitive2Constant
, FICL_WORD_IMMEDIATE
);
3339 ficlDictionarySetPrimitive(dictionary
, "2literal",
3340 ficlPrimitive2LiteralIm
, FICL_WORD_IMMEDIATE
);
3341 ficlDictionarySetPrimitive(dictionary
, "2variable",
3342 ficlPrimitive2Variable
, FICL_WORD_IMMEDIATE
);
3344 * D+ D- D. D.R D0< D0= D2* D2/ in softcore
3345 * D< D= D>S DABS DMAX DMIN DNEGATE in softcore
3346 * m-star-slash is TODO
3353 ficlDictionarySetPrimitive(dictionary
, "2rot",
3354 ficlPrimitive2Rot
, FICL_WORD_DEFAULT
);
3355 ficlDictionarySetPrimitive(dictionary
, "2value",
3356 ficlPrimitive2Constant
, FICL_WORD_IMMEDIATE
);
3357 /* du< in softcore */
3359 * The optional Exception and Exception Extensions word set
3361 ficlDictionarySetPrimitive(dictionary
, "catch", ficlPrimitiveCatch
,
3363 ficlDictionarySetPrimitive(dictionary
, "throw", ficlPrimitiveThrow
,
3366 ficlDictionarySetConstant(environment
, "exception", FICL_TRUE
);
3367 ficlDictionarySetConstant(environment
, "exception-ext", FICL_TRUE
);
3370 * The optional Locals and Locals Extensions word set
3371 * see softcore.c for implementation of locals|
3373 #if FICL_WANT_LOCALS
3374 ficlDictionarySetPrimitive(dictionary
, "doLocal",
3375 ficlPrimitiveDoLocalIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3376 ficlDictionarySetPrimitive(dictionary
, "(local)",
3377 ficlPrimitiveLocalParen
, FICL_WORD_COMPILE_ONLY
);
3378 ficlDictionarySetPrimitive(dictionary
, "(2local)",
3379 ficlPrimitive2LocalParen
, FICL_WORD_COMPILE_ONLY
);
3381 ficlDictionarySetConstant(environment
, "locals", FICL_TRUE
);
3382 ficlDictionarySetConstant(environment
, "locals-ext", FICL_TRUE
);
3383 ficlDictionarySetConstant(environment
, "#locals", FICL_MAX_LOCALS
);
3387 * The optional Memory-Allocation word set
3390 ficlDictionarySetPrimitive(dictionary
, "allocate",
3391 ficlPrimitiveAllocate
, FICL_WORD_DEFAULT
);
3392 ficlDictionarySetPrimitive(dictionary
, "free", ficlPrimitiveFree
,
3394 ficlDictionarySetPrimitive(dictionary
, "resize", ficlPrimitiveResize
,
3397 ficlDictionarySetConstant(environment
, "memory-alloc", FICL_TRUE
);
3400 * The optional Search-Order word set
3402 ficlSystemCompileSearch(system
);
3405 * The optional Programming-Tools and Programming-Tools
3406 * Extensions word set
3408 ficlSystemCompileTools(system
);
3411 * The optional File-Access and File-Access Extensions word set
3414 ficlSystemCompileFile(system
);
3420 ficlDictionarySetPrimitive(dictionary
, ".ver", ficlPrimitiveVersion
,
3422 ficlDictionarySetPrimitive(dictionary
, ">name", ficlPrimitiveToName
,
3424 ficlDictionarySetPrimitive(dictionary
, "add-parse-step",
3425 ficlPrimitiveAddParseStep
, FICL_WORD_DEFAULT
);
3426 ficlDictionarySetPrimitive(dictionary
, "body>", ficlPrimitiveFromBody
,
3428 ficlDictionarySetPrimitive(dictionary
, "compile-only",
3429 ficlPrimitiveCompileOnly
, FICL_WORD_DEFAULT
);
3430 ficlDictionarySetPrimitive(dictionary
, "endif", ficlPrimitiveEndifCoIm
,
3431 FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3432 ficlDictionarySetPrimitive(dictionary
, "last-word",
3433 ficlPrimitiveLastWord
, FICL_WORD_DEFAULT
);
3434 ficlDictionarySetPrimitive(dictionary
, "hash", ficlPrimitiveHash
,
3436 ficlDictionarySetPrimitive(dictionary
, "objectify",
3437 ficlPrimitiveSetObjectFlag
, FICL_WORD_DEFAULT
);
3438 ficlDictionarySetPrimitive(dictionary
, "?object",
3439 ficlPrimitiveIsObject
, FICL_WORD_DEFAULT
);
3440 ficlDictionarySetPrimitive(dictionary
, "parse-word",
3441 ficlPrimitiveParseNoCopy
, FICL_WORD_DEFAULT
);
3442 ficlDictionarySetPrimitive(dictionary
, "sfind", ficlPrimitiveSFind
,
3444 ficlDictionarySetPrimitive(dictionary
, "sliteral",
3445 ficlPrimitiveSLiteralCoIm
, FICL_WORD_COMPILE_ONLY_IMMEDIATE
);
3446 ficlDictionarySetPrimitive(dictionary
, "sprintf", ficlPrimitiveSprintf
,
3448 ficlDictionarySetPrimitive(dictionary
, "strlen", ficlPrimitiveStrlen
,
3450 ficlDictionarySetPrimitive(dictionary
, "x.", ficlPrimitiveHexDot
,
3453 ficlDictionarySetPrimitive(dictionary
, "user", ficlPrimitiveUser
,
3458 * internal support words
3460 interpret
= ficlDictionarySetPrimitive(dictionary
, "interpret",
3461 ficlPrimitiveInterpret
, FICL_WORD_DEFAULT
);
3462 ficlDictionarySetPrimitive(dictionary
, "lookup", ficlPrimitiveLookup
,
3464 ficlDictionarySetPrimitive(dictionary
, "(parse-step)",
3465 ficlPrimitiveParseStepParen
, FICL_WORD_DEFAULT
);
3466 system
->exitInnerWord
= ficlDictionarySetPrimitive(dictionary
,
3467 "exit-inner", ficlPrimitiveExitInner
, FICL_WORD_DEFAULT
);
3470 * Set constants representing the internal instruction words
3471 * If you want all of 'em, turn that "#if 0" to "#if 1".
3472 * By default you only get the numbers (fi0, fiNeg1, etc).
3474 #define FICL_TOKEN(token, description) \
3475 ficlDictionarySetConstant(dictionary, #token, token);
3477 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \
3478 ficlDictionarySetConstant(dictionary, #token, token);
3480 #define FICL_INSTRUCTION_TOKEN(token, description, flags)
3482 #include "ficltokens.h"
3484 #undef FICL_INSTRUCTION_TOKEN
3487 * Set up system's outer interpreter loop - maybe this should
3490 system
->interpreterLoop
[0] = interpret
;
3491 system
->interpreterLoop
[1] = (ficlWord
*)ficlInstructionBranchParen
;
3492 system
->interpreterLoop
[2] = (ficlWord
*)(void *)(-2);
3494 FICL_SYSTEM_ASSERT(system
,
3495 ficlDictionaryCellsAvailable(dictionary
) > 0);