dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / common / ficl / primitives.c
blobc8b982970571c2927f1e433f3d8554a367f2e2d0
1 /*
2 * w o r d s . c
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 $
8 */
9 /*
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
24 * are met:
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
41 * SUCH DAMAGE.
44 #include "ficl.h"
45 #include <limits.h>
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...
69 static void
70 markBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag)
72 ficlStackPushPointer(vm->dataStack, dictionary->here);
73 ficlStackPushPointer(vm->dataStack, tag);
76 static void
77 markControlTag(ficlVm *vm, char *tag)
79 ficlStackPushPointer(vm->dataStack, tag);
82 static void
83 matchControlTag(ficlVm *vm, char *wantTag)
85 char *tag;
87 FICL_STACK_CHECK(vm->dataStack, 1, 0);
89 tag = (char *)ficlStackPopPointer(vm->dataStack);
92 * Changed the code below to compare the pointers first
93 * (by popular demand)
95 if ((tag != wantTag) && strcmp(tag, wantTag)) {
96 ficlVmThrowError(vm,
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
106 static void
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
126 static void
127 resolveForwardBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag)
129 ficlInteger offset;
130 ficlCell *patchAddr;
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.
146 static void
147 resolveAbsBranch(ficlDictionary *dictionary, ficlVm *vm, char *wantTag)
149 ficlCell *patchAddr;
150 char *tag;
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.
177 static void
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);
189 #if FICL_WANT_LOCALS
190 vm->callback.system->localsCount = 0;
191 #endif
194 static void
195 ficlPrimitiveSemicolonCoIm(ficlVm *vm)
197 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
199 matchControlTag(vm, colonTag);
201 #if FICL_WANT_LOCALS
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;
210 #endif
212 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionSemiParen);
213 vm->state = FICL_VM_STATE_INTERPRET;
214 ficlDictionaryUnsmudge(dictionary);
218 * e x i t
219 * CORE
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".
226 static void
227 ficlPrimitiveExitCoIm(ficlVm *vm)
229 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
230 FICL_IGNORE(vm);
232 #if FICL_WANT_LOCALS
233 if (vm->callback.system->localsCount > 0) {
234 ficlDictionaryAppendUnsigned(dictionary,
235 ficlInstructionUnlinkParen);
237 #endif
238 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionExitParen);
242 * c o n s t a n t
243 * IMMEDIATE
244 * Compiles a constant into the dictionary. Constants return their
245 * value when invoked. Expects a value on top of the parm stack.
247 static void
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));
259 static void
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
274 * stack
276 static void
277 ficlPrimitiveDot(ficlVm *vm)
279 ficlCell c;
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);
289 static void
290 ficlPrimitiveUDot(ficlVm *vm)
292 ficlUnsigned u;
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);
302 static void
303 ficlPrimitiveHexDot(ficlVm *vm)
305 ficlUnsigned u;
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);
316 * s t r l e n
317 * Ficl ( c-string -- length )
319 * Returns the length of a C-style (zero-terminated) string.
321 * --lch
323 static void
324 ficlPrimitiveStrlen(ficlVm *vm)
326 char *address = (char *)ficlStackPopPointer(vm->dataStack);
327 ficlStackPushInteger(vm->dataStack, strlen(address));
331 * s p r i n t f
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
340 * the buffer
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).
354 * --lch
356 static void
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;
367 int base = 10;
368 int unsignedInteger = 0; /* false */
370 int append = 1; /* true */
372 while (format < formatStop) {
373 char scratch[64];
374 char *source;
375 int actualLength;
376 int desiredLength;
377 int leadingZeroes;
379 if (*format != '%') {
380 source = format;
381 actualLength = desiredLength = 1;
382 leadingZeroes = 0;
383 } else {
384 format++;
385 if (format == formatStop)
386 break;
388 leadingZeroes = (*format == '0');
389 if (leadingZeroes) {
390 format++;
391 if (format == formatStop)
392 break;
395 desiredLength = isdigit((unsigned char)*format);
396 if (desiredLength) {
397 desiredLength = strtoul(format, &format, 10);
398 if (format == formatStop)
399 break;
400 } else if (*format == '*') {
401 desiredLength =
402 ficlStackPopInteger(vm->dataStack);
404 format++;
405 if (format == formatStop)
406 break;
409 switch (*format) {
410 case 's':
411 case 'S':
412 actualLength =
413 ficlStackPopInteger(vm->dataStack);
414 source = (char *)
415 ficlStackPopPointer(vm->dataStack);
416 break;
417 case 'x':
418 case 'X':
419 base = 16;
420 case 'u':
421 case 'U':
422 unsignedInteger = 1; /* true */
423 case 'd':
424 case 'D': {
425 int integer;
426 integer = ficlStackPopInteger(vm->dataStack);
427 if (unsignedInteger)
428 ficlUltoa(integer, scratch, base);
429 else
430 ficlLtoa(integer, scratch, base);
431 base = 10;
432 unsignedInteger = 0; /* false */
433 source = scratch;
434 actualLength = strlen(scratch);
435 break;
437 case '%':
438 source = format;
439 actualLength = 1;
440 default:
441 continue;
445 if (append) {
446 if (!desiredLength)
447 desiredLength = actualLength;
448 if (desiredLength > bufferLength) {
449 append = 0; /* false */
450 desiredLength = bufferLength;
452 while (desiredLength > actualLength) {
453 *buffer++ = (char)((leadingZeroes) ? '0' : ' ');
454 bufferLength--;
455 desiredLength--;
457 memcpy(buffer, source, actualLength);
458 buffer += actualLength;
459 bufferLength -= actualLength;
462 format++;
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
473 static void
474 ficlPrimitiveDepth(ficlVm *vm)
476 int i;
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
487 static void
488 ficlPrimitiveEmit(ficlVm *vm)
490 char buffer[2];
491 int i;
493 FICL_STACK_CHECK(vm->dataStack, 1, 0);
495 i = ficlStackPopInteger(vm->dataStack);
496 buffer[0] = (char)i;
497 buffer[1] = '\0';
498 ficlVmTextOut(vm, buffer);
501 static void
502 ficlPrimitiveCR(ficlVm *vm)
504 ficlVmTextOut(vm, "\n");
507 static void
508 ficlPrimitiveBackslash(ficlVm *vm)
510 char *trace = ficlVmGetInBuf(vm);
511 char *stop = ficlVmGetInBufEnd(vm);
512 char c = *trace;
514 while ((trace != stop) && (c != '\r') && (c != '\n')) {
515 c = *++trace;
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.
523 if (trace != stop) {
524 trace++;
526 if ((trace != stop) && (c != *trace) &&
527 ((*trace == '\r') || (*trace == '\n')))
528 trace++;
531 ficlVmUpdateTib(vm, trace);
535 * paren CORE
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
540 * in the parse area.
542 static void
543 ficlPrimitiveParenthesis(ficlVm *vm)
545 ficlVmParseStringEx(vm, ')', 0);
549 * F E T C H & S T O R E
553 * i f C o I m
554 * IMMEDIATE
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.
559 static void
560 ficlPrimitiveIfCoIm(ficlVm *vm)
562 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
564 ficlDictionaryAppendUnsigned(dictionary,
565 ficlInstructionBranch0ParenWithCheck);
566 markBranch(dictionary, vm, origTag);
567 ficlDictionaryAppendUnsigned(dictionary, 1);
571 * e l s e C o I m
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
579 * address.
580 * 4) Push the "else" patch address. ("endif" patches this to jump past
581 * the "else" code.
583 static void
584 ficlPrimitiveElseCoIm(ficlVm *vm)
586 ficlCell *patchAddr;
587 ficlInteger offset;
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" */
606 * e n d i f C o I m
608 static void
609 ficlPrimitiveEndifCoIm(ficlVm *vm)
611 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
612 resolveForwardBranch(dictionary, vm, origTag);
616 * c a s e C o I m
617 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
620 * At FICL_VM_STATE_COMPILE-time, a CASE-SYS (see DPANS94 6.2.0873) looks
621 * like this:
622 * i*addr i caseTag
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
626 * to ENDCASE.
628 static void
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
641 static void
642 ficlPrimitiveEndcaseCoIm(ficlVm *vm)
644 ficlUnsigned fixupCount;
645 ficlDictionary *dictionary;
646 ficlCell *patchAddr;
647 ficlInteger offset;
650 * if the last OF ended with FALLTHROUGH,
651 * just add the FALLTHROUGH fixup to the
652 * ENDOF fixups
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;
683 * o f C o I m
684 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
686 static void
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;
714 * e n d o f C o I m
715 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
717 static void
718 ficlPrimitiveEndofCoIm(ficlVm *vm)
720 ficlCell *patchAddr;
721 ficlUnsigned fixupCount;
722 ficlInteger offset;
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,
743 * and the caseTag
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
761 static void
762 ficlPrimitiveFallthroughCoIm(ficlVm *vm)
764 ficlCell *patchAddr;
765 ficlInteger offset;
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;
797 * h a s h
798 * hash ( c-addr u -- code)
799 * calculates hashcode of specified string and leaves it on the stack
801 static void
802 ficlPrimitiveHash(ficlVm *vm)
804 ficlString s;
806 FICL_STRING_SET_LENGTH(s, ficlStackPopUnsigned(vm->dataStack));
807 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack));
808 ficlStackPushUnsigned(vm->dataStack, ficlHashCode(s));
812 * i n t e r p r e t
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...
821 * End 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);
829 static void
830 ficlPrimitiveInterpret(ficlVm *vm)
832 ficlString s;
833 int i;
834 ficlSystem *system;
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.
844 if (s.length == 0) {
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];
855 if (word == NULL)
856 break;
858 if (word->code == ficlPrimitiveParseStepParen) {
859 ficlParseStep pStep;
860 pStep = (ficlParseStep)(word->param->fn);
861 if ((*pStep)(vm, s))
862 return;
863 } else {
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))
870 return;
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)
883 static void
884 ficlPrimitiveLookup(ficlVm *vm)
886 ficlString name;
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).
899 void
900 ficlPrimitiveParseStepParen(ficlVm *vm)
902 ficlString s;
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));
912 static void
913 ficlPrimitiveAddParseStep(ficlVm *vm)
915 ficlWord *pStep;
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);
926 * l i t e r a l I m
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)".
930 * IMMEDIATE
932 void
933 ficlPrimitiveLiteralIm(ficlVm *vm)
935 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
936 ficlInteger value;
938 value = ficlStackPopInteger(vm->dataStack);
940 switch (value) {
941 case 1:
942 case 2:
943 case 3:
944 case 4:
945 case 5:
946 case 6:
947 case 7:
948 case 8:
949 case 9:
950 case 10:
951 case 11:
952 case 12:
953 case 13:
954 case 14:
955 case 15:
956 case 16:
957 ficlDictionaryAppendUnsigned(dictionary, value);
958 break;
960 case 0:
961 case -1:
962 case -2:
963 case -3:
964 case -4:
965 case -5:
966 case -6:
967 case -7:
968 case -8:
969 case -9:
970 case -10:
971 case -11:
972 case -12:
973 case -13:
974 case -14:
975 case -15:
976 case -16:
977 ficlDictionaryAppendUnsigned(dictionary,
978 ficlInstruction0 - value);
979 break;
981 default:
982 ficlDictionaryAppendUnsigned(dictionary,
983 ficlInstructionLiteralParen);
984 ficlDictionaryAppendUnsigned(dictionary, value);
985 break;
989 static void
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));
1000 * D o / L o o p
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
1009 * +loop
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.
1023 static void
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);
1041 static void
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);
1060 static void
1061 ficlPrimitiveLoopCoIm(ficlVm *vm)
1063 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1065 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionLoopParen);
1066 resolveBackBranch(dictionary, vm, doTag);
1067 resolveAbsBranch(dictionary, vm, leaveTag);
1070 static void
1071 ficlPrimitivePlusLoopCoIm(ficlVm *vm)
1073 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1075 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionPlusLoopParen);
1076 resolveBackBranch(dictionary, vm, doTag);
1077 resolveAbsBranch(dictionary, vm, leaveTag);
1081 * v a r i a b l e
1083 static void
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);
1094 static void
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
1108 static void
1109 ficlPrimitiveBase(ficlVm *vm)
1111 ficlCell *pBase, c;
1113 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1115 pBase = (ficlCell *)(&vm->base);
1116 c.p = pBase;
1117 ficlStackPush(vm->dataStack, c);
1120 static void
1121 ficlPrimitiveDecimal(ficlVm *vm)
1123 vm->base = 10;
1127 static void
1128 ficlPrimitiveHex(ficlVm *vm)
1130 vm->base = 16;
1134 * a l l o t & f r i e n d s
1136 static void
1137 ficlPrimitiveAllot(ficlVm *vm)
1139 ficlDictionary *dictionary;
1140 ficlInteger i;
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);
1152 static void
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);
1164 * t i c k
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.
1170 void
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);
1179 if (!word)
1180 ficlVmThrowError(vm, "%.*s not found",
1181 FICL_STRING_GET_LENGTH(name),
1182 FICL_STRING_GET_POINTER(name));
1183 ficlStackPushPointer(vm->dataStack, word);
1186 static void
1187 ficlPrimitiveBracketTickCoIm(ficlVm *vm)
1189 ficlPrimitiveTick(vm);
1190 ficlPrimitiveLiteralIm(vm);
1194 * p o s t p o n e
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)
1199 static void
1200 ficlPrimitivePostponeCoIm(ficlVm *vm)
1202 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1203 ficlWord *word;
1204 ficlWord *pComma = ficlSystemLookup(vm->callback.system, ",");
1205 ficlCell c;
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));
1214 } else {
1215 ficlPrimitiveLiteralIm(vm);
1216 c.p = pComma;
1217 ficlDictionaryAppendCell(dictionary, c);
1222 * e x e c u t e
1223 * Pop an execution token (pointer to a word) off the stack and
1224 * run it
1226 static void
1227 ficlPrimitiveExecute(ficlVm *vm)
1229 ficlWord *word;
1231 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1233 word = ficlStackPopPointer(vm->dataStack);
1234 ficlVmExecuteWord(vm, word);
1238 * i m m e d i a t e
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)
1243 static void
1244 ficlPrimitiveImmediate(ficlVm *vm)
1246 FICL_IGNORE(vm);
1247 ficlDictionarySetImmediate(ficlVmGetDictionary(vm));
1250 static void
1251 ficlPrimitiveCompileOnly(ficlVm *vm)
1253 FICL_IGNORE(vm);
1254 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_COMPILE_ONLY);
1257 static void
1258 ficlPrimitiveSetObjectFlag(ficlVm *vm)
1260 FICL_IGNORE(vm);
1261 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_OBJECT);
1264 static void
1265 ficlPrimitiveIsObject(ficlVm *vm)
1267 ficlInteger flag;
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);
1276 static void
1277 ficlPrimitiveCountedStringQuoteIm(ficlVm *vm)
1279 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1281 if (vm->state == FICL_VM_STATE_INTERPRET) {
1282 ficlCountedString *counted = (ficlCountedString *)
1283 dictionary->here;
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);
1296 dictionary->here =
1297 FICL_POINTER_TO_CELL(ficlVmGetString(vm,
1298 (ficlCountedString *)dictionary->here, '\"'));
1299 ficlDictionaryAlign(dictionary);
1304 * d o t Q u o t e
1305 * IMMEDIATE word that compiles a string literal for later display
1306 * FICL_VM_STATE_COMPILE fiStringLiteralParen, then copy the bytes of the
1307 * string from the
1308 * TIB to the dictionary. Backpatch the count byte and align the dictionary.
1310 static void
1311 ficlPrimitiveDotQuoteCoIm(ficlVm *vm)
1313 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1314 ficlWord *pType = ficlSystemLookup(vm->callback.system, "type");
1315 ficlCell c;
1317 FICL_VM_ASSERT(vm, pType);
1319 ficlDictionaryAppendUnsigned(dictionary,
1320 ficlInstructionStringLiteralParen);
1321 dictionary->here =
1322 FICL_POINTER_TO_CELL(ficlVmGetString(vm,
1323 (ficlCountedString *)dictionary->here, '\"'));
1324 ficlDictionaryAlign(dictionary);
1325 c.p = pType;
1326 ficlDictionaryAppendCell(dictionary, c);
1329 static void
1330 ficlPrimitiveDotParen(ficlVm *vm)
1332 char *from = ficlVmGetInBuf(vm);
1333 char *stop = ficlVmGetInBufEnd(vm);
1334 char *to = vm->pad;
1335 char c;
1338 * Note: the standard does not want leading spaces skipped.
1340 for (c = *from; (from != stop) && (c != ')'); c = *++from)
1341 *to++ = c;
1343 *to = '\0';
1344 if ((from != stop) && (c == ')'))
1345 from++;
1347 ficlVmTextOut(vm, vm->pad);
1348 ficlVmUpdateTib(vm, from);
1352 * s l i t e r a l
1353 * STRING
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;
1365 char *from;
1366 char *to;
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) {
1381 *to++ = *from++;
1384 *to++ = 0;
1385 dictionary->here = FICL_POINTER_TO_CELL(ficlAlignPointer(to));
1389 * s t a t e
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> .
1405 static void
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);
1416 static void
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;
1430 #endif
1431 FICL_IGNORE(vm);
1433 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoesParen);
1437 * t o b o d y
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.
1442 static void
1443 ficlPrimitiveToBody(ficlVm *vm)
1445 ficlWord *word;
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
1456 static void
1457 ficlPrimitiveFromBody(ficlVm *vm)
1459 char *ptr;
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
1469 * xt.
1471 static void
1472 ficlPrimitiveToName(ficlVm *vm)
1474 ficlWord *word;
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);
1483 static void
1484 ficlPrimitiveLastWord(ficlVm *vm)
1486 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1487 ficlWord *wp = dictionary->smudge;
1488 ficlCell c;
1490 FICL_VM_ASSERT(vm, wp);
1492 c.p = wp;
1493 ficlVmPush(vm, c);
1497 * l b r a c k e t e t c
1499 static void
1500 ficlPrimitiveLeftBracketCoIm(ficlVm *vm)
1502 vm->state = FICL_VM_STATE_INTERPRET;
1505 static void
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.
1516 * (clear the pad)
1518 static void
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.
1533 static void
1534 ficlPrimitiveNumberSign(ficlVm *vm)
1536 ficlCountedString *counted;
1537 ficl2Unsigned u;
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.
1555 static void
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!
1577 static void
1578 ficlPrimitiveNumberSignS(ficlVm *vm)
1580 ficlCountedString *counted;
1581 ficl2Unsigned u;
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);
1589 do {
1590 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base));
1591 counted->text[counted->length++] =
1592 ficlDigitToCharacter(uqr.remainder);
1593 u = uqr.quotient;
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.
1605 static void
1606 ficlPrimitiveHold(ficlVm *vm)
1608 ficlCountedString *counted;
1609 int i;
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.
1624 static void
1625 ficlPrimitiveSign(ficlVm *vm)
1627 ficlCountedString *counted;
1628 int i;
1630 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1632 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1633 i = ficlStackPopInteger(vm->dataStack);
1634 if (i < 0)
1635 counted->text[counted->length++] = '-';
1639 * t o N u m b e r
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
1650 * conversion.
1652 static void
1653 ficlPrimitiveToNumber(ficlVm *vm)
1655 ficlUnsigned length;
1656 char *trace;
1657 ficl2Unsigned accumulator;
1658 ficlUnsigned base = vm->base;
1659 ficlUnsigned c;
1660 ficlUnsigned digit;
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--) {
1669 if (c < '0')
1670 break;
1672 digit = c - '0';
1674 if (digit > 9)
1675 digit = tolower(c) - 'a' + 10;
1677 * Note: following test also catches chars between 9 and a
1678 * because 'digit' is unsigned!
1680 if (digit >= base)
1681 break;
1683 accumulator = ficl2UnsignedMultiplyAccumulate(accumulator,
1684 base, digit);
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.
1705 static void
1706 ficlPrimitiveQuit(ficlVm *vm)
1708 ficlVmThrow(vm, FICL_VM_STATUS_QUIT);
1711 static void
1712 ficlPrimitiveAbort(ficlVm *vm)
1714 ficlVmThrow(vm, FICL_VM_STATUS_ABORT);
1718 * a c c e p t
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
1729 * the stack.)
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.
1735 static void
1736 ficlPrimitiveAccept(ficlVm *vm)
1738 ficlUnsigned size;
1739 char *address;
1740 int c;
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) {
1749 c = getchar();
1750 if (c == '\n' || c == '\r')
1751 break;
1752 address[length++] = c;
1754 ficlStackPushInteger(vm->dataStack, length);
1758 * a l i g n
1759 * 6.1.0705 ALIGN CORE ( -- )
1760 * If the data-space pointer is not aligned, reserve enough space to
1761 * align it.
1763 static void
1764 ficlPrimitiveAlign(ficlVm *vm)
1766 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1767 FICL_IGNORE(vm);
1768 ficlDictionaryAlign(dictionary);
1772 * a l i g n e d
1774 static void
1775 ficlPrimitiveAligned(ficlVm *vm)
1777 void *addr;
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
1788 * A.6.1.0760 BEGIN
1789 * Typical use:
1790 * : X ... BEGIN ... test UNTIL ;
1791 * or
1792 * : X ... BEGIN ... test WHILE ... REPEAT ;
1794 static void
1795 ficlPrimitiveBeginCoIm(ficlVm *vm)
1797 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1798 markBranch(dictionary, vm, destTag);
1801 static void
1802 ficlPrimitiveUntilCoIm(ficlVm *vm)
1804 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1806 ficlDictionaryAppendUnsigned(dictionary,
1807 ficlInstructionBranch0ParenWithCheck);
1808 resolveBackBranch(dictionary, vm, destTag);
1811 static void
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);
1829 static void
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);
1842 static void
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.
1859 * bracket-char CORE
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.
1867 static void
1868 ficlPrimitiveChar(ficlVm *vm)
1870 ficlString s;
1872 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1874 s = ficlVmGetWord(vm);
1875 ficlStackPushUnsigned(vm->dataStack, (ficlUnsigned)(s.text[0]));
1878 static void
1879 ficlPrimitiveCharCoIm(ficlVm *vm)
1881 ficlPrimitiveChar(vm);
1882 ficlPrimitiveLiteralIm(vm);
1886 * c h a r P l u s
1887 * char-plus CORE ( c-addr1 -- c-addr2 )
1888 * Add the size in address units of a character to c-addr1, giving c-addr2.
1890 static void
1891 ficlPrimitiveCharPlus(ficlVm *vm)
1893 char *p;
1895 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1897 p = ficlStackPopPointer(vm->dataStack);
1898 ficlStackPushPointer(vm->dataStack, p + 1);
1902 * c h a r s
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)
1910 #endif
1911 static void
1912 ficlPrimitiveChars(ficlVm *vm)
1914 if (sizeof (char) > 1) {
1915 ficlInteger i;
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)
1926 #endif
1929 * c o u n t
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.
1936 static void
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.
1961 static void
1962 ficlPrimitiveEnvironmentQ(ficlVm *vm)
1964 ficlDictionary *environment;
1965 ficlWord *word;
1966 ficlString name;
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);
1976 if (word != NULL) {
1977 ficlVmExecuteWord(vm, word);
1978 ficlStackPushInteger(vm->dataStack, FICL_TRUE);
1979 } else {
1980 ficlStackPushInteger(vm->dataStack, FICL_FALSE);
1985 * e v a l u a t e
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.
1994 static void
1995 ficlPrimitiveEvaluate(ficlVm *vm)
1997 ficlCell id;
1998 int result;
1999 ficlString string;
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));
2006 id = vm->sourceId;
2007 vm->sourceId.i = -1;
2008 result = ficlVmExecuteString(vm, string);
2009 vm->sourceId = id;
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.
2022 static void
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,
2038 '\"'));
2039 ficlDictionaryAlign(dictionary);
2044 * t y p e
2045 * Pop count and char address from stack and print the designated string.
2047 static void
2048 ficlPrimitiveType(ficlVm *vm)
2050 ficlUnsigned length;
2051 char *s;
2053 FICL_STACK_CHECK(vm->dataStack, 2, 0);
2055 length = ficlStackPopUnsigned(vm->dataStack);
2056 s = ficlStackPopPointer(vm->dataStack);
2058 if ((s == NULL) || (length == 0))
2059 return;
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
2064 * and terminate it.
2066 if (s[length] != 0) {
2067 char *here = (char *)ficlVmGetDictionary(vm)->here;
2068 if (s != here)
2069 strncpy(here, s, length);
2071 here[length] = '\0';
2072 s = here;
2075 ficlVmTextOut(vm, s);
2079 * w o r d
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.
2092 static void
2093 ficlPrimitiveWord(ficlVm *vm)
2095 ficlCountedString *counted;
2096 char delim;
2097 ficlString name;
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)
2131 ficlString s;
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));
2141 * p a r s e
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
2146 * a zero length.
2147 * NOTE! PARSE differs from WORD: it does not skip leading delimiters.
2149 static void
2150 ficlPrimitiveParse(ficlVm *vm)
2152 ficlString s;
2153 char delim;
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));
2165 * f i n d
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.
2174 static void
2175 do_find(ficlVm *vm, ficlString name, void *returnForFailure)
2177 ficlWord *word;
2179 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name);
2180 if (word) {
2181 ficlStackPushPointer(vm->dataStack, word);
2182 ficlStackPushInteger(vm->dataStack,
2183 (ficlWordIsImmediate(word) ? 1 : -1));
2184 } else {
2185 ficlStackPushPointer(vm->dataStack, returnForFailure);
2186 ficlStackPushUnsigned(vm->dataStack, 0);
2191 * f i n d
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.
2200 static void
2201 ficlPrimitiveCFind(ficlVm *vm)
2203 ficlCountedString *counted;
2204 ficlString name;
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);
2214 * s f i n d
2215 * Ficl ( c-addr u -- 0 0 | xt 1 | xt -1 )
2216 * Like FIND, but takes "c-addr u" for the string.
2218 static void
2219 ficlPrimitiveSFind(ficlVm *vm)
2221 ficlString name;
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);
2232 * r e c u r s e
2234 static void
2235 ficlPrimitiveRecurseCoIm(ficlVm *vm)
2237 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2238 ficlCell c;
2240 FICL_IGNORE(vm);
2241 c.p = dictionary->smudge;
2242 ficlDictionaryAppendCell(dictionary, c);
2246 * s o u r c e
2247 * CORE ( -- c-addr u )
2248 * c-addr is the address of, and u is the number of characters in, the
2249 * input buffer.
2251 static void
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));
2261 * v e r s i o n
2262 * non-standard...
2264 static void
2265 ficlPrimitiveVersion(ficlVm *vm)
2267 ficlVmTextOut(vm, "Ficl version " FICL_VERSION "\n");
2271 * t o I n
2272 * to-in CORE
2274 static void
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.
2288 static void
2289 ficlPrimitiveColonNoName(ficlVm *vm)
2291 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2292 ficlWord *word;
2293 ficlString name;
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
2321 * nUser.
2323 #if FICL_WANT_USER
2324 static void
2325 ficlPrimitiveUser(ficlVm *vm)
2327 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2328 ficlString name = ficlVmGetWord(vm);
2329 ficlCell c;
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);
2340 #endif
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).
2351 void
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 */
2360 isFloat = 0;
2361 #endif /* FICL_WANT_FLOAT */
2363 if (vm->state == FICL_VM_STATE_INTERPRET) {
2364 ficlStack *stack;
2365 #if FICL_WANT_FLOAT
2366 if (isFloat)
2367 stack = vm->floatStack;
2368 else
2369 #endif /* FICL_WANT_FLOAT */
2370 stack = vm->dataStack;
2372 ficlStackPush(stack, vm->returnStack->frame[nLocal]);
2373 if (isDouble)
2374 ficlStackPush(stack, vm->returnStack->frame[nLocal+1]);
2375 } else {
2376 ficlInstruction instruction;
2377 ficlInteger appendLocalOffset;
2378 #if FICL_WANT_FLOAT
2379 if (isFloat) {
2380 instruction =
2381 (isDouble) ? ficlInstructionGetF2LocalParen :
2382 ficlInstructionGetFLocalParen;
2383 appendLocalOffset = FICL_TRUE;
2384 } else
2385 #endif /* FICL_WANT_FLOAT */
2386 if (nLocal == 0) {
2387 instruction = (isDouble) ? ficlInstructionGet2Local0 :
2388 ficlInstructionGetLocal0;
2389 appendLocalOffset = FICL_FALSE;
2390 } else if ((nLocal == 1) && !isDouble) {
2391 instruction = ficlInstructionGetLocal1;
2392 appendLocalOffset = FICL_FALSE;
2393 } else {
2394 instruction =
2395 (isDouble) ? ficlInstructionGet2LocalParen :
2396 ficlInstructionGetLocalParen;
2397 appendLocalOffset = FICL_TRUE;
2400 ficlDictionaryAppendUnsigned(dictionary, instruction);
2401 if (appendLocalOffset)
2402 ficlDictionaryAppendUnsigned(dictionary, nLocal);
2406 static void
2407 ficlPrimitiveDoLocalIm(ficlVm *vm)
2409 ficlLocalParenIm(vm, 0, 0);
2412 static void
2413 ficlPrimitiveDo2LocalIm(ficlVm *vm)
2415 ficlLocalParenIm(vm, 1, 0);
2418 #if FICL_WANT_FLOAT
2419 static void
2420 ficlPrimitiveDoFLocalIm(ficlVm *vm)
2422 ficlLocalParenIm(vm, 0, 1);
2425 static void
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.
2455 void
2456 ficlLocalParen(ficlVm *vm, int isDouble, int isFloat)
2458 ficlDictionary *dictionary;
2459 ficlString name;
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
2473 ficlPrimitive code;
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 */
2485 isFloat = 0;
2486 #else /* FICL_WANT_FLOAT */
2487 if (isFloat) {
2488 if (isDouble) {
2489 code = ficlPrimitiveDoF2LocalIm;
2490 instruction = ficlInstructionToF2LocalParen;
2491 } else {
2492 code = ficlPrimitiveDoFLocalIm;
2493 instruction = ficlInstructionToFLocalParen;
2495 } else
2496 #endif /* FICL_WANT_FLOAT */
2497 if (isDouble) {
2498 code = ficlPrimitiveDo2LocalIm;
2499 instruction = ficlInstructionTo2LocalParen;
2500 } else {
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
2513 * stack frame
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;
2536 static void
2537 ficlPrimitiveLocalParen(ficlVm *vm)
2539 ficlLocalParen(vm, 0, 0);
2542 static void
2543 ficlPrimitive2LocalParen(ficlVm *vm)
2545 ficlLocalParen(vm, 1, 0);
2547 #endif /* FICL_WANT_LOCALS */
2550 * t o V a l u e
2551 * CORE EXT
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
2557 static void
2558 ficlPrimitiveToValue(ficlVm *vm)
2560 ficlString name = ficlVmGetWord(vm);
2561 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2562 ficlWord *word;
2563 ficlInstruction instruction = 0;
2564 ficlStack *stack;
2565 ficlInteger isDouble;
2566 #if FICL_WANT_LOCALS
2567 ficlInteger nLocal;
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);
2579 if (!word)
2580 goto TO_GLOBAL;
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;
2590 #if FICL_WANT_FLOAT
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 */
2600 else {
2601 ficlVmThrowError(vm,
2602 "to %.*s : local is of unknown type",
2603 FICL_STRING_GET_LENGTH(name),
2604 FICL_STRING_GET_POINTER(name));
2605 return;
2608 nLocal = word->param[0].i;
2609 appendLocalOffset = FICL_TRUE;
2611 #if FICL_WANT_FLOAT
2612 if (!isFloat) {
2613 #endif /* FICL_WANT_FLOAT */
2614 if (nLocal == 0) {
2615 instruction =
2616 (isDouble) ? ficlInstructionTo2Local0 :
2617 ficlInstructionToLocal0;
2618 appendLocalOffset = FICL_FALSE;
2619 } else if ((nLocal == 1) && !isDouble) {
2620 instruction = ficlInstructionToLocal1;
2621 appendLocalOffset = FICL_FALSE;
2623 #if FICL_WANT_FLOAT
2625 #endif /* FICL_WANT_FLOAT */
2627 ficlDictionaryAppendUnsigned(dictionary, instruction);
2628 if (appendLocalOffset)
2629 ficlDictionaryAppendUnsigned(dictionary, nLocal);
2630 return;
2632 #endif
2634 #if FICL_WANT_LOCALS
2635 TO_GLOBAL:
2636 #endif /* FICL_WANT_LOCALS */
2637 word = ficlDictionaryLookup(dictionary, name);
2638 if (!word)
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;
2648 break;
2649 case ficlInstruction2ConstantParen:
2650 instruction = ficlInstruction2Store;
2651 stack = vm->dataStack;
2652 isDouble = FICL_TRUE;
2653 break;
2654 #if FICL_WANT_FLOAT
2655 case ficlInstructionFConstantParen:
2656 instruction = ficlInstructionFStore;
2657 stack = vm->floatStack;
2658 isDouble = FICL_FALSE;
2659 break;
2660 case ficlInstructionF2ConstantParen:
2661 instruction = ficlInstructionF2Store;
2662 stack = vm->floatStack;
2663 isDouble = FICL_TRUE;
2664 break;
2665 #endif /* FICL_WANT_FLOAT */
2666 default:
2667 ficlVmThrowError(vm,
2668 "to %.*s : value/constant is of unknown type",
2669 FICL_STRING_GET_LENGTH(name),
2670 FICL_STRING_GET_POINTER(name));
2671 return;
2674 if (vm->state == FICL_VM_STATE_INTERPRET) {
2675 word->param[0] = ficlStackPop(stack);
2676 if (isDouble)
2677 word->param[1] = ficlStackPop(stack);
2678 } else {
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.
2694 static void
2695 ficlPrimitiveFMSlashMod(ficlVm *vm)
2697 ficl2Integer d1;
2698 ficlInteger n1;
2699 ficl2IntegerQR qr;
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.
2719 static void
2720 ficlPrimitiveSMSlashRem(ficlVm *vm)
2722 ficl2Integer d1;
2723 ficlInteger n1;
2724 ficl2IntegerQR qr;
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));
2736 static void
2737 ficlPrimitiveMod(ficlVm *vm)
2739 ficl2Integer d1;
2740 ficlInteger n1;
2741 ficlInteger i;
2742 ficl2IntegerQR qr;
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.
2760 static void
2761 ficlPrimitiveUMSlashMod(ficlVm *vm)
2763 ficl2Unsigned ud;
2764 ficlUnsigned u1;
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));
2776 * m S t a r
2777 * m-star CORE ( n1 n2 -- d )
2778 * d is the signed product of n1 times n2.
2780 static void
2781 ficlPrimitiveMStar(ficlVm *vm)
2783 ficlInteger n2;
2784 ficlInteger n1;
2785 ficl2Integer d;
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);
2795 static void
2796 ficlPrimitiveUMStar(ficlVm *vm)
2798 ficlUnsigned u2;
2799 ficlUnsigned u1;
2800 ficl2Unsigned ud;
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);
2811 * 2 r o t
2812 * DOUBLE ( d1 d2 d3 -- d2 d3 d1 )
2814 static void
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);
2829 * p a d
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.
2834 static void
2835 ficlPrimitivePad(ficlVm *vm)
2837 ficlStackPushPointer(vm->dataStack, vm->pad);
2841 * s o u r c e - i d
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
2851 static void
2852 ficlPrimitiveSourceID(ficlVm *vm)
2854 ficlStackPushInteger(vm->dataStack, vm->sourceId.i);
2858 * r e f i l l
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.
2870 static void
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,
2885 * push zero.
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.
2900 static void
2901 ficlPrimitiveCatch(ficlVm *vm)
2903 int except;
2904 jmp_buf vmState;
2905 ficlVm vmCopy;
2906 ficlStack dataStackCopy;
2907 ficlStack returnStackCopy;
2908 ficlWord *word;
2910 FICL_VM_ASSERT(vm, vm);
2911 FICL_VM_ASSERT(vm, vm->callback.system->exitInnerWord);
2914 * Get xt.
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
2926 * changes.
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));
2941 * Give vm a jmp_buf
2943 vm->exceptionHandler = &vmState;
2946 * Safety net
2948 except = setjmp(vmState);
2950 switch (except) {
2952 * Setup condition - push poison pill so that the VM throws
2953 * VM_INNEREXIT if the XT terminates normally, then execute
2954 * the XT
2956 case 0:
2957 /* Open mouth, insert emetic */
2958 ficlVmPushIP(vm, &(vm->callback.system->exitInnerWord));
2959 ficlVmExecuteWord(vm, word);
2960 ficlVmInnerLoop(vm, 0);
2961 break;
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);
2973 break;
2976 * Some other exception got thrown - restore pre-existing VM state
2977 * and push the exception code
2979 default:
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 */
2988 break;
2993 * t h r o w
2994 * EXCEPTION
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
3003 static void
3004 ficlPrimitiveThrow(ficlVm *vm)
3006 int except;
3008 except = ficlStackPopInteger(vm->dataStack);
3010 if (except)
3011 ficlVmThrow(vm, except);
3015 * a l l o c a t e
3016 * MEMORY
3018 static void
3019 ficlPrimitiveAllocate(ficlVm *vm)
3021 size_t size;
3022 void *p;
3024 size = ficlStackPopInteger(vm->dataStack);
3025 p = ficlMalloc(size);
3026 ficlStackPushPointer(vm->dataStack, p);
3027 if (p != NULL)
3028 ficlStackPushInteger(vm->dataStack, 0);
3029 else
3030 ficlStackPushInteger(vm->dataStack, 1);
3034 * f r e e
3035 * MEMORY
3037 static void
3038 ficlPrimitiveFree(ficlVm *vm)
3040 void *p;
3042 p = ficlStackPopPointer(vm->dataStack);
3043 ficlFree(p);
3044 ficlStackPushInteger(vm->dataStack, 0);
3048 * r e s i z e
3049 * MEMORY
3051 static void
3052 ficlPrimitiveResize(ficlVm *vm)
3054 size_t size;
3055 void *new, *old;
3057 size = ficlStackPopInteger(vm->dataStack);
3058 old = ficlStackPopPointer(vm->dataStack);
3059 new = ficlRealloc(old, size);
3061 if (new) {
3062 ficlStackPushPointer(vm->dataStack, new);
3063 ficlStackPushInteger(vm->dataStack, 0);
3064 } else {
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
3074 static void
3075 ficlPrimitiveExitInner(ficlVm *vm)
3077 ficlVmThrow(vm, FICL_VM_STATUS_INNER_EXIT);
3080 #if 0
3081 static void
3082 ficlPrimitiveName(ficlVm *vm)
3084 FICL_IGNORE(vm);
3086 #endif
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.
3092 void
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"
3106 #undef FICL_TOKEN
3107 #undef FICL_INSTRUCTION_TOKEN
3110 * The Core word set
3111 * see softcore.c for definitions of: abs bl space spaces abort"
3113 ficlDictionarySetPrimitive(dictionary, "#", ficlPrimitiveNumberSign,
3114 FICL_WORD_DEFAULT);
3115 ficlDictionarySetPrimitive(dictionary, "#>",
3116 ficlPrimitiveNumberSignGreater, FICL_WORD_DEFAULT);
3117 ficlDictionarySetPrimitive(dictionary, "#s", ficlPrimitiveNumberSignS,
3118 FICL_WORD_DEFAULT);
3119 ficlDictionarySetPrimitive(dictionary, "\'", ficlPrimitiveTick,
3120 FICL_WORD_DEFAULT);
3121 ficlDictionarySetPrimitive(dictionary, "(", ficlPrimitiveParenthesis,
3122 FICL_WORD_IMMEDIATE);
3123 ficlDictionarySetPrimitive(dictionary, "+loop",
3124 ficlPrimitivePlusLoopCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3125 ficlDictionarySetPrimitive(dictionary, ".", ficlPrimitiveDot,
3126 FICL_WORD_DEFAULT);
3127 ficlDictionarySetPrimitive(dictionary, ".\"",
3128 ficlPrimitiveDotQuoteCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3129 ficlDictionarySetPrimitive(dictionary, ":", ficlPrimitiveColon,
3130 FICL_WORD_DEFAULT);
3131 ficlDictionarySetPrimitive(dictionary, ";", ficlPrimitiveSemicolonCoIm,
3132 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3133 ficlDictionarySetPrimitive(dictionary, "<#",
3134 ficlPrimitiveLessNumberSign, FICL_WORD_DEFAULT);
3135 ficlDictionarySetPrimitive(dictionary, ">body", ficlPrimitiveToBody,
3136 FICL_WORD_DEFAULT);
3137 ficlDictionarySetPrimitive(dictionary, ">in", ficlPrimitiveToIn,
3138 FICL_WORD_DEFAULT);
3139 ficlDictionarySetPrimitive(dictionary, ">number", ficlPrimitiveToNumber,
3140 FICL_WORD_DEFAULT);
3141 ficlDictionarySetPrimitive(dictionary, "abort", ficlPrimitiveAbort,
3142 FICL_WORD_DEFAULT);
3143 ficlDictionarySetPrimitive(dictionary, "accept", ficlPrimitiveAccept,
3144 FICL_WORD_DEFAULT);
3145 ficlDictionarySetPrimitive(dictionary, "align", ficlPrimitiveAlign,
3146 FICL_WORD_DEFAULT);
3147 ficlDictionarySetPrimitive(dictionary, "aligned", ficlPrimitiveAligned,
3148 FICL_WORD_DEFAULT);
3149 ficlDictionarySetPrimitive(dictionary, "allot", ficlPrimitiveAllot,
3150 FICL_WORD_DEFAULT);
3151 ficlDictionarySetPrimitive(dictionary, "base", ficlPrimitiveBase,
3152 FICL_WORD_DEFAULT);
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,
3158 FICL_WORD_DEFAULT);
3159 ficlDictionarySetPrimitive(dictionary, "char+", ficlPrimitiveCharPlus,
3160 FICL_WORD_DEFAULT);
3161 ficlDictionarySetPrimitive(dictionary, "chars", ficlPrimitiveChars,
3162 FICL_WORD_DEFAULT);
3163 ficlDictionarySetPrimitive(dictionary, "constant",
3164 ficlPrimitiveConstant, FICL_WORD_DEFAULT);
3165 ficlDictionarySetPrimitive(dictionary, "count", ficlPrimitiveCount,
3166 FICL_WORD_DEFAULT);
3167 ficlDictionarySetPrimitive(dictionary, "cr", ficlPrimitiveCR,
3168 FICL_WORD_DEFAULT);
3169 ficlDictionarySetPrimitive(dictionary, "create", ficlPrimitiveCreate,
3170 FICL_WORD_DEFAULT);
3171 ficlDictionarySetPrimitive(dictionary, "decimal", ficlPrimitiveDecimal,
3172 FICL_WORD_DEFAULT);
3173 ficlDictionarySetPrimitive(dictionary, "depth", ficlPrimitiveDepth,
3174 FICL_WORD_DEFAULT);
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,
3182 FICL_WORD_DEFAULT);
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,
3192 FICL_WORD_DEFAULT);
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,
3198 FICL_WORD_DEFAULT);
3199 ficlDictionarySetPrimitive(dictionary, "fm/mod",
3200 ficlPrimitiveFMSlashMod, FICL_WORD_DEFAULT);
3201 ficlDictionarySetPrimitive(dictionary, "here", ficlPrimitiveHere,
3202 FICL_WORD_DEFAULT);
3203 ficlDictionarySetPrimitive(dictionary, "hold", ficlPrimitiveHold,
3204 FICL_WORD_DEFAULT);
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,
3214 FICL_WORD_DEFAULT);
3215 ficlDictionarySetPrimitive(dictionary, "mod", ficlPrimitiveMod,
3216 FICL_WORD_DEFAULT);
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,
3222 FICL_WORD_DEFAULT);
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,
3230 FICL_WORD_DEFAULT);
3231 ficlDictionarySetPrimitive(dictionary, "sm/rem",
3232 ficlPrimitiveSMSlashRem, FICL_WORD_DEFAULT);
3233 ficlDictionarySetPrimitive(dictionary, "source", ficlPrimitiveSource,
3234 FICL_WORD_DEFAULT);
3235 ficlDictionarySetPrimitive(dictionary, "state", ficlPrimitiveState,
3236 FICL_WORD_DEFAULT);
3237 ficlDictionarySetPrimitive(dictionary, "then", ficlPrimitiveEndifCoIm,
3238 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3239 ficlDictionarySetPrimitive(dictionary, "type", ficlPrimitiveType,
3240 FICL_WORD_DEFAULT);
3241 ficlDictionarySetPrimitive(dictionary, "u.", ficlPrimitiveUDot,
3242 FICL_WORD_DEFAULT);
3243 ficlDictionarySetPrimitive(dictionary, "um*", ficlPrimitiveUMStar,
3244 FICL_WORD_DEFAULT);
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,
3254 FICL_WORD_DEFAULT);
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,
3262 FICL_WORD_DEFAULT);
3264 * The Core Extensions word set...
3265 * see softcore.fr for other definitions
3267 /* "#tib" */
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,
3280 FICL_WORD_DEFAULT);
3281 ficlDictionarySetPrimitive(dictionary, "pad", ficlPrimitivePad,
3282 FICL_WORD_DEFAULT);
3283 ficlDictionarySetPrimitive(dictionary, "parse", ficlPrimitiveParse,
3284 FICL_WORD_DEFAULT);
3287 * query restore-input save-input tib u.r u> unused
3288 * [FICL_VM_STATE_COMPILE]
3290 ficlDictionarySetPrimitive(dictionary, "refill", ficlPrimitiveRefill,
3291 FICL_WORD_DEFAULT);
3292 ficlDictionarySetPrimitive(dictionary, "source-id",
3293 ficlPrimitiveSourceID, FICL_WORD_DEFAULT);
3294 ficlDictionarySetPrimitive(dictionary, "to", ficlPrimitiveToValue,
3295 FICL_WORD_IMMEDIATE);
3296 ficlDictionarySetPrimitive(dictionary, "value", ficlPrimitiveConstant,
3297 FICL_WORD_DEFAULT);
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);
3317 ficl2Integer id;
3318 ficlInteger low, high;
3320 low = ULONG_MAX;
3321 high = LONG_MAX;
3322 FICL_2INTEGER_SET(high, low, id);
3323 ficlDictionarySet2Constant(environment, "max-d", id);
3324 high = ULONG_MAX;
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
3347 * M+ in softcore
3351 * DOUBLE EXT
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,
3362 FICL_WORD_DEFAULT);
3363 ficlDictionarySetPrimitive(dictionary, "throw", ficlPrimitiveThrow,
3364 FICL_WORD_DEFAULT);
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);
3384 #endif
3387 * The optional Memory-Allocation word set
3390 ficlDictionarySetPrimitive(dictionary, "allocate",
3391 ficlPrimitiveAllocate, FICL_WORD_DEFAULT);
3392 ficlDictionarySetPrimitive(dictionary, "free", ficlPrimitiveFree,
3393 FICL_WORD_DEFAULT);
3394 ficlDictionarySetPrimitive(dictionary, "resize", ficlPrimitiveResize,
3395 FICL_WORD_DEFAULT);
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
3413 #if FICL_WANT_FILE
3414 ficlSystemCompileFile(system);
3415 #endif
3418 * Ficl extras
3420 ficlDictionarySetPrimitive(dictionary, ".ver", ficlPrimitiveVersion,
3421 FICL_WORD_DEFAULT);
3422 ficlDictionarySetPrimitive(dictionary, ">name", ficlPrimitiveToName,
3423 FICL_WORD_DEFAULT);
3424 ficlDictionarySetPrimitive(dictionary, "add-parse-step",
3425 ficlPrimitiveAddParseStep, FICL_WORD_DEFAULT);
3426 ficlDictionarySetPrimitive(dictionary, "body>", ficlPrimitiveFromBody,
3427 FICL_WORD_DEFAULT);
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,
3435 FICL_WORD_DEFAULT);
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,
3443 FICL_WORD_DEFAULT);
3444 ficlDictionarySetPrimitive(dictionary, "sliteral",
3445 ficlPrimitiveSLiteralCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3446 ficlDictionarySetPrimitive(dictionary, "sprintf", ficlPrimitiveSprintf,
3447 FICL_WORD_DEFAULT);
3448 ficlDictionarySetPrimitive(dictionary, "strlen", ficlPrimitiveStrlen,
3449 FICL_WORD_DEFAULT);
3450 ficlDictionarySetPrimitive(dictionary, "x.", ficlPrimitiveHexDot,
3451 FICL_WORD_DEFAULT);
3452 #if FICL_WANT_USER
3453 ficlDictionarySetPrimitive(dictionary, "user", ficlPrimitiveUser,
3454 FICL_WORD_DEFAULT);
3455 #endif
3458 * internal support words
3460 interpret = ficlDictionarySetPrimitive(dictionary, "interpret",
3461 ficlPrimitiveInterpret, FICL_WORD_DEFAULT);
3462 ficlDictionarySetPrimitive(dictionary, "lookup", ficlPrimitiveLookup,
3463 FICL_WORD_DEFAULT);
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);
3476 #if 0
3477 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \
3478 ficlDictionarySetConstant(dictionary, #token, token);
3479 #else
3480 #define FICL_INSTRUCTION_TOKEN(token, description, flags)
3481 #endif /* 0 */
3482 #include "ficltokens.h"
3483 #undef FICL_TOKEN
3484 #undef FICL_INSTRUCTION_TOKEN
3487 * Set up system's outer interpreter loop - maybe this should
3488 * be in initSystem?
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);