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.
12 *
13 * Get the latest Ficl release at http://ficl.sourceforge.net
14 *
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.
19 *
20 * L I C E N S E and D I S C L A I M E R
21 *
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.
30 *
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.
42 */
43
44 #include "ficl.h"
45 #include <limits.h>
46
47 /*
48 * Control structure building words use these
49 * strings' addresses as markers on the stack to
50 * check for structure completion.
51 */
52 static char doTag[] = "do";
53 static char colonTag[] = "colon";
54 static char leaveTag[] = "leave";
55
56 static char destTag[] = "target";
57 static char origTag[] = "origin";
58
59 static char caseTag[] = "case";
60 static char ofTag[] = "of";
61 static char fallthroughTag[] = "fallthrough";
62
63 /*
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
65 *
66 * Push current dictionary location for later branch resolution.
67 * The location may be either a branch target or a patch address...
68 */
69 static void
markBranch(ficlDictionary * dictionary,ficlVm * vm,char * tag)70 markBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag)
71 {
72 ficlStackPushPointer(vm->dataStack, dictionary->here);
73 ficlStackPushPointer(vm->dataStack, tag);
74 }
75
76 static void
markControlTag(ficlVm * vm,char * tag)77 markControlTag(ficlVm *vm, char *tag)
78 {
79 ficlStackPushPointer(vm->dataStack, tag);
80 }
81
82 static void
matchControlTag(ficlVm * vm,char * wantTag)83 matchControlTag(ficlVm *vm, char *wantTag)
84 {
85 char *tag;
86
87 FICL_STACK_CHECK(vm->dataStack, 1, 0);
88
89 tag = (char *)ficlStackPopPointer(vm->dataStack);
90
91 /*
92 * Changed the code below to compare the pointers first
93 * (by popular demand)
94 */
95 if ((tag != wantTag) && strcmp(tag, wantTag)) {
96 ficlVmThrowError(vm,
97 "Error -- unmatched control structure \"%s\"", wantTag);
98 }
99 }
100
101 /*
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
105 */
106 static void
resolveBackBranch(ficlDictionary * dictionary,ficlVm * vm,char * tag)107 resolveBackBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag)
108 {
109 ficlCell *patchAddr, c;
110
111 matchControlTag(vm, tag);
112
113 FICL_STACK_CHECK(vm->dataStack, 1, 0);
114
115 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
116 c.i = patchAddr - dictionary->here;
117
118 ficlDictionaryAppendCell(dictionary, c);
119 }
120
121 /*
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
125 */
126 static void
resolveForwardBranch(ficlDictionary * dictionary,ficlVm * vm,char * tag)127 resolveForwardBranch(ficlDictionary *dictionary, ficlVm *vm, char *tag)
128 {
129 ficlInteger offset;
130 ficlCell *patchAddr;
131
132 matchControlTag(vm, tag);
133
134 FICL_STACK_CHECK(vm->dataStack, 1, 0);
135
136 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
137 offset = dictionary->here - patchAddr;
138 (*patchAddr).i = offset;
139 }
140
141 /*
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.
145 */
146 static void
resolveAbsBranch(ficlDictionary * dictionary,ficlVm * vm,char * wantTag)147 resolveAbsBranch(ficlDictionary *dictionary, ficlVm *vm, char *wantTag)
148 {
149 ficlCell *patchAddr;
150 char *tag;
151
152 FICL_STACK_CHECK(vm->dataStack, 2, 0);
153
154 tag = ficlStackPopPointer(vm->dataStack);
155
156 /*
157 * Changed the comparison below to compare the pointers first
158 * (by popular demand)
159 */
160 if ((tag != wantTag) && strcmp(tag, wantTag)) {
161 ficlVmTextOut(vm, "Warning -- Unmatched control word: ");
162 ficlVmTextOut(vm, wantTag);
163 ficlVmTextOut(vm, "\n");
164 }
165
166 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
167 (*patchAddr).p = dictionary->here;
168 }
169
170 /*
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.
176 */
177 static void
ficlPrimitiveColon(ficlVm * vm)178 ficlPrimitiveColon(ficlVm *vm)
179 {
180 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
181 ficlString name = ficlVmGetWord(vm);
182
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);
188
189 #if FICL_WANT_LOCALS
190 vm->callback.system->localsCount = 0;
191 #endif
192 }
193
194 static void
ficlPrimitiveSemicolonCoIm(ficlVm * vm)195 ficlPrimitiveSemicolonCoIm(ficlVm *vm)
196 {
197 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
198
199 matchControlTag(vm, colonTag);
200
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);
208 }
209 vm->callback.system->localsCount = 0;
210 #endif
211
212 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionSemiParen);
213 vm->state = FICL_VM_STATE_INTERPRET;
214 ficlDictionaryUnsmudge(dictionary);
215 }
216
217 /*
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".
225 */
226 static void
ficlPrimitiveExitCoIm(ficlVm * vm)227 ficlPrimitiveExitCoIm(ficlVm *vm)
228 {
229 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
230 FICL_IGNORE(vm);
231
232 #if FICL_WANT_LOCALS
233 if (vm->callback.system->localsCount > 0) {
234 ficlDictionaryAppendUnsigned(dictionary,
235 ficlInstructionUnlinkParen);
236 }
237 #endif
238 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionExitParen);
239 }
240
241 /*
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.
246 */
247 static void
ficlPrimitiveConstant(ficlVm * vm)248 ficlPrimitiveConstant(ficlVm *vm)
249 {
250 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
251 ficlString name = ficlVmGetWord(vm);
252
253 FICL_STACK_CHECK(vm->dataStack, 1, 0);
254
255 ficlDictionaryAppendConstantInstruction(dictionary, name,
256 ficlInstructionConstantParen, ficlStackPopInteger(vm->dataStack));
257 }
258
259 static void
ficlPrimitive2Constant(ficlVm * vm)260 ficlPrimitive2Constant(ficlVm *vm)
261 {
262 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
263 ficlString name = ficlVmGetWord(vm);
264
265 FICL_STACK_CHECK(vm->dataStack, 2, 0);
266
267 ficlDictionaryAppend2ConstantInstruction(dictionary, name,
268 ficlInstruction2ConstantParen, ficlStackPop2Integer(vm->dataStack));
269 }
270
271 /*
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
275 */
276 static void
ficlPrimitiveDot(ficlVm * vm)277 ficlPrimitiveDot(ficlVm *vm)
278 {
279 ficlCell c;
280
281 FICL_STACK_CHECK(vm->dataStack, 1, 0);
282
283 c = ficlStackPop(vm->dataStack);
284 ficlLtoa((c).i, vm->pad, vm->base);
285 strcat(vm->pad, " ");
286 ficlVmTextOut(vm, vm->pad);
287 }
288
289 static void
ficlPrimitiveUDot(ficlVm * vm)290 ficlPrimitiveUDot(ficlVm *vm)
291 {
292 ficlUnsigned u;
293
294 FICL_STACK_CHECK(vm->dataStack, 1, 0);
295
296 u = ficlStackPopUnsigned(vm->dataStack);
297 ficlUltoa(u, vm->pad, vm->base);
298 strcat(vm->pad, " ");
299 ficlVmTextOut(vm, vm->pad);
300 }
301
302 static void
ficlPrimitiveHexDot(ficlVm * vm)303 ficlPrimitiveHexDot(ficlVm *vm)
304 {
305 ficlUnsigned u;
306
307 FICL_STACK_CHECK(vm->dataStack, 1, 0);
308
309 u = ficlStackPopUnsigned(vm->dataStack);
310 ficlUltoa(u, vm->pad, 16);
311 strcat(vm->pad, " ");
312 ficlVmTextOut(vm, vm->pad);
313 }
314
315 /*
316 * s t r l e n
317 * Ficl ( c-string -- length )
318 *
319 * Returns the length of a C-style (zero-terminated) string.
320 *
321 * --lch
322 */
323 static void
ficlPrimitiveStrlen(ficlVm * vm)324 ficlPrimitiveStrlen(ficlVm *vm)
325 {
326 char *address = (char *)ficlStackPopPointer(vm->dataStack);
327 ficlStackPushInteger(vm->dataStack, strlen(address));
328 }
329
330 /*
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).
349 *
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).
353 *
354 * --lch
355 */
356 static void
ficlPrimitiveSprintf(ficlVm * vm)357 ficlPrimitiveSprintf(ficlVm *vm)
358 {
359 int bufferLength = ficlStackPopInteger(vm->dataStack);
360 char *buffer = (char *)ficlStackPopPointer(vm->dataStack);
361 char *bufferStart = buffer;
362
363 int formatLength = ficlStackPopInteger(vm->dataStack);
364 char *format = (char *)ficlStackPopPointer(vm->dataStack);
365 char *formatStop = format + formatLength;
366
367 int base = 10;
368 int unsignedInteger = 0; /* false */
369
370 int append = 1; /* true */
371
372 while (format < formatStop) {
373 char scratch[64];
374 char *source;
375 int actualLength;
376 int desiredLength;
377 int leadingZeroes;
378
379 if (*format != '%') {
380 source = format;
381 actualLength = desiredLength = 1;
382 leadingZeroes = 0;
383 } else {
384 format++;
385 if (format == formatStop)
386 break;
387
388 leadingZeroes = (*format == '0');
389 if (leadingZeroes) {
390 format++;
391 if (format == formatStop)
392 break;
393 }
394
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);
403
404 format++;
405 if (format == formatStop)
406 break;
407 }
408
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 /* FALLTHROUGH */
421 case 'u':
422 case 'U':
423 unsignedInteger = 1; /* true */
424 /* FALLTHROUGH */
425 case 'd':
426 case 'D': {
427 int integer;
428 integer = ficlStackPopInteger(vm->dataStack);
429 if (unsignedInteger)
430 ficlUltoa(integer, scratch, base);
431 else
432 ficlLtoa(integer, scratch, base);
433 base = 10;
434 unsignedInteger = 0; /* false */
435 source = scratch;
436 actualLength = strlen(scratch);
437 break;
438 }
439 case '%':
440 source = format;
441 actualLength = 1;
442 /* FALLTHROUGH */
443 default:
444 continue;
445 }
446 }
447
448 if (append) {
449 if (!desiredLength)
450 desiredLength = actualLength;
451 if (desiredLength > bufferLength) {
452 append = 0; /* false */
453 desiredLength = bufferLength;
454 }
455 while (desiredLength > actualLength) {
456 *buffer++ = (char)((leadingZeroes) ? '0' : ' ');
457 bufferLength--;
458 desiredLength--;
459 }
460 memcpy(buffer, source, actualLength);
461 buffer += actualLength;
462 bufferLength -= actualLength;
463 }
464
465 format++;
466 }
467
468 ficlStackPushPointer(vm->dataStack, bufferStart);
469 ficlStackPushInteger(vm->dataStack, buffer - bufferStart);
470 ficlStackPushInteger(vm->dataStack, FICL_BOOL(!append));
471 }
472
473 /*
474 * d u p & f r i e n d s
475 */
476 static void
ficlPrimitiveDepth(ficlVm * vm)477 ficlPrimitiveDepth(ficlVm *vm)
478 {
479 int i;
480
481 FICL_STACK_CHECK(vm->dataStack, 0, 1);
482
483 i = ficlStackDepth(vm->dataStack);
484 ficlStackPushInteger(vm->dataStack, i);
485 }
486
487 /*
488 * e m i t & f r i e n d s
489 */
490 static void
ficlPrimitiveEmit(ficlVm * vm)491 ficlPrimitiveEmit(ficlVm *vm)
492 {
493 char buffer[2];
494 int i;
495
496 FICL_STACK_CHECK(vm->dataStack, 1, 0);
497
498 i = ficlStackPopInteger(vm->dataStack);
499 buffer[0] = (char)i;
500 buffer[1] = '\0';
501 ficlVmTextOut(vm, buffer);
502 }
503
504 static void
ficlPrimitiveCR(ficlVm * vm)505 ficlPrimitiveCR(ficlVm *vm)
506 {
507 ficlVmTextOut(vm, "\n");
508 }
509
510 static void
ficlPrimitiveBackslash(ficlVm * vm)511 ficlPrimitiveBackslash(ficlVm *vm)
512 {
513 char *trace = ficlVmGetInBuf(vm);
514 char *stop = ficlVmGetInBufEnd(vm);
515 char c = *trace;
516
517 while ((trace != stop) && (c != '\r') && (c != '\n')) {
518 c = *++trace;
519 }
520
521 /*
522 * Cope with DOS or UNIX-style EOLs -
523 * Check for /r, /n, /r/n, or /n/r end-of-line sequences,
524 * and point trace to next char. If EOL is \0, we're done.
525 */
526 if (trace != stop) {
527 trace++;
528
529 if ((trace != stop) && (c != *trace) &&
530 ((*trace == '\r') || (*trace == '\n')))
531 trace++;
532 }
533
534 ficlVmUpdateTib(vm, trace);
535 }
536
537 /*
538 * paren CORE
539 * Compilation: Perform the execution semantics given below.
540 * Execution: ( "ccc<paren>" -- )
541 * Parse ccc delimited by ) (right parenthesis). ( is an immediate word.
542 * The number of characters in ccc may be zero to the number of characters
543 * in the parse area.
544 */
545 static void
ficlPrimitiveParenthesis(ficlVm * vm)546 ficlPrimitiveParenthesis(ficlVm *vm)
547 {
548 ficlVmParseStringEx(vm, ')', 0);
549 }
550
551 /*
552 * F E T C H & S T O R E
553 */
554
555 /*
556 * i f C o I m
557 * IMMEDIATE
558 * Compiles code for a conditional branch into the dictionary
559 * and pushes the branch patch address on the stack for later
560 * patching by ELSE or THEN/ENDIF.
561 */
562 static void
ficlPrimitiveIfCoIm(ficlVm * vm)563 ficlPrimitiveIfCoIm(ficlVm *vm)
564 {
565 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
566
567 ficlDictionaryAppendUnsigned(dictionary,
568 ficlInstructionBranch0ParenWithCheck);
569 markBranch(dictionary, vm, origTag);
570 ficlDictionaryAppendUnsigned(dictionary, 1);
571 }
572
573 /*
574 * e l s e C o I m
575 *
576 * IMMEDIATE -- compiles an "else"...
577 * 1) FICL_VM_STATE_COMPILE a branch and a patch address;
578 * the address gets patched
579 * by "endif" to point past the "else" code.
580 * 2) Pop the the "if" patch address
581 * 3) Patch the "if" branch to point to the current FICL_VM_STATE_COMPILE
582 * address.
583 * 4) Push the "else" patch address. ("endif" patches this to jump past
584 * the "else" code.
585 */
586 static void
ficlPrimitiveElseCoIm(ficlVm * vm)587 ficlPrimitiveElseCoIm(ficlVm *vm)
588 {
589 ficlCell *patchAddr;
590 ficlInteger offset;
591 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
592
593 /* (1) FICL_VM_STATE_COMPILE branch runtime */
594 ficlDictionaryAppendUnsigned(dictionary,
595 ficlInstructionBranchParenWithCheck);
596
597 matchControlTag(vm, origTag);
598 /* (2) pop "if" patch addr */
599 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
600 markBranch(dictionary, vm, origTag); /* (4) push "else" patch addr */
601
602 /* (1) FICL_VM_STATE_COMPILE patch placeholder */
603 ficlDictionaryAppendUnsigned(dictionary, 1);
604 offset = dictionary->here - patchAddr;
605 (*patchAddr).i = offset; /* (3) Patch "if" */
606 }
607
608 /*
609 * e n d i f C o I m
610 */
611 static void
ficlPrimitiveEndifCoIm(ficlVm * vm)612 ficlPrimitiveEndifCoIm(ficlVm *vm)
613 {
614 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
615 resolveForwardBranch(dictionary, vm, origTag);
616 }
617
618 /*
619 * c a s e C o I m
620 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
621 *
622 *
623 * At FICL_VM_STATE_COMPILE-time, a CASE-SYS (see DPANS94 6.2.0873) looks
624 * like this:
625 * i*addr i caseTag
626 * and an OF-SYS (see DPANS94 6.2.1950) looks like this:
627 * i*addr i caseTag addr ofTag
628 * The integer under caseTag is the count of fixup addresses that branch
629 * to ENDCASE.
630 */
631 static void
ficlPrimitiveCaseCoIm(ficlVm * vm)632 ficlPrimitiveCaseCoIm(ficlVm *vm)
633 {
634 FICL_STACK_CHECK(vm->dataStack, 0, 2);
635
636 ficlStackPushUnsigned(vm->dataStack, 0);
637 markControlTag(vm, caseTag);
638 }
639
640 /*
641 * e n d c a s eC o I m
642 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
643 */
644 static void
ficlPrimitiveEndcaseCoIm(ficlVm * vm)645 ficlPrimitiveEndcaseCoIm(ficlVm *vm)
646 {
647 ficlUnsigned fixupCount;
648 ficlDictionary *dictionary;
649 ficlCell *patchAddr;
650 ficlInteger offset;
651
652 /*
653 * if the last OF ended with FALLTHROUGH,
654 * just add the FALLTHROUGH fixup to the
655 * ENDOF fixups
656 */
657 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) {
658 matchControlTag(vm, fallthroughTag);
659 patchAddr = ficlStackPopPointer(vm->dataStack);
660 matchControlTag(vm, caseTag);
661 fixupCount = ficlStackPopUnsigned(vm->dataStack);
662 ficlStackPushPointer(vm->dataStack, patchAddr);
663 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1);
664 markControlTag(vm, caseTag);
665 }
666
667 matchControlTag(vm, caseTag);
668
669 FICL_STACK_CHECK(vm->dataStack, 1, 0);
670
671 fixupCount = ficlStackPopUnsigned(vm->dataStack);
672 FICL_STACK_CHECK(vm->dataStack, fixupCount, 0);
673
674 dictionary = ficlVmGetDictionary(vm);
675
676 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDrop);
677
678 while (fixupCount--) {
679 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
680 offset = dictionary->here - patchAddr;
681 (*patchAddr).i = offset;
682 }
683 }
684
685 /*
686 * o f C o I m
687 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
688 */
689 static void
ficlPrimitiveOfCoIm(ficlVm * vm)690 ficlPrimitiveOfCoIm(ficlVm *vm)
691 {
692 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
693 ficlCell *fallthroughFixup = NULL;
694
695 FICL_STACK_CHECK(vm->dataStack, 1, 3);
696
697 if (ficlStackGetTop(vm->dataStack).p == fallthroughTag) {
698 matchControlTag(vm, fallthroughTag);
699 fallthroughFixup = ficlStackPopPointer(vm->dataStack);
700 }
701
702 matchControlTag(vm, caseTag);
703
704 markControlTag(vm, caseTag);
705
706 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionOfParen);
707 markBranch(dictionary, vm, ofTag);
708 ficlDictionaryAppendUnsigned(dictionary, 2);
709
710 if (fallthroughFixup != NULL) {
711 ficlInteger offset = dictionary->here - fallthroughFixup;
712 (*fallthroughFixup).i = offset;
713 }
714 }
715
716 /*
717 * e n d o f C o I m
718 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
719 */
720 static void
ficlPrimitiveEndofCoIm(ficlVm * vm)721 ficlPrimitiveEndofCoIm(ficlVm *vm)
722 {
723 ficlCell *patchAddr;
724 ficlUnsigned fixupCount;
725 ficlInteger offset;
726 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
727
728 FICL_STACK_CHECK(vm->dataStack, 4, 3);
729
730 /* ensure we're in an OF, */
731 matchControlTag(vm, ofTag);
732
733 /* grab the address of the branch location after the OF */
734 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
735 /* ensure we're also in a "case" */
736 matchControlTag(vm, caseTag);
737 /* grab the current number of ENDOF fixups */
738 fixupCount = ficlStackPopUnsigned(vm->dataStack);
739
740 /* FICL_VM_STATE_COMPILE branch runtime */
741 ficlDictionaryAppendUnsigned(dictionary,
742 ficlInstructionBranchParenWithCheck);
743
744 /*
745 * push a new ENDOF fixup, the updated count of ENDOF fixups,
746 * and the caseTag
747 */
748 ficlStackPushPointer(vm->dataStack, dictionary->here);
749 ficlStackPushUnsigned(vm->dataStack, fixupCount + 1);
750 markControlTag(vm, caseTag);
751
752 /* reserve space for the ENDOF fixup */
753 ficlDictionaryAppendUnsigned(dictionary, 2);
754
755 /* and patch the original OF */
756 offset = dictionary->here - patchAddr;
757 (*patchAddr).i = offset;
758 }
759
760 /*
761 * f a l l t h r o u g h C o I m
762 * IMMEDIATE FICL_VM_STATE_COMPILE-ONLY
763 */
764 static void
ficlPrimitiveFallthroughCoIm(ficlVm * vm)765 ficlPrimitiveFallthroughCoIm(ficlVm *vm)
766 {
767 ficlCell *patchAddr;
768 ficlInteger offset;
769 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
770
771 FICL_STACK_CHECK(vm->dataStack, 4, 3);
772
773 /* ensure we're in an OF, */
774 matchControlTag(vm, ofTag);
775 /* grab the address of the branch location after the OF */
776 patchAddr = (ficlCell *)ficlStackPopPointer(vm->dataStack);
777 /* ensure we're also in a "case" */
778 matchControlTag(vm, caseTag);
779
780 /* okay, here we go. put the case tag back. */
781 markControlTag(vm, caseTag);
782
783 /* FICL_VM_STATE_COMPILE branch runtime */
784 ficlDictionaryAppendUnsigned(dictionary,
785 ficlInstructionBranchParenWithCheck);
786
787 /* push a new FALLTHROUGH fixup and the fallthroughTag */
788 ficlStackPushPointer(vm->dataStack, dictionary->here);
789 markControlTag(vm, fallthroughTag);
790
791 /* reserve space for the FALLTHROUGH fixup */
792 ficlDictionaryAppendUnsigned(dictionary, 2);
793
794 /* and patch the original OF */
795 offset = dictionary->here - patchAddr;
796 (*patchAddr).i = offset;
797 }
798
799 /*
800 * h a s h
801 * hash ( c-addr u -- code)
802 * calculates hashcode of specified string and leaves it on the stack
803 */
804 static void
ficlPrimitiveHash(ficlVm * vm)805 ficlPrimitiveHash(ficlVm *vm)
806 {
807 ficlString s;
808
809 FICL_STRING_SET_LENGTH(s, ficlStackPopUnsigned(vm->dataStack));
810 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack));
811 ficlStackPushUnsigned(vm->dataStack, ficlHashCode(s));
812 }
813
814 /*
815 * i n t e r p r e t
816 * This is the "user interface" of a Forth. It does the following:
817 * while there are words in the VM's Text Input Buffer
818 * Copy next word into the pad (ficlVmGetWord)
819 * Attempt to find the word in the dictionary (ficlDictionaryLookup)
820 * If successful, execute the word.
821 * Otherwise, attempt to convert the word to a number (isNumber)
822 * If successful, push the number onto the parameter stack.
823 * Otherwise, print an error message and exit loop...
824 * End Loop
825 *
826 * From the standard, section 3.4
827 * Text interpretation (see 6.1.1360 EVALUATE and 6.1.2050 QUIT) shall
828 * repeat the following steps until either the parse area is empty or an
829 * ambiguous condition exists:
830 * a) Skip leading spaces and parse a name (see 3.4.1);
831 */
832 static void
ficlPrimitiveInterpret(ficlVm * vm)833 ficlPrimitiveInterpret(ficlVm *vm)
834 {
835 ficlString s;
836 int i;
837 ficlSystem *system;
838
839 FICL_VM_ASSERT(vm, vm);
840
841 system = vm->callback.system;
842 s = ficlVmGetWord0(vm);
843
844 /*
845 * Get next word...if out of text, we're done.
846 */
847 if (s.length == 0) {
848 ficlVmThrow(vm, FICL_VM_STATUS_OUT_OF_TEXT);
849 }
850
851 /*
852 * Run the parse chain against the incoming token until somebody
853 * eats it. Otherwise emit an error message and give up.
854 */
855 for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) {
856 ficlWord *word = system->parseList[i];
857
858 if (word == NULL)
859 break;
860
861 if (word->code == ficlPrimitiveParseStepParen) {
862 ficlParseStep pStep;
863 pStep = (ficlParseStep)(word->param->fn);
864 if ((*pStep)(vm, s))
865 return;
866 } else {
867 ficlStackPushPointer(vm->dataStack,
868 FICL_STRING_GET_POINTER(s));
869 ficlStackPushUnsigned(vm->dataStack,
870 FICL_STRING_GET_LENGTH(s));
871 ficlVmExecuteXT(vm, word);
872 if (ficlStackPopInteger(vm->dataStack))
873 return;
874 }
875 }
876
877 ficlVmThrowError(vm, "%.*s not found", FICL_STRING_GET_LENGTH(s),
878 FICL_STRING_GET_POINTER(s));
879 /* back to inner interpreter */
880 }
881
882 /*
883 * Surrogate precompiled parse step for ficlParseWord
884 * (this step is hard coded in FICL_VM_STATE_INTERPRET)
885 */
886 static void
ficlPrimitiveLookup(ficlVm * vm)887 ficlPrimitiveLookup(ficlVm *vm)
888 {
889 ficlString name;
890 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack));
891 FICL_STRING_SET_POINTER(name, ficlStackPopPointer(vm->dataStack));
892 ficlStackPushInteger(vm->dataStack, ficlVmParseWord(vm, name));
893 }
894
895 /*
896 * p a r e n P a r s e S t e p
897 * (parse-step) ( c-addr u -- flag )
898 * runtime for a precompiled parse step - pop a counted string off the
899 * stack, run the parse step against it, and push the result flag (FICL_TRUE
900 * if success, FICL_FALSE otherwise).
901 */
902 void
ficlPrimitiveParseStepParen(ficlVm * vm)903 ficlPrimitiveParseStepParen(ficlVm *vm)
904 {
905 ficlString s;
906 ficlWord *word = vm->runningWord;
907 ficlParseStep pStep = (ficlParseStep)(word->param->fn);
908
909 FICL_STRING_SET_LENGTH(s, ficlStackPopInteger(vm->dataStack));
910 FICL_STRING_SET_POINTER(s, ficlStackPopPointer(vm->dataStack));
911
912 ficlStackPushInteger(vm->dataStack, (*pStep)(vm, s));
913 }
914
915 static void
ficlPrimitiveAddParseStep(ficlVm * vm)916 ficlPrimitiveAddParseStep(ficlVm *vm)
917 {
918 ficlWord *pStep;
919 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
920
921 FICL_STACK_CHECK(vm->dataStack, 1, 0);
922
923 pStep = (ficlWord *)(ficlStackPop(vm->dataStack).p);
924 if ((pStep != NULL) && ficlDictionaryIsAWord(dictionary, pStep))
925 ficlSystemAddParseStep(vm->callback.system, pStep);
926 }
927
928 /*
929 * l i t e r a l I m
930 *
931 * IMMEDIATE code for "literal". This function gets a value from the stack
932 * and compiles it into the dictionary preceded by the code for "(literal)".
933 * IMMEDIATE
934 */
935 void
ficlPrimitiveLiteralIm(ficlVm * vm)936 ficlPrimitiveLiteralIm(ficlVm *vm)
937 {
938 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
939 ficlInteger value;
940
941 value = ficlStackPopInteger(vm->dataStack);
942
943 switch (value) {
944 case 1:
945 case 2:
946 case 3:
947 case 4:
948 case 5:
949 case 6:
950 case 7:
951 case 8:
952 case 9:
953 case 10:
954 case 11:
955 case 12:
956 case 13:
957 case 14:
958 case 15:
959 case 16:
960 ficlDictionaryAppendUnsigned(dictionary, value);
961 break;
962
963 case 0:
964 case -1:
965 case -2:
966 case -3:
967 case -4:
968 case -5:
969 case -6:
970 case -7:
971 case -8:
972 case -9:
973 case -10:
974 case -11:
975 case -12:
976 case -13:
977 case -14:
978 case -15:
979 case -16:
980 ficlDictionaryAppendUnsigned(dictionary,
981 ficlInstruction0 - value);
982 break;
983
984 default:
985 ficlDictionaryAppendUnsigned(dictionary,
986 ficlInstructionLiteralParen);
987 ficlDictionaryAppendUnsigned(dictionary, value);
988 break;
989 }
990 }
991
992 static void
ficlPrimitive2LiteralIm(ficlVm * vm)993 ficlPrimitive2LiteralIm(ficlVm *vm)
994 {
995 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
996
997 ficlDictionaryAppendUnsigned(dictionary, ficlInstruction2LiteralParen);
998 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack));
999 ficlDictionaryAppendCell(dictionary, ficlStackPop(vm->dataStack));
1000 }
1001
1002 /*
1003 * D o / L o o p
1004 * do -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY
1005 * Compiles code to initialize a loop: FICL_VM_STATE_COMPILE (do),
1006 * allot space to hold the "leave" address, push a branch
1007 * target address for the loop.
1008 * (do) -- runtime for "do"
1009 * pops index and limit from the p stack and moves them
1010 * to the r stack, then skips to the loop body.
1011 * loop -- IMMEDIATE FICL_VM_STATE_COMPILE ONLY
1012 * +loop
1013 * Compiles code for the test part of a loop:
1014 * FICL_VM_STATE_COMPILE (loop), resolve forward branch from "do", and
1015 * copy "here" address to the "leave" address allotted by "do"
1016 * i,j,k -- FICL_VM_STATE_COMPILE ONLY
1017 * Runtime: Push loop indices on param stack (i is innermost loop...)
1018 * Note: each loop has three values on the return stack:
1019 * ( R: leave limit index )
1020 * "leave" is the absolute address of the next ficlCell after the loop
1021 * limit and index are the loop control variables.
1022 * leave -- FICL_VM_STATE_COMPILE ONLY
1023 * Runtime: pop the loop control variables, then pop the
1024 * "leave" address and jump (absolute) there.
1025 */
1026 static void
ficlPrimitiveDoCoIm(ficlVm * vm)1027 ficlPrimitiveDoCoIm(ficlVm *vm)
1028 {
1029 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1030
1031 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoParen);
1032 /*
1033 * Allot space for a pointer to the end
1034 * of the loop - "leave" uses this...
1035 */
1036 markBranch(dictionary, vm, leaveTag);
1037 ficlDictionaryAppendUnsigned(dictionary, 0);
1038 /*
1039 * Mark location of head of loop...
1040 */
1041 markBranch(dictionary, vm, doTag);
1042 }
1043
1044 static void
ficlPrimitiveQDoCoIm(ficlVm * vm)1045 ficlPrimitiveQDoCoIm(ficlVm *vm)
1046 {
1047 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1048
1049 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionQDoParen);
1050 /*
1051 * Allot space for a pointer to the end
1052 * of the loop - "leave" uses this...
1053 */
1054 markBranch(dictionary, vm, leaveTag);
1055 ficlDictionaryAppendUnsigned(dictionary, 0);
1056 /*
1057 * Mark location of head of loop...
1058 */
1059 markBranch(dictionary, vm, doTag);
1060 }
1061
1062
1063 static void
ficlPrimitiveLoopCoIm(ficlVm * vm)1064 ficlPrimitiveLoopCoIm(ficlVm *vm)
1065 {
1066 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1067
1068 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionLoopParen);
1069 resolveBackBranch(dictionary, vm, doTag);
1070 resolveAbsBranch(dictionary, vm, leaveTag);
1071 }
1072
1073 static void
ficlPrimitivePlusLoopCoIm(ficlVm * vm)1074 ficlPrimitivePlusLoopCoIm(ficlVm *vm)
1075 {
1076 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1077
1078 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionPlusLoopParen);
1079 resolveBackBranch(dictionary, vm, doTag);
1080 resolveAbsBranch(dictionary, vm, leaveTag);
1081 }
1082
1083 /*
1084 * v a r i a b l e
1085 */
1086 static void
ficlPrimitiveVariable(ficlVm * vm)1087 ficlPrimitiveVariable(ficlVm *vm)
1088 {
1089 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1090 ficlString name = ficlVmGetWord(vm);
1091
1092 ficlDictionaryAppendWord(dictionary, name,
1093 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT);
1094 ficlVmDictionaryAllotCells(vm, dictionary, 1);
1095 }
1096
1097 static void
ficlPrimitive2Variable(ficlVm * vm)1098 ficlPrimitive2Variable(ficlVm *vm)
1099 {
1100 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1101 ficlString name = ficlVmGetWord(vm);
1102
1103 ficlDictionaryAppendWord(dictionary, name,
1104 (ficlPrimitive)ficlInstructionVariableParen, FICL_WORD_DEFAULT);
1105 ficlVmDictionaryAllotCells(vm, dictionary, 2);
1106 }
1107
1108 /*
1109 * b a s e & f r i e n d s
1110 */
1111 static void
ficlPrimitiveBase(ficlVm * vm)1112 ficlPrimitiveBase(ficlVm *vm)
1113 {
1114 ficlCell *pBase, c;
1115
1116 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1117
1118 pBase = (ficlCell *)(&vm->base);
1119 c.p = pBase;
1120 ficlStackPush(vm->dataStack, c);
1121 }
1122
1123 static void
ficlPrimitiveDecimal(ficlVm * vm)1124 ficlPrimitiveDecimal(ficlVm *vm)
1125 {
1126 vm->base = 10;
1127 }
1128
1129
1130 static void
ficlPrimitiveHex(ficlVm * vm)1131 ficlPrimitiveHex(ficlVm *vm)
1132 {
1133 vm->base = 16;
1134 }
1135
1136 /*
1137 * a l l o t & f r i e n d s
1138 */
1139 static void
ficlPrimitiveAllot(ficlVm * vm)1140 ficlPrimitiveAllot(ficlVm *vm)
1141 {
1142 ficlDictionary *dictionary;
1143 ficlInteger i;
1144
1145 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1146
1147 dictionary = ficlVmGetDictionary(vm);
1148 i = ficlStackPopInteger(vm->dataStack);
1149
1150 FICL_VM_DICTIONARY_CHECK(vm, dictionary, i);
1151
1152 ficlVmDictionaryAllot(vm, dictionary, i);
1153 }
1154
1155 static void
ficlPrimitiveHere(ficlVm * vm)1156 ficlPrimitiveHere(ficlVm *vm)
1157 {
1158 ficlDictionary *dictionary;
1159
1160 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1161
1162 dictionary = ficlVmGetDictionary(vm);
1163 ficlStackPushPointer(vm->dataStack, dictionary->here);
1164 }
1165
1166 /*
1167 * t i c k
1168 * tick CORE ( "<spaces>name" -- xt )
1169 * Skip leading space delimiters. Parse name delimited by a space. Find
1170 * name and return xt, the execution token for name. An ambiguous condition
1171 * exists if name is not found.
1172 */
1173 void
ficlPrimitiveTick(ficlVm * vm)1174 ficlPrimitiveTick(ficlVm *vm)
1175 {
1176 ficlWord *word = NULL;
1177 ficlString name = ficlVmGetWord(vm);
1178
1179 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1180
1181 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name);
1182 if (!word)
1183 ficlVmThrowError(vm, "%.*s not found",
1184 FICL_STRING_GET_LENGTH(name),
1185 FICL_STRING_GET_POINTER(name));
1186 ficlStackPushPointer(vm->dataStack, word);
1187 }
1188
1189 static void
ficlPrimitiveBracketTickCoIm(ficlVm * vm)1190 ficlPrimitiveBracketTickCoIm(ficlVm *vm)
1191 {
1192 ficlPrimitiveTick(vm);
1193 ficlPrimitiveLiteralIm(vm);
1194 }
1195
1196 /*
1197 * p o s t p o n e
1198 * Lookup the next word in the input stream and FICL_VM_STATE_COMPILE code to
1199 * insert it into definitions created by the resulting word
1200 * (defers compilation, even of immediate words)
1201 */
1202 static void
ficlPrimitivePostponeCoIm(ficlVm * vm)1203 ficlPrimitivePostponeCoIm(ficlVm *vm)
1204 {
1205 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1206 ficlWord *word;
1207 ficlWord *pComma = ficlSystemLookup(vm->callback.system, ",");
1208 ficlCell c;
1209
1210 FICL_VM_ASSERT(vm, pComma);
1211
1212 ficlPrimitiveTick(vm);
1213 word = ficlStackGetTop(vm->dataStack).p;
1214 if (ficlWordIsImmediate(word)) {
1215 ficlDictionaryAppendCell(dictionary,
1216 ficlStackPop(vm->dataStack));
1217 } else {
1218 ficlPrimitiveLiteralIm(vm);
1219 c.p = pComma;
1220 ficlDictionaryAppendCell(dictionary, c);
1221 }
1222 }
1223
1224 /*
1225 * e x e c u t e
1226 * Pop an execution token (pointer to a word) off the stack and
1227 * run it
1228 */
1229 static void
ficlPrimitiveExecute(ficlVm * vm)1230 ficlPrimitiveExecute(ficlVm *vm)
1231 {
1232 ficlWord *word;
1233
1234 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1235
1236 word = ficlStackPopPointer(vm->dataStack);
1237 ficlVmExecuteWord(vm, word);
1238 }
1239
1240 /*
1241 * i m m e d i a t e
1242 * Make the most recently compiled word IMMEDIATE -- it executes even
1243 * in FICL_VM_STATE_COMPILE state (most often used for control compiling words
1244 * such as IF, THEN, etc)
1245 */
1246 static void
ficlPrimitiveImmediate(ficlVm * vm)1247 ficlPrimitiveImmediate(ficlVm *vm)
1248 {
1249 FICL_IGNORE(vm);
1250 ficlDictionarySetImmediate(ficlVmGetDictionary(vm));
1251 }
1252
1253 static void
ficlPrimitiveCompileOnly(ficlVm * vm)1254 ficlPrimitiveCompileOnly(ficlVm *vm)
1255 {
1256 FICL_IGNORE(vm);
1257 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_COMPILE_ONLY);
1258 }
1259
1260 static void
ficlPrimitiveSetObjectFlag(ficlVm * vm)1261 ficlPrimitiveSetObjectFlag(ficlVm *vm)
1262 {
1263 FICL_IGNORE(vm);
1264 ficlDictionarySetFlags(ficlVmGetDictionary(vm), FICL_WORD_OBJECT);
1265 }
1266
1267 static void
ficlPrimitiveIsObject(ficlVm * vm)1268 ficlPrimitiveIsObject(ficlVm *vm)
1269 {
1270 ficlInteger flag;
1271 ficlWord *word = (ficlWord *)ficlStackPopPointer(vm->dataStack);
1272
1273 flag = ((word != NULL) && (word->flags & FICL_WORD_OBJECT))?
1274 FICL_TRUE : FICL_FALSE;
1275
1276 ficlStackPushInteger(vm->dataStack, flag);
1277 }
1278
1279 static void
ficlPrimitiveCountedStringQuoteIm(ficlVm * vm)1280 ficlPrimitiveCountedStringQuoteIm(ficlVm *vm)
1281 {
1282 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1283
1284 if (vm->state == FICL_VM_STATE_INTERPRET) {
1285 ficlCountedString *counted = (ficlCountedString *)
1286 dictionary->here;
1287
1288 ficlVmGetString(vm, counted, '\"');
1289 ficlStackPushPointer(vm->dataStack, counted);
1290
1291 /*
1292 * move HERE past string so it doesn't get overwritten. --lch
1293 */
1294 ficlVmDictionaryAllot(vm, dictionary,
1295 counted->length + sizeof (ficlUnsigned8));
1296 } else { /* FICL_VM_STATE_COMPILE state */
1297 ficlDictionaryAppendUnsigned(dictionary,
1298 ficlInstructionCStringLiteralParen);
1299 dictionary->here =
1300 FICL_POINTER_TO_CELL(ficlVmGetString(vm,
1301 (ficlCountedString *)dictionary->here, '\"'));
1302 ficlDictionaryAlign(dictionary);
1303 }
1304 }
1305
1306 /*
1307 * d o t Q u o t e
1308 * IMMEDIATE word that compiles a string literal for later display
1309 * FICL_VM_STATE_COMPILE fiStringLiteralParen, then copy the bytes of the
1310 * string from the
1311 * TIB to the dictionary. Backpatch the count byte and align the dictionary.
1312 */
1313 static void
ficlPrimitiveDotQuoteCoIm(ficlVm * vm)1314 ficlPrimitiveDotQuoteCoIm(ficlVm *vm)
1315 {
1316 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1317 ficlWord *pType = ficlSystemLookup(vm->callback.system, "type");
1318 ficlCell c;
1319
1320 FICL_VM_ASSERT(vm, pType);
1321
1322 ficlDictionaryAppendUnsigned(dictionary,
1323 ficlInstructionStringLiteralParen);
1324 dictionary->here =
1325 FICL_POINTER_TO_CELL(ficlVmGetString(vm,
1326 (ficlCountedString *)dictionary->here, '\"'));
1327 ficlDictionaryAlign(dictionary);
1328 c.p = pType;
1329 ficlDictionaryAppendCell(dictionary, c);
1330 }
1331
1332 static void
ficlPrimitiveDotParen(ficlVm * vm)1333 ficlPrimitiveDotParen(ficlVm *vm)
1334 {
1335 char *from = ficlVmGetInBuf(vm);
1336 char *stop = ficlVmGetInBufEnd(vm);
1337 char *to = vm->pad;
1338 char c;
1339
1340 /*
1341 * Note: the standard does not want leading spaces skipped.
1342 */
1343 for (c = *from; (from != stop) && (c != ')'); c = *++from)
1344 *to++ = c;
1345
1346 *to = '\0';
1347 if ((from != stop) && (c == ')'))
1348 from++;
1349
1350 ficlVmTextOut(vm, vm->pad);
1351 ficlVmUpdateTib(vm, from);
1352 }
1353
1354 /*
1355 * s l i t e r a l
1356 * STRING
1357 * Interpretation: Interpretation semantics for this word are undefined.
1358 * Compilation: ( c-addr1 u -- )
1359 * Append the run-time semantics given below to the current definition.
1360 * Run-time: ( -- c-addr2 u )
1361 * Return c-addr2 u describing a string consisting of the characters
1362 * specified by c-addr1 u during compilation. A program shall not alter
1363 * the returned string.
1364 */
ficlPrimitiveSLiteralCoIm(ficlVm * vm)1365 static void ficlPrimitiveSLiteralCoIm(ficlVm *vm)
1366 {
1367 ficlDictionary *dictionary;
1368 char *from;
1369 char *to;
1370 ficlUnsigned length;
1371
1372 FICL_STACK_CHECK(vm->dataStack, 2, 0);
1373
1374 dictionary = ficlVmGetDictionary(vm);
1375 length = ficlStackPopUnsigned(vm->dataStack);
1376 from = ficlStackPopPointer(vm->dataStack);
1377
1378 ficlDictionaryAppendUnsigned(dictionary,
1379 ficlInstructionStringLiteralParen);
1380 to = (char *)dictionary->here;
1381 *to++ = (char)length;
1382
1383 for (; length > 0; --length) {
1384 *to++ = *from++;
1385 }
1386
1387 *to++ = 0;
1388 dictionary->here = FICL_POINTER_TO_CELL(ficlAlignPointer(to));
1389 }
1390
1391 /*
1392 * s t a t e
1393 * Return the address of the VM's state member (must be sized the
1394 * same as a ficlCell for this reason)
1395 */
ficlPrimitiveState(ficlVm * vm)1396 static void ficlPrimitiveState(ficlVm *vm)
1397 {
1398 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1399 ficlStackPushPointer(vm->dataStack, &vm->state);
1400 }
1401
1402 /*
1403 * c r e a t e . . . d o e s >
1404 * Make a new word in the dictionary with the run-time effect of
1405 * a variable (push my address), but with extra space allotted
1406 * for use by does> .
1407 */
1408 static void
ficlPrimitiveCreate(ficlVm * vm)1409 ficlPrimitiveCreate(ficlVm *vm)
1410 {
1411 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1412 ficlString name = ficlVmGetWord(vm);
1413
1414 ficlDictionaryAppendWord(dictionary, name,
1415 (ficlPrimitive)ficlInstructionCreateParen, FICL_WORD_DEFAULT);
1416 ficlVmDictionaryAllotCells(vm, dictionary, 1);
1417 }
1418
1419 static void
ficlPrimitiveDoesCoIm(ficlVm * vm)1420 ficlPrimitiveDoesCoIm(ficlVm *vm)
1421 {
1422 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1423 #if FICL_WANT_LOCALS
1424 if (vm->callback.system->localsCount > 0) {
1425 ficlDictionary *locals =
1426 ficlSystemGetLocals(vm->callback.system);
1427 ficlDictionaryEmpty(locals, locals->forthWordlist->size);
1428 ficlDictionaryAppendUnsigned(dictionary,
1429 ficlInstructionUnlinkParen);
1430 }
1431
1432 vm->callback.system->localsCount = 0;
1433 #endif
1434 FICL_IGNORE(vm);
1435
1436 ficlDictionaryAppendUnsigned(dictionary, ficlInstructionDoesParen);
1437 }
1438
1439 /*
1440 * t o b o d y
1441 * to-body CORE ( xt -- a-addr )
1442 * a-addr is the data-field address corresponding to xt. An ambiguous
1443 * condition exists if xt is not for a word defined via CREATE.
1444 */
1445 static void
ficlPrimitiveToBody(ficlVm * vm)1446 ficlPrimitiveToBody(ficlVm *vm)
1447 {
1448 ficlWord *word;
1449 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1450
1451 word = ficlStackPopPointer(vm->dataStack);
1452 ficlStackPushPointer(vm->dataStack, word->param + 1);
1453 }
1454
1455 /*
1456 * from-body Ficl ( a-addr -- xt )
1457 * Reverse effect of >body
1458 */
1459 static void
ficlPrimitiveFromBody(ficlVm * vm)1460 ficlPrimitiveFromBody(ficlVm *vm)
1461 {
1462 char *ptr;
1463 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1464
1465 ptr = (char *)ficlStackPopPointer(vm->dataStack) - sizeof (ficlWord);
1466 ficlStackPushPointer(vm->dataStack, ptr);
1467 }
1468
1469 /*
1470 * >name Ficl ( xt -- c-addr u )
1471 * Push the address and length of a word's name given its address
1472 * xt.
1473 */
1474 static void
ficlPrimitiveToName(ficlVm * vm)1475 ficlPrimitiveToName(ficlVm *vm)
1476 {
1477 ficlWord *word;
1478
1479 FICL_STACK_CHECK(vm->dataStack, 1, 2);
1480
1481 word = ficlStackPopPointer(vm->dataStack);
1482 ficlStackPushPointer(vm->dataStack, word->name);
1483 ficlStackPushUnsigned(vm->dataStack, word->length);
1484 }
1485
1486 static void
ficlPrimitiveLastWord(ficlVm * vm)1487 ficlPrimitiveLastWord(ficlVm *vm)
1488 {
1489 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1490 ficlWord *wp = dictionary->smudge;
1491 ficlCell c;
1492
1493 FICL_VM_ASSERT(vm, wp);
1494
1495 c.p = wp;
1496 ficlVmPush(vm, c);
1497 }
1498
1499 /*
1500 * l b r a c k e t e t c
1501 */
1502 static void
ficlPrimitiveLeftBracketCoIm(ficlVm * vm)1503 ficlPrimitiveLeftBracketCoIm(ficlVm *vm)
1504 {
1505 vm->state = FICL_VM_STATE_INTERPRET;
1506 }
1507
1508 static void
ficlPrimitiveRightBracket(ficlVm * vm)1509 ficlPrimitiveRightBracket(ficlVm *vm)
1510 {
1511 vm->state = FICL_VM_STATE_COMPILE;
1512 }
1513
1514 /*
1515 * p i c t u r e d n u m e r i c w o r d s
1516 *
1517 * less-number-sign CORE ( -- )
1518 * Initialize the pictured numeric output conversion process.
1519 * (clear the pad)
1520 */
1521 static void
ficlPrimitiveLessNumberSign(ficlVm * vm)1522 ficlPrimitiveLessNumberSign(ficlVm *vm)
1523 {
1524 ficlCountedString *counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1525 counted->length = 0;
1526 }
1527
1528 /*
1529 * number-sign CORE ( ud1 -- ud2 )
1530 * Divide ud1 by the number in BASE giving the quotient ud2 and the remainder
1531 * n. (n is the least-significant digit of ud1.) Convert n to external form
1532 * and add the resulting character to the beginning of the pictured numeric
1533 * output string. An ambiguous condition exists if # executes outside of a
1534 * <# #> delimited number conversion.
1535 */
1536 static void
ficlPrimitiveNumberSign(ficlVm * vm)1537 ficlPrimitiveNumberSign(ficlVm *vm)
1538 {
1539 ficlCountedString *counted;
1540 ficl2Unsigned u;
1541 ficl2UnsignedQR uqr;
1542
1543 FICL_STACK_CHECK(vm->dataStack, 2, 2);
1544
1545 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1546 u = ficlStackPop2Unsigned(vm->dataStack);
1547 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base));
1548 counted->text[counted->length++] = ficlDigitToCharacter(uqr.remainder);
1549 ficlStackPush2Unsigned(vm->dataStack, uqr.quotient);
1550 }
1551
1552 /*
1553 * number-sign-greater CORE ( xd -- c-addr u )
1554 * Drop xd. Make the pictured numeric output string available as a character
1555 * string. c-addr and u specify the resulting character string. A program
1556 * may replace characters within the string.
1557 */
1558 static void
ficlPrimitiveNumberSignGreater(ficlVm * vm)1559 ficlPrimitiveNumberSignGreater(ficlVm *vm)
1560 {
1561 ficlCountedString *counted;
1562
1563 FICL_STACK_CHECK(vm->dataStack, 2, 2);
1564
1565 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1566 counted->text[counted->length] = 0;
1567 ficlStringReverse(counted->text);
1568 ficlStackDrop(vm->dataStack, 2);
1569 ficlStackPushPointer(vm->dataStack, counted->text);
1570 ficlStackPushUnsigned(vm->dataStack, counted->length);
1571 }
1572
1573 /*
1574 * number-sign-s CORE ( ud1 -- ud2 )
1575 * Convert one digit of ud1 according to the rule for #. Continue conversion
1576 * until the quotient is zero. ud2 is zero. An ambiguous condition exists if
1577 * #S executes outside of a <# #> delimited number conversion.
1578 * TO DO: presently does not use ud1 hi ficlCell - use it!
1579 */
1580 static void
ficlPrimitiveNumberSignS(ficlVm * vm)1581 ficlPrimitiveNumberSignS(ficlVm *vm)
1582 {
1583 ficlCountedString *counted;
1584 ficl2Unsigned u;
1585 ficl2UnsignedQR uqr;
1586
1587 FICL_STACK_CHECK(vm->dataStack, 2, 2);
1588
1589 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1590 u = ficlStackPop2Unsigned(vm->dataStack);
1591
1592 do {
1593 uqr = ficl2UnsignedDivide(u, (ficlUnsigned16)(vm->base));
1594 counted->text[counted->length++] =
1595 ficlDigitToCharacter(uqr.remainder);
1596 u = uqr.quotient;
1597 } while (FICL_2UNSIGNED_NOT_ZERO(u));
1598
1599 ficlStackPush2Unsigned(vm->dataStack, u);
1600 }
1601
1602 /*
1603 * HOLD CORE ( char -- )
1604 * Add char to the beginning of the pictured numeric output string.
1605 * An ambiguous condition exists if HOLD executes outside of a <# #>
1606 * delimited number conversion.
1607 */
1608 static void
ficlPrimitiveHold(ficlVm * vm)1609 ficlPrimitiveHold(ficlVm *vm)
1610 {
1611 ficlCountedString *counted;
1612 int i;
1613
1614 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1615
1616 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1617 i = ficlStackPopInteger(vm->dataStack);
1618 counted->text[counted->length++] = (char)i;
1619 }
1620
1621 /*
1622 * SIGN CORE ( n -- )
1623 * If n is negative, add a minus sign to the beginning of the pictured
1624 * numeric output string. An ambiguous condition exists if SIGN
1625 * executes outside of a <# #> delimited number conversion.
1626 */
1627 static void
ficlPrimitiveSign(ficlVm * vm)1628 ficlPrimitiveSign(ficlVm *vm)
1629 {
1630 ficlCountedString *counted;
1631 int i;
1632
1633 FICL_STACK_CHECK(vm->dataStack, 1, 0);
1634
1635 counted = FICL_POINTER_TO_COUNTED_STRING(vm->pad);
1636 i = ficlStackPopInteger(vm->dataStack);
1637 if (i < 0)
1638 counted->text[counted->length++] = '-';
1639 }
1640
1641 /*
1642 * t o N u m b e r
1643 * to-number CORE ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 )
1644 * ud2 is the unsigned result of converting the characters within the
1645 * string specified by c-addr1 u1 into digits, using the number in BASE,
1646 * and adding each into ud1 after multiplying ud1 by the number in BASE.
1647 * Conversion continues left-to-right until a character that is not
1648 * convertible, including any + or -, is encountered or the string is
1649 * entirely converted. c-addr2 is the location of the first unconverted
1650 * character or the first character past the end of the string if the string
1651 * was entirely converted. u2 is the number of unconverted characters in the
1652 * string. An ambiguous condition exists if ud2 overflows during the
1653 * conversion.
1654 */
1655 static void
ficlPrimitiveToNumber(ficlVm * vm)1656 ficlPrimitiveToNumber(ficlVm *vm)
1657 {
1658 ficlUnsigned length;
1659 char *trace;
1660 ficl2Unsigned accumulator;
1661 ficlUnsigned base = vm->base;
1662 ficlUnsigned c;
1663 ficlUnsigned digit;
1664
1665 FICL_STACK_CHECK(vm->dataStack, 4, 4);
1666
1667 length = ficlStackPopUnsigned(vm->dataStack);
1668 trace = (char *)ficlStackPopPointer(vm->dataStack);
1669 accumulator = ficlStackPop2Unsigned(vm->dataStack);
1670
1671 for (c = *trace; length > 0; c = *++trace, length--) {
1672 if (c < '0')
1673 break;
1674
1675 digit = c - '0';
1676
1677 if (digit > 9)
1678 digit = tolower(c) - 'a' + 10;
1679 /*
1680 * Note: following test also catches chars between 9 and a
1681 * because 'digit' is unsigned!
1682 */
1683 if (digit >= base)
1684 break;
1685
1686 accumulator = ficl2UnsignedMultiplyAccumulate(accumulator,
1687 base, digit);
1688 }
1689
1690 ficlStackPush2Unsigned(vm->dataStack, accumulator);
1691 ficlStackPushPointer(vm->dataStack, trace);
1692 ficlStackPushUnsigned(vm->dataStack, length);
1693 }
1694
1695 /*
1696 * q u i t & a b o r t
1697 * quit CORE ( -- ) ( R: i*x -- )
1698 * Empty the return stack, store zero in SOURCE-ID if it is present, make
1699 * the user input device the input source, and enter interpretation state.
1700 * Do not display a message. Repeat the following:
1701 *
1702 * Accept a line from the input source into the input buffer, set >IN to
1703 * zero, and FICL_VM_STATE_INTERPRET.
1704 * Display the implementation-defined system prompt if in
1705 * interpretation state, all processing has been completed, and no
1706 * ambiguous condition exists.
1707 */
1708 static void
ficlPrimitiveQuit(ficlVm * vm)1709 ficlPrimitiveQuit(ficlVm *vm)
1710 {
1711 ficlVmThrow(vm, FICL_VM_STATUS_QUIT);
1712 }
1713
1714 static void
ficlPrimitiveAbort(ficlVm * vm)1715 ficlPrimitiveAbort(ficlVm *vm)
1716 {
1717 ficlVmThrow(vm, FICL_VM_STATUS_ABORT);
1718 }
1719
1720 /*
1721 * a c c e p t
1722 * accept CORE ( c-addr +n1 -- +n2 )
1723 * Receive a string of at most +n1 characters. An ambiguous condition
1724 * exists if +n1 is zero or greater than 32,767. Display graphic characters
1725 * as they are received. A program that depends on the presence or absence
1726 * of non-graphic characters in the string has an environmental dependency.
1727 * The editing functions, if any, that the system performs in order to
1728 * construct the string are implementation-defined.
1729 *
1730 * (Although the standard text doesn't say so, I assume that the intent
1731 * of 'accept' is to store the string at the address specified on
1732 * the stack.)
1733 *
1734 * NOTE: getchar() is used there as its present both in loader and
1735 * userland; however, the more correct solution would be to set
1736 * terminal to raw mode for userland.
1737 */
1738 static void
ficlPrimitiveAccept(ficlVm * vm)1739 ficlPrimitiveAccept(ficlVm *vm)
1740 {
1741 ficlUnsigned size;
1742 char *address;
1743 int c;
1744 ficlUnsigned length = 0;
1745
1746 FICL_STACK_CHECK(vm->dataStack, 2, 1);
1747
1748 size = ficlStackPopInteger(vm->dataStack);
1749 address = ficlStackPopPointer(vm->dataStack);
1750
1751 while (size != length) {
1752 c = getchar();
1753 if (c == '\n' || c == '\r')
1754 break;
1755 address[length++] = c;
1756 }
1757 ficlStackPushInteger(vm->dataStack, length);
1758 }
1759
1760 /*
1761 * a l i g n
1762 * 6.1.0705 ALIGN CORE ( -- )
1763 * If the data-space pointer is not aligned, reserve enough space to
1764 * align it.
1765 */
1766 static void
ficlPrimitiveAlign(ficlVm * vm)1767 ficlPrimitiveAlign(ficlVm *vm)
1768 {
1769 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1770 FICL_IGNORE(vm);
1771 ficlDictionaryAlign(dictionary);
1772 }
1773
1774 /*
1775 * a l i g n e d
1776 */
1777 static void
ficlPrimitiveAligned(ficlVm * vm)1778 ficlPrimitiveAligned(ficlVm *vm)
1779 {
1780 void *addr;
1781
1782 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1783
1784 addr = ficlStackPopPointer(vm->dataStack);
1785 ficlStackPushPointer(vm->dataStack, ficlAlignPointer(addr));
1786 }
1787
1788 /*
1789 * b e g i n & f r i e n d s
1790 * Indefinite loop control structures
1791 * A.6.1.0760 BEGIN
1792 * Typical use:
1793 * : X ... BEGIN ... test UNTIL ;
1794 * or
1795 * : X ... BEGIN ... test WHILE ... REPEAT ;
1796 */
1797 static void
ficlPrimitiveBeginCoIm(ficlVm * vm)1798 ficlPrimitiveBeginCoIm(ficlVm *vm)
1799 {
1800 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1801 markBranch(dictionary, vm, destTag);
1802 }
1803
1804 static void
ficlPrimitiveUntilCoIm(ficlVm * vm)1805 ficlPrimitiveUntilCoIm(ficlVm *vm)
1806 {
1807 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1808
1809 ficlDictionaryAppendUnsigned(dictionary,
1810 ficlInstructionBranch0ParenWithCheck);
1811 resolveBackBranch(dictionary, vm, destTag);
1812 }
1813
1814 static void
ficlPrimitiveWhileCoIm(ficlVm * vm)1815 ficlPrimitiveWhileCoIm(ficlVm *vm)
1816 {
1817 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1818
1819 FICL_STACK_CHECK(vm->dataStack, 2, 5);
1820
1821 ficlDictionaryAppendUnsigned(dictionary,
1822 ficlInstructionBranch0ParenWithCheck);
1823 markBranch(dictionary, vm, origTag);
1824
1825 /* equivalent to 2swap */
1826 ficlStackRoll(vm->dataStack, 3);
1827 ficlStackRoll(vm->dataStack, 3);
1828
1829 ficlDictionaryAppendUnsigned(dictionary, 1);
1830 }
1831
1832 static void
ficlPrimitiveRepeatCoIm(ficlVm * vm)1833 ficlPrimitiveRepeatCoIm(ficlVm *vm)
1834 {
1835 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1836
1837 ficlDictionaryAppendUnsigned(dictionary,
1838 ficlInstructionBranchParenWithCheck);
1839 /* expect "begin" branch marker */
1840 resolveBackBranch(dictionary, vm, destTag);
1841 /* expect "while" branch marker */
1842 resolveForwardBranch(dictionary, vm, origTag);
1843 }
1844
1845 static void
ficlPrimitiveAgainCoIm(ficlVm * vm)1846 ficlPrimitiveAgainCoIm(ficlVm *vm)
1847 {
1848 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1849
1850 ficlDictionaryAppendUnsigned(dictionary,
1851 ficlInstructionBranchParenWithCheck);
1852 /* expect "begin" branch marker */
1853 resolveBackBranch(dictionary, vm, destTag);
1854 }
1855
1856 /*
1857 * c h a r & f r i e n d s
1858 * 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
1859 * Skip leading space delimiters. Parse name delimited by a space.
1860 * Put the value of its first character onto the stack.
1861 *
1862 * bracket-char CORE
1863 * Interpretation: Interpretation semantics for this word are undefined.
1864 * Compilation: ( "<spaces>name" -- )
1865 * Skip leading space delimiters. Parse name delimited by a space.
1866 * Append the run-time semantics given below to the current definition.
1867 * Run-time: ( -- char )
1868 * Place char, the value of the first character of name, on the stack.
1869 */
1870 static void
ficlPrimitiveChar(ficlVm * vm)1871 ficlPrimitiveChar(ficlVm *vm)
1872 {
1873 ficlString s;
1874
1875 FICL_STACK_CHECK(vm->dataStack, 0, 1);
1876
1877 s = ficlVmGetWord(vm);
1878 ficlStackPushUnsigned(vm->dataStack, (ficlUnsigned)(s.text[0]));
1879 }
1880
1881 static void
ficlPrimitiveCharCoIm(ficlVm * vm)1882 ficlPrimitiveCharCoIm(ficlVm *vm)
1883 {
1884 ficlPrimitiveChar(vm);
1885 ficlPrimitiveLiteralIm(vm);
1886 }
1887
1888 /*
1889 * c h a r P l u s
1890 * char-plus CORE ( c-addr1 -- c-addr2 )
1891 * Add the size in address units of a character to c-addr1, giving c-addr2.
1892 */
1893 static void
ficlPrimitiveCharPlus(ficlVm * vm)1894 ficlPrimitiveCharPlus(ficlVm *vm)
1895 {
1896 char *p;
1897
1898 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1899
1900 p = ficlStackPopPointer(vm->dataStack);
1901 ficlStackPushPointer(vm->dataStack, p + 1);
1902 }
1903
1904 /*
1905 * c h a r s
1906 * chars CORE ( n1 -- n2 )
1907 * n2 is the size in address units of n1 characters.
1908 * For most processors, this function can be a no-op. To guarantee
1909 * portability, we'll multiply by sizeof (char).
1910 */
1911 #if defined(_M_IX86)
1912 #pragma warning(disable: 4127)
1913 #endif
1914 static void
ficlPrimitiveChars(ficlVm * vm)1915 ficlPrimitiveChars(ficlVm *vm)
1916 {
1917 if (sizeof (char) > 1) {
1918 ficlInteger i;
1919
1920 FICL_STACK_CHECK(vm->dataStack, 1, 1);
1921
1922 i = ficlStackPopInteger(vm->dataStack);
1923 ficlStackPushInteger(vm->dataStack, i * sizeof (char));
1924 }
1925 /* otherwise no-op! */
1926 }
1927 #if defined(_M_IX86)
1928 #pragma warning(default: 4127)
1929 #endif
1930
1931 /*
1932 * c o u n t
1933 * COUNT CORE ( c-addr1 -- c-addr2 u )
1934 * Return the character string specification for the counted string stored
1935 * at c-addr1. c-addr2 is the address of the first character after c-addr1.
1936 * u is the contents of the character at c-addr1, which is the length in
1937 * characters of the string at c-addr2.
1938 */
1939 static void
ficlPrimitiveCount(ficlVm * vm)1940 ficlPrimitiveCount(ficlVm *vm)
1941 {
1942 ficlCountedString *counted;
1943
1944 FICL_STACK_CHECK(vm->dataStack, 1, 2);
1945
1946 counted = ficlStackPopPointer(vm->dataStack);
1947 ficlStackPushPointer(vm->dataStack, counted->text);
1948 ficlStackPushUnsigned(vm->dataStack, counted->length);
1949 }
1950
1951 /*
1952 * e n v i r o n m e n t ?
1953 * environment-query CORE ( c-addr u -- FICL_FALSE | i*x FICL_TRUE )
1954 * c-addr is the address of a character string and u is the string's
1955 * character count. u may have a value in the range from zero to an
1956 * implementation-defined maximum which shall not be less than 31. The
1957 * character string should contain a keyword from 3.2.6 Environmental
1958 * queries or the optional word sets to be checked for correspondence
1959 * with an attribute of the present environment. If the system treats the
1960 * attribute as unknown, the returned flag is FICL_FALSE; otherwise, the flag
1961 * is FICL_TRUE and the i*x returned is of the type specified in the table for
1962 * the attribute queried.
1963 */
1964 static void
ficlPrimitiveEnvironmentQ(ficlVm * vm)1965 ficlPrimitiveEnvironmentQ(ficlVm *vm)
1966 {
1967 ficlDictionary *environment;
1968 ficlWord *word;
1969 ficlString name;
1970
1971 FICL_STACK_CHECK(vm->dataStack, 2, 1);
1972
1973 environment = vm->callback.system->environment;
1974 name.length = ficlStackPopUnsigned(vm->dataStack);
1975 name.text = ficlStackPopPointer(vm->dataStack);
1976
1977 word = ficlDictionaryLookup(environment, name);
1978
1979 if (word != NULL) {
1980 ficlVmExecuteWord(vm, word);
1981 ficlStackPushInteger(vm->dataStack, FICL_TRUE);
1982 } else {
1983 ficlStackPushInteger(vm->dataStack, FICL_FALSE);
1984 }
1985 }
1986
1987 /*
1988 * e v a l u a t e
1989 * EVALUATE CORE ( i*x c-addr u -- j*x )
1990 * Save the current input source specification. Store minus-one (-1) in
1991 * SOURCE-ID if it is present. Make the string described by c-addr and u
1992 * both the input source and input buffer, set >IN to zero, and
1993 * FICL_VM_STATE_INTERPRET.
1994 * When the parse area is empty, restore the prior input source
1995 * specification. Other stack effects are due to the words EVALUATEd.
1996 */
1997 static void
ficlPrimitiveEvaluate(ficlVm * vm)1998 ficlPrimitiveEvaluate(ficlVm *vm)
1999 {
2000 ficlCell id;
2001 int result;
2002 ficlString string;
2003
2004 FICL_STACK_CHECK(vm->dataStack, 2, 0);
2005
2006 FICL_STRING_SET_LENGTH(string, ficlStackPopUnsigned(vm->dataStack));
2007 FICL_STRING_SET_POINTER(string, ficlStackPopPointer(vm->dataStack));
2008
2009 id = vm->sourceId;
2010 vm->sourceId.i = -1;
2011 result = ficlVmExecuteString(vm, string);
2012 vm->sourceId = id;
2013 if (result != FICL_VM_STATUS_OUT_OF_TEXT)
2014 ficlVmThrow(vm, result);
2015 }
2016
2017 /*
2018 * s t r i n g q u o t e
2019 * Interpreting: get string delimited by a quote from the input stream,
2020 * copy to a scratch area, and put its count and address on the stack.
2021 * Compiling: FICL_VM_STATE_COMPILE code to push the address and count
2022 * of a string literal, FICL_VM_STATE_COMPILE the string from the input
2023 * stream, and align the dictionary pointer.
2024 */
2025 static void
ficlPrimitiveStringQuoteIm(ficlVm * vm)2026 ficlPrimitiveStringQuoteIm(ficlVm *vm)
2027 {
2028 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2029
2030 if (vm->state == FICL_VM_STATE_INTERPRET) {
2031 ficlCountedString *counted;
2032 counted = (ficlCountedString *)dictionary->here;
2033 ficlVmGetString(vm, counted, '\"');
2034 ficlStackPushPointer(vm->dataStack, counted->text);
2035 ficlStackPushUnsigned(vm->dataStack, counted->length);
2036 } else { /* FICL_VM_STATE_COMPILE state */
2037 ficlDictionaryAppendUnsigned(dictionary,
2038 ficlInstructionStringLiteralParen);
2039 dictionary->here = FICL_POINTER_TO_CELL(
2040 ficlVmGetString(vm, (ficlCountedString *)dictionary->here,
2041 '\"'));
2042 ficlDictionaryAlign(dictionary);
2043 }
2044 }
2045
2046 /*
2047 * t y p e
2048 * Pop count and char address from stack and print the designated string.
2049 */
2050 static void
ficlPrimitiveType(ficlVm * vm)2051 ficlPrimitiveType(ficlVm *vm)
2052 {
2053 ficlUnsigned length;
2054 char *s;
2055
2056 FICL_STACK_CHECK(vm->dataStack, 2, 0);
2057
2058 length = ficlStackPopUnsigned(vm->dataStack);
2059 s = ficlStackPopPointer(vm->dataStack);
2060
2061 if ((s == NULL) || (length == 0))
2062 return;
2063
2064 /*
2065 * Since we don't have an output primitive for a counted string
2066 * (oops), make sure the string is null terminated. If not, copy
2067 * and terminate it.
2068 */
2069 if (s[length] != 0) {
2070 char *here = (char *)ficlVmGetDictionary(vm)->here;
2071 if (s != here)
2072 strncpy(here, s, length);
2073
2074 here[length] = '\0';
2075 s = here;
2076 }
2077
2078 ficlVmTextOut(vm, s);
2079 }
2080
2081 /*
2082 * w o r d
2083 * word CORE ( char "<chars>ccc<char>" -- c-addr )
2084 * Skip leading delimiters. Parse characters ccc delimited by char. An
2085 * ambiguous condition exists if the length of the parsed string is greater
2086 * than the implementation-defined length of a counted string.
2087 *
2088 * c-addr is the address of a transient region containing the parsed word
2089 * as a counted string. If the parse area was empty or contained no
2090 * characters other than the delimiter, the resulting string has a zero
2091 * length. A space, not included in the length, follows the string. A
2092 * program may replace characters within the string.
2093 * NOTE! Ficl also NULL-terminates the dest string.
2094 */
2095 static void
ficlPrimitiveWord(ficlVm * vm)2096 ficlPrimitiveWord(ficlVm *vm)
2097 {
2098 ficlCountedString *counted;
2099 char delim;
2100 ficlString name;
2101
2102 FICL_STACK_CHECK(vm->dataStack, 1, 1);
2103
2104 counted = (ficlCountedString *)vm->pad;
2105 delim = (char)ficlStackPopInteger(vm->dataStack);
2106 name = ficlVmParseStringEx(vm, delim, 1);
2107
2108 if (FICL_STRING_GET_LENGTH(name) > FICL_PAD_SIZE - 1)
2109 FICL_STRING_SET_LENGTH(name, FICL_PAD_SIZE - 1);
2110
2111 counted->length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(name);
2112 strncpy(counted->text, FICL_STRING_GET_POINTER(name),
2113 FICL_STRING_GET_LENGTH(name));
2114
2115 /*
2116 * store an extra space at the end of the primitive...
2117 * why? dunno yet. Guy Carver did it.
2118 */
2119 counted->text[counted->length] = ' ';
2120 counted->text[counted->length + 1] = 0;
2121
2122 ficlStackPushPointer(vm->dataStack, counted);
2123 }
2124
2125 /*
2126 * p a r s e - w o r d
2127 * Ficl PARSE-WORD ( <spaces>name -- c-addr u )
2128 * Skip leading spaces and parse name delimited by a space. c-addr is the
2129 * address within the input buffer and u is the length of the selected
2130 * string. If the parse area is empty, the resulting string has a zero length.
2131 */
ficlPrimitiveParseNoCopy(ficlVm * vm)2132 static void ficlPrimitiveParseNoCopy(ficlVm *vm)
2133 {
2134 ficlString s;
2135
2136 FICL_STACK_CHECK(vm->dataStack, 0, 2);
2137
2138 s = ficlVmGetWord0(vm);
2139 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s));
2140 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s));
2141 }
2142
2143 /*
2144 * p a r s e
2145 * CORE EXT ( char "ccc<char>" -- c-addr u )
2146 * Parse ccc delimited by the delimiter char.
2147 * c-addr is the address (within the input buffer) and u is the length of
2148 * the parsed string. If the parse area was empty, the resulting string has
2149 * a zero length.
2150 * NOTE! PARSE differs from WORD: it does not skip leading delimiters.
2151 */
2152 static void
ficlPrimitiveParse(ficlVm * vm)2153 ficlPrimitiveParse(ficlVm *vm)
2154 {
2155 ficlString s;
2156 char delim;
2157
2158 FICL_STACK_CHECK(vm->dataStack, 1, 2);
2159
2160 delim = (char)ficlStackPopInteger(vm->dataStack);
2161
2162 s = ficlVmParseStringEx(vm, delim, 0);
2163 ficlStackPushPointer(vm->dataStack, FICL_STRING_GET_POINTER(s));
2164 ficlStackPushUnsigned(vm->dataStack, FICL_STRING_GET_LENGTH(s));
2165 }
2166
2167 /*
2168 * f i n d
2169 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
2170 * Find the definition named in the counted string at c-addr. If the
2171 * definition is not found, return c-addr and zero. If the definition is
2172 * found, return its execution token xt. If the definition is immediate,
2173 * also return one (1), otherwise also return minus-one (-1). For a given
2174 * string, the values returned by FIND while compiling may differ from
2175 * those returned while not compiling.
2176 */
2177 static void
do_find(ficlVm * vm,ficlString name,void * returnForFailure)2178 do_find(ficlVm *vm, ficlString name, void *returnForFailure)
2179 {
2180 ficlWord *word;
2181
2182 word = ficlDictionaryLookup(ficlVmGetDictionary(vm), name);
2183 if (word) {
2184 ficlStackPushPointer(vm->dataStack, word);
2185 ficlStackPushInteger(vm->dataStack,
2186 (ficlWordIsImmediate(word) ? 1 : -1));
2187 } else {
2188 ficlStackPushPointer(vm->dataStack, returnForFailure);
2189 ficlStackPushUnsigned(vm->dataStack, 0);
2190 }
2191 }
2192
2193 /*
2194 * f i n d
2195 * FIND CORE ( c-addr -- c-addr 0 | xt 1 | xt -1 )
2196 * Find the definition named in the counted string at c-addr. If the
2197 * definition is not found, return c-addr and zero. If the definition is
2198 * found, return its execution token xt. If the definition is immediate,
2199 * also return one (1), otherwise also return minus-one (-1). For a given
2200 * string, the values returned by FIND while compiling may differ from
2201 * those returned while not compiling.
2202 */
2203 static void
ficlPrimitiveCFind(ficlVm * vm)2204 ficlPrimitiveCFind(ficlVm *vm)
2205 {
2206 ficlCountedString *counted;
2207 ficlString name;
2208
2209 FICL_STACK_CHECK(vm->dataStack, 1, 2);
2210
2211 counted = ficlStackPopPointer(vm->dataStack);
2212 FICL_STRING_SET_FROM_COUNTED_STRING(name, *counted);
2213 do_find(vm, name, counted);
2214 }
2215
2216 /*
2217 * s f i n d
2218 * Ficl ( c-addr u -- 0 0 | xt 1 | xt -1 )
2219 * Like FIND, but takes "c-addr u" for the string.
2220 */
2221 static void
ficlPrimitiveSFind(ficlVm * vm)2222 ficlPrimitiveSFind(ficlVm *vm)
2223 {
2224 ficlString name;
2225
2226 FICL_STACK_CHECK(vm->dataStack, 2, 2);
2227
2228 name.length = ficlStackPopInteger(vm->dataStack);
2229 name.text = ficlStackPopPointer(vm->dataStack);
2230
2231 do_find(vm, name, NULL);
2232 }
2233
2234 /*
2235 * r e c u r s e
2236 */
2237 static void
ficlPrimitiveRecurseCoIm(ficlVm * vm)2238 ficlPrimitiveRecurseCoIm(ficlVm *vm)
2239 {
2240 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2241 ficlCell c;
2242
2243 FICL_IGNORE(vm);
2244 c.p = dictionary->smudge;
2245 ficlDictionaryAppendCell(dictionary, c);
2246 }
2247
2248 /*
2249 * s o u r c e
2250 * CORE ( -- c-addr u )
2251 * c-addr is the address of, and u is the number of characters in, the
2252 * input buffer.
2253 */
2254 static void
ficlPrimitiveSource(ficlVm * vm)2255 ficlPrimitiveSource(ficlVm *vm)
2256 {
2257 FICL_STACK_CHECK(vm->dataStack, 0, 2);
2258
2259 ficlStackPushPointer(vm->dataStack, vm->tib.text);
2260 ficlStackPushInteger(vm->dataStack, ficlVmGetInBufLen(vm));
2261 }
2262
2263 /*
2264 * v e r s i o n
2265 * non-standard...
2266 */
2267 static void
ficlPrimitiveVersion(ficlVm * vm)2268 ficlPrimitiveVersion(ficlVm *vm)
2269 {
2270 ficlVmTextOut(vm, "Ficl version " FICL_VERSION "\n");
2271 }
2272
2273 /*
2274 * t o I n
2275 * to-in CORE
2276 */
2277 static void
ficlPrimitiveToIn(ficlVm * vm)2278 ficlPrimitiveToIn(ficlVm *vm)
2279 {
2280 FICL_STACK_CHECK(vm->dataStack, 0, 1);
2281
2282 ficlStackPushPointer(vm->dataStack, &vm->tib.index);
2283 }
2284
2285 /*
2286 * c o l o n N o N a m e
2287 * CORE EXT ( C: -- colon-sys ) ( S: -- xt )
2288 * Create an unnamed colon definition and push its address.
2289 * Change state to FICL_VM_STATE_COMPILE.
2290 */
2291 static void
ficlPrimitiveColonNoName(ficlVm * vm)2292 ficlPrimitiveColonNoName(ficlVm *vm)
2293 {
2294 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2295 ficlWord *word;
2296 ficlString name;
2297
2298 FICL_STRING_SET_LENGTH(name, 0);
2299 FICL_STRING_SET_POINTER(name, NULL);
2300
2301 vm->state = FICL_VM_STATE_COMPILE;
2302 word = ficlDictionaryAppendWord(dictionary, name,
2303 (ficlPrimitive)ficlInstructionColonParen,
2304 FICL_WORD_DEFAULT | FICL_WORD_SMUDGED);
2305
2306 ficlStackPushPointer(vm->dataStack, word);
2307 markControlTag(vm, colonTag);
2308 }
2309
2310 /*
2311 * u s e r V a r i a b l e
2312 * user ( u -- ) "<spaces>name"
2313 * Get a name from the input stream and create a user variable
2314 * with the name and the index supplied. The run-time effect
2315 * of a user variable is to push the address of the indexed ficlCell
2316 * in the running vm's user array.
2317 *
2318 * User variables are vm local cells. Each vm has an array of
2319 * FICL_USER_CELLS of them when FICL_WANT_USER is nonzero.
2320 * Ficl's user facility is implemented with two primitives,
2321 * "user" and "(user)", a variable ("nUser") (in softcore.c) that
2322 * holds the index of the next free user ficlCell, and a redefinition
2323 * (also in softcore) of "user" that defines a user word and increments
2324 * nUser.
2325 */
2326 #if FICL_WANT_USER
2327 static void
ficlPrimitiveUser(ficlVm * vm)2328 ficlPrimitiveUser(ficlVm *vm)
2329 {
2330 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2331 ficlString name = ficlVmGetWord(vm);
2332 ficlCell c;
2333
2334 c = ficlStackPop(vm->dataStack);
2335 if (c.i >= FICL_USER_CELLS) {
2336 ficlVmThrowError(vm, "Error - out of user space");
2337 }
2338
2339 ficlDictionaryAppendWord(dictionary, name,
2340 (ficlPrimitive)ficlInstructionUserParen, FICL_WORD_DEFAULT);
2341 ficlDictionaryAppendCell(dictionary, c);
2342 }
2343 #endif
2344
2345 #if FICL_WANT_LOCALS
2346 /*
2347 * Each local is recorded in a private locals dictionary as a
2348 * word that does doLocalIm at runtime. DoLocalIm compiles code
2349 * into the client definition to fetch the value of the
2350 * corresponding local variable from the return stack.
2351 * The private dictionary gets initialized at the end of each block
2352 * that uses locals (in ; and does> for example).
2353 */
2354 void
ficlLocalParenIm(ficlVm * vm,int isDouble,int isFloat)2355 ficlLocalParenIm(ficlVm *vm, int isDouble, int isFloat)
2356 {
2357 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2358 ficlInteger nLocal = vm->runningWord->param[0].i;
2359
2360 #if !FICL_WANT_FLOAT
2361 FICL_VM_ASSERT(vm, !isFloat);
2362 /* get rid of unused parameter warning */
2363 isFloat = 0;
2364 #endif /* FICL_WANT_FLOAT */
2365
2366 if (vm->state == FICL_VM_STATE_INTERPRET) {
2367 ficlStack *stack;
2368 #if FICL_WANT_FLOAT
2369 if (isFloat)
2370 stack = vm->floatStack;
2371 else
2372 #endif /* FICL_WANT_FLOAT */
2373 stack = vm->dataStack;
2374
2375 ficlStackPush(stack, vm->returnStack->frame[nLocal]);
2376 if (isDouble)
2377 ficlStackPush(stack, vm->returnStack->frame[nLocal+1]);
2378 } else {
2379 ficlInstruction instruction;
2380 ficlInteger appendLocalOffset;
2381 #if FICL_WANT_FLOAT
2382 if (isFloat) {
2383 instruction =
2384 (isDouble) ? ficlInstructionGetF2LocalParen :
2385 ficlInstructionGetFLocalParen;
2386 appendLocalOffset = FICL_TRUE;
2387 } else
2388 #endif /* FICL_WANT_FLOAT */
2389 if (nLocal == 0) {
2390 instruction = (isDouble) ? ficlInstructionGet2Local0 :
2391 ficlInstructionGetLocal0;
2392 appendLocalOffset = FICL_FALSE;
2393 } else if ((nLocal == 1) && !isDouble) {
2394 instruction = ficlInstructionGetLocal1;
2395 appendLocalOffset = FICL_FALSE;
2396 } else {
2397 instruction =
2398 (isDouble) ? ficlInstructionGet2LocalParen :
2399 ficlInstructionGetLocalParen;
2400 appendLocalOffset = FICL_TRUE;
2401 }
2402
2403 ficlDictionaryAppendUnsigned(dictionary, instruction);
2404 if (appendLocalOffset)
2405 ficlDictionaryAppendUnsigned(dictionary, nLocal);
2406 }
2407 }
2408
2409 static void
ficlPrimitiveDoLocalIm(ficlVm * vm)2410 ficlPrimitiveDoLocalIm(ficlVm *vm)
2411 {
2412 ficlLocalParenIm(vm, 0, 0);
2413 }
2414
2415 static void
ficlPrimitiveDo2LocalIm(ficlVm * vm)2416 ficlPrimitiveDo2LocalIm(ficlVm *vm)
2417 {
2418 ficlLocalParenIm(vm, 1, 0);
2419 }
2420
2421 #if FICL_WANT_FLOAT
2422 static void
ficlPrimitiveDoFLocalIm(ficlVm * vm)2423 ficlPrimitiveDoFLocalIm(ficlVm *vm)
2424 {
2425 ficlLocalParenIm(vm, 0, 1);
2426 }
2427
2428 static void
ficlPrimitiveDoF2LocalIm(ficlVm * vm)2429 ficlPrimitiveDoF2LocalIm(ficlVm *vm)
2430 {
2431 ficlLocalParenIm(vm, 1, 1);
2432 }
2433 #endif /* FICL_WANT_FLOAT */
2434
2435 /*
2436 * l o c a l P a r e n
2437 * paren-local-paren LOCAL
2438 * Interpretation: Interpretation semantics for this word are undefined.
2439 * Execution: ( c-addr u -- )
2440 * When executed during compilation, (LOCAL) passes a message to the
2441 * system that has one of two meanings. If u is non-zero,
2442 * the message identifies a new local whose definition name is given by
2443 * the string of characters identified by c-addr u. If u is zero,
2444 * the message is last local and c-addr has no significance.
2445 *
2446 * The result of executing (LOCAL) during compilation of a definition is
2447 * to create a set of named local identifiers, each of which is
2448 * a definition name, that only have execution semantics within the scope
2449 * of that definition's source.
2450 *
2451 * local Execution: ( -- x )
2452 *
2453 * Push the local's value, x, onto the stack. The local's value is
2454 * initialized as described in 13.3.3 Processing locals and may be
2455 * changed by preceding the local's name with TO. An ambiguous condition
2456 * exists when local is executed while in interpretation state.
2457 */
2458 void
ficlLocalParen(ficlVm * vm,int isDouble,int isFloat)2459 ficlLocalParen(ficlVm *vm, int isDouble, int isFloat)
2460 {
2461 ficlDictionary *dictionary;
2462 ficlString name;
2463
2464 FICL_STACK_CHECK(vm->dataStack, 2, 0);
2465
2466 dictionary = ficlVmGetDictionary(vm);
2467 FICL_STRING_SET_LENGTH(name, ficlStackPopUnsigned(vm->dataStack));
2468 FICL_STRING_SET_POINTER(name,
2469 (char *)ficlStackPopPointer(vm->dataStack));
2470
2471 if (FICL_STRING_GET_LENGTH(name) > 0) {
2472 /*
2473 * add a local to the **locals** dictionary and
2474 * update localsCount
2475 */
2476 ficlPrimitive code;
2477 ficlInstruction instruction;
2478 ficlDictionary *locals;
2479
2480 locals = ficlSystemGetLocals(vm->callback.system);
2481 if (vm->callback.system->localsCount >= FICL_MAX_LOCALS) {
2482 ficlVmThrowError(vm, "Error: out of local space");
2483 }
2484
2485 #if !FICL_WANT_FLOAT
2486 FICL_VM_ASSERT(vm, !isFloat);
2487 /* get rid of unused parameter warning */
2488 isFloat = 0;
2489 #else /* FICL_WANT_FLOAT */
2490 if (isFloat) {
2491 if (isDouble) {
2492 code = ficlPrimitiveDoF2LocalIm;
2493 instruction = ficlInstructionToF2LocalParen;
2494 } else {
2495 code = ficlPrimitiveDoFLocalIm;
2496 instruction = ficlInstructionToFLocalParen;
2497 }
2498 } else
2499 #endif /* FICL_WANT_FLOAT */
2500 if (isDouble) {
2501 code = ficlPrimitiveDo2LocalIm;
2502 instruction = ficlInstructionTo2LocalParen;
2503 } else {
2504 code = ficlPrimitiveDoLocalIm;
2505 instruction = ficlInstructionToLocalParen;
2506 }
2507
2508 ficlDictionaryAppendWord(locals, name, code,
2509 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
2510 ficlDictionaryAppendUnsigned(locals,
2511 vm->callback.system->localsCount);
2512
2513 if (vm->callback.system->localsCount == 0) {
2514 /*
2515 * FICL_VM_STATE_COMPILE code to create a local
2516 * stack frame
2517 */
2518 ficlDictionaryAppendUnsigned(dictionary,
2519 ficlInstructionLinkParen);
2520
2521 /* save location in dictionary for #locals */
2522 vm->callback.system->localsFixup = dictionary->here;
2523 ficlDictionaryAppendUnsigned(dictionary,
2524 vm->callback.system->localsCount);
2525 }
2526
2527 ficlDictionaryAppendUnsigned(dictionary, instruction);
2528 ficlDictionaryAppendUnsigned(dictionary,
2529 vm->callback.system->localsCount);
2530
2531 vm->callback.system->localsCount += (isDouble) ? 2 : 1;
2532 } else if (vm->callback.system->localsCount > 0) {
2533 /* write localsCount to (link) param area in dictionary */
2534 *(ficlInteger *)(vm->callback.system->localsFixup) =
2535 vm->callback.system->localsCount;
2536 }
2537 }
2538
2539 static void
ficlPrimitiveLocalParen(ficlVm * vm)2540 ficlPrimitiveLocalParen(ficlVm *vm)
2541 {
2542 ficlLocalParen(vm, 0, 0);
2543 }
2544
2545 static void
ficlPrimitive2LocalParen(ficlVm * vm)2546 ficlPrimitive2LocalParen(ficlVm *vm)
2547 {
2548 ficlLocalParen(vm, 1, 0);
2549 }
2550 #endif /* FICL_WANT_LOCALS */
2551
2552 /*
2553 * t o V a l u e
2554 * CORE EXT
2555 * Interpretation: ( x "<spaces>name" -- )
2556 * Skip leading spaces and parse name delimited by a space. Store x in
2557 * name. An ambiguous condition exists if name was not defined by VALUE.
2558 * NOTE: In Ficl, VALUE is an alias of CONSTANT
2559 */
2560 static void
ficlPrimitiveToValue(ficlVm * vm)2561 ficlPrimitiveToValue(ficlVm *vm)
2562 {
2563 ficlString name = ficlVmGetWord(vm);
2564 ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2565 ficlWord *word;
2566 ficlInstruction instruction = 0;
2567 ficlStack *stack;
2568 ficlInteger isDouble;
2569 #if FICL_WANT_LOCALS
2570 ficlInteger nLocal;
2571 ficlInteger appendLocalOffset;
2572 ficlInteger isFloat;
2573 #endif /* FICL_WANT_LOCALS */
2574
2575 #if FICL_WANT_LOCALS
2576 if ((vm->callback.system->localsCount > 0) &&
2577 (vm->state == FICL_VM_STATE_COMPILE)) {
2578 ficlDictionary *locals;
2579
2580 locals = ficlSystemGetLocals(vm->callback.system);
2581 word = ficlDictionaryLookup(locals, name);
2582 if (!word)
2583 goto TO_GLOBAL;
2584
2585 if (word->code == ficlPrimitiveDoLocalIm) {
2586 instruction = ficlInstructionToLocalParen;
2587 isDouble = isFloat = FICL_FALSE;
2588 } else if (word->code == ficlPrimitiveDo2LocalIm) {
2589 instruction = ficlInstructionTo2LocalParen;
2590 isDouble = FICL_TRUE;
2591 isFloat = FICL_FALSE;
2592 }
2593 #if FICL_WANT_FLOAT
2594 else if (word->code == ficlPrimitiveDoFLocalIm) {
2595 instruction = ficlInstructionToFLocalParen;
2596 isDouble = FICL_FALSE;
2597 isFloat = FICL_TRUE;
2598 } else if (word->code == ficlPrimitiveDoF2LocalIm) {
2599 instruction = ficlInstructionToF2LocalParen;
2600 isDouble = isFloat = FICL_TRUE;
2601 }
2602 #endif /* FICL_WANT_FLOAT */
2603 else {
2604 ficlVmThrowError(vm,
2605 "to %.*s : local is of unknown type",
2606 FICL_STRING_GET_LENGTH(name),
2607 FICL_STRING_GET_POINTER(name));
2608 return;
2609 }
2610
2611 nLocal = word->param[0].i;
2612 appendLocalOffset = FICL_TRUE;
2613
2614 #if FICL_WANT_FLOAT
2615 if (!isFloat) {
2616 #endif /* FICL_WANT_FLOAT */
2617 if (nLocal == 0) {
2618 instruction =
2619 (isDouble) ? ficlInstructionTo2Local0 :
2620 ficlInstructionToLocal0;
2621 appendLocalOffset = FICL_FALSE;
2622 } else if ((nLocal == 1) && !isDouble) {
2623 instruction = ficlInstructionToLocal1;
2624 appendLocalOffset = FICL_FALSE;
2625 }
2626 #if FICL_WANT_FLOAT
2627 }
2628 #endif /* FICL_WANT_FLOAT */
2629
2630 ficlDictionaryAppendUnsigned(dictionary, instruction);
2631 if (appendLocalOffset)
2632 ficlDictionaryAppendUnsigned(dictionary, nLocal);
2633 return;
2634 }
2635 #endif
2636
2637 #if FICL_WANT_LOCALS
2638 TO_GLOBAL:
2639 #endif /* FICL_WANT_LOCALS */
2640 word = ficlDictionaryLookup(dictionary, name);
2641 if (!word)
2642 ficlVmThrowError(vm, "%.*s not found",
2643 FICL_STRING_GET_LENGTH(name),
2644 FICL_STRING_GET_POINTER(name));
2645
2646 switch ((ficlInstruction)word->code) {
2647 case ficlInstructionConstantParen:
2648 instruction = ficlInstructionStore;
2649 stack = vm->dataStack;
2650 isDouble = FICL_FALSE;
2651 break;
2652 case ficlInstruction2ConstantParen:
2653 instruction = ficlInstruction2Store;
2654 stack = vm->dataStack;
2655 isDouble = FICL_TRUE;
2656 break;
2657 #if FICL_WANT_FLOAT
2658 case ficlInstructionFConstantParen:
2659 instruction = ficlInstructionFStore;
2660 stack = vm->floatStack;
2661 isDouble = FICL_FALSE;
2662 break;
2663 case ficlInstructionF2ConstantParen:
2664 instruction = ficlInstructionF2Store;
2665 stack = vm->floatStack;
2666 isDouble = FICL_TRUE;
2667 break;
2668 #endif /* FICL_WANT_FLOAT */
2669 default:
2670 ficlVmThrowError(vm,
2671 "to %.*s : value/constant is of unknown type",
2672 FICL_STRING_GET_LENGTH(name),
2673 FICL_STRING_GET_POINTER(name));
2674 return;
2675 }
2676
2677 if (vm->state == FICL_VM_STATE_INTERPRET) {
2678 word->param[0] = ficlStackPop(stack);
2679 if (isDouble)
2680 word->param[1] = ficlStackPop(stack);
2681 } else {
2682 /* FICL_VM_STATE_COMPILE code to store to word's param */
2683 ficlStackPushPointer(vm->dataStack, &word->param[0]);
2684 ficlPrimitiveLiteralIm(vm);
2685 ficlDictionaryAppendUnsigned(dictionary, instruction);
2686 }
2687 }
2688
2689 /*
2690 * f m S l a s h M o d
2691 * f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
2692 * Divide d1 by n1, giving the floored quotient n3 and the remainder n2.
2693 * Input and output stack arguments are signed. An ambiguous condition
2694 * exists if n1 is zero or if the quotient lies outside the range of a
2695 * single-ficlCell signed integer.
2696 */
2697 static void
ficlPrimitiveFMSlashMod(ficlVm * vm)2698 ficlPrimitiveFMSlashMod(ficlVm *vm)
2699 {
2700 ficl2Integer d1;
2701 ficlInteger n1;
2702 ficl2IntegerQR qr;
2703
2704 FICL_STACK_CHECK(vm->dataStack, 3, 2);
2705
2706 n1 = ficlStackPopInteger(vm->dataStack);
2707 d1 = ficlStackPop2Integer(vm->dataStack);
2708 qr = ficl2IntegerDivideFloored(d1, n1);
2709 ficlStackPushInteger(vm->dataStack, qr.remainder);
2710 ficlStackPushInteger(vm->dataStack,
2711 FICL_2UNSIGNED_GET_LOW(qr.quotient));
2712 }
2713
2714 /*
2715 * s m S l a s h R e m
2716 * s-m-slash-remainder CORE ( d1 n1 -- n2 n3 )
2717 * Divide d1 by n1, giving the symmetric quotient n3 and the remainder n2.
2718 * Input and output stack arguments are signed. An ambiguous condition
2719 * exists if n1 is zero or if the quotient lies outside the range of a
2720 * single-ficlCell signed integer.
2721 */
2722 static void
ficlPrimitiveSMSlashRem(ficlVm * vm)2723 ficlPrimitiveSMSlashRem(ficlVm *vm)
2724 {
2725 ficl2Integer d1;
2726 ficlInteger n1;
2727 ficl2IntegerQR qr;
2728
2729 FICL_STACK_CHECK(vm->dataStack, 3, 2);
2730
2731 n1 = ficlStackPopInteger(vm->dataStack);
2732 d1 = ficlStackPop2Integer(vm->dataStack);
2733 qr = ficl2IntegerDivideSymmetric(d1, n1);
2734 ficlStackPushInteger(vm->dataStack, qr.remainder);
2735 ficlStackPushInteger(vm->dataStack,
2736 FICL_2UNSIGNED_GET_LOW(qr.quotient));
2737 }
2738
2739 static void
ficlPrimitiveMod(ficlVm * vm)2740 ficlPrimitiveMod(ficlVm *vm)
2741 {
2742 ficl2Integer d1;
2743 ficlInteger n1;
2744 ficlInteger i;
2745 ficl2IntegerQR qr;
2746 FICL_STACK_CHECK(vm->dataStack, 2, 1);
2747
2748 n1 = ficlStackPopInteger(vm->dataStack);
2749 i = ficlStackPopInteger(vm->dataStack);
2750 FICL_INTEGER_TO_2INTEGER(i, d1);
2751 qr = ficl2IntegerDivideSymmetric(d1, n1);
2752 ficlStackPushInteger(vm->dataStack, qr.remainder);
2753 }
2754
2755 /*
2756 * u m S l a s h M o d
2757 * u-m-slash-mod CORE ( ud u1 -- u2 u3 )
2758 * Divide ud by u1, giving the quotient u3 and the remainder u2.
2759 * All values and arithmetic are unsigned. An ambiguous condition
2760 * exists if u1 is zero or if the quotient lies outside the range of a
2761 * single-ficlCell unsigned integer.
2762 */
2763 static void
ficlPrimitiveUMSlashMod(ficlVm * vm)2764 ficlPrimitiveUMSlashMod(ficlVm *vm)
2765 {
2766 ficl2Unsigned ud;
2767 ficlUnsigned u1;
2768 ficl2UnsignedQR uqr;
2769
2770 u1 = ficlStackPopUnsigned(vm->dataStack);
2771 ud = ficlStackPop2Unsigned(vm->dataStack);
2772 uqr = ficl2UnsignedDivide(ud, u1);
2773 ficlStackPushUnsigned(vm->dataStack, uqr.remainder);
2774 ficlStackPushUnsigned(vm->dataStack,
2775 FICL_2UNSIGNED_GET_LOW(uqr.quotient));
2776 }
2777
2778 /*
2779 * m S t a r
2780 * m-star CORE ( n1 n2 -- d )
2781 * d is the signed product of n1 times n2.
2782 */
2783 static void
ficlPrimitiveMStar(ficlVm * vm)2784 ficlPrimitiveMStar(ficlVm *vm)
2785 {
2786 ficlInteger n2;
2787 ficlInteger n1;
2788 ficl2Integer d;
2789 FICL_STACK_CHECK(vm->dataStack, 2, 2);
2790
2791 n2 = ficlStackPopInteger(vm->dataStack);
2792 n1 = ficlStackPopInteger(vm->dataStack);
2793
2794 d = ficl2IntegerMultiply(n1, n2);
2795 ficlStackPush2Integer(vm->dataStack, d);
2796 }
2797
2798 static void
ficlPrimitiveUMStar(ficlVm * vm)2799 ficlPrimitiveUMStar(ficlVm *vm)
2800 {
2801 ficlUnsigned u2;
2802 ficlUnsigned u1;
2803 ficl2Unsigned ud;
2804 FICL_STACK_CHECK(vm->dataStack, 2, 2);
2805
2806 u2 = ficlStackPopUnsigned(vm->dataStack);
2807 u1 = ficlStackPopUnsigned(vm->dataStack);
2808
2809 ud = ficl2UnsignedMultiply(u1, u2);
2810 ficlStackPush2Unsigned(vm->dataStack, ud);
2811 }
2812
2813 /*
2814 * 2 r o t
2815 * DOUBLE ( d1 d2 d3 -- d2 d3 d1 )
2816 */
2817 static void
ficlPrimitive2Rot(ficlVm * vm)2818 ficlPrimitive2Rot(ficlVm *vm)
2819 {
2820 ficl2Integer d1, d2, d3;
2821 FICL_STACK_CHECK(vm->dataStack, 6, 6);
2822
2823 d3 = ficlStackPop2Integer(vm->dataStack);
2824 d2 = ficlStackPop2Integer(vm->dataStack);
2825 d1 = ficlStackPop2Integer(vm->dataStack);
2826 ficlStackPush2Integer(vm->dataStack, d2);
2827 ficlStackPush2Integer(vm->dataStack, d3);
2828 ficlStackPush2Integer(vm->dataStack, d1);
2829 }
2830
2831 /*
2832 * p a d
2833 * CORE EXT ( -- c-addr )
2834 * c-addr is the address of a transient region that can be used to hold
2835 * data for intermediate processing.
2836 */
2837 static void
ficlPrimitivePad(ficlVm * vm)2838 ficlPrimitivePad(ficlVm *vm)
2839 {
2840 ficlStackPushPointer(vm->dataStack, vm->pad);
2841 }
2842
2843 /*
2844 * s o u r c e - i d
2845 * CORE EXT, FILE ( -- 0 | -1 | fileid )
2846 * Identifies the input source as follows:
2847 *
2848 * SOURCE-ID Input source
2849 * --------- ------------
2850 * fileid Text file fileid
2851 * -1 String (via EVALUATE)
2852 * 0 User input device
2853 */
2854 static void
ficlPrimitiveSourceID(ficlVm * vm)2855 ficlPrimitiveSourceID(ficlVm *vm)
2856 {
2857 ficlStackPushInteger(vm->dataStack, vm->sourceId.i);
2858 }
2859
2860 /*
2861 * r e f i l l
2862 * CORE EXT ( -- flag )
2863 * Attempt to fill the input buffer from the input source, returning
2864 * a FICL_TRUE flag if successful.
2865 * When the input source is the user input device, attempt to receive input
2866 * into the terminal input buffer. If successful, make the result the input
2867 * buffer, set >IN to zero, and return FICL_TRUE. Receipt of a line containing
2868 * no characters is considered successful. If there is no input available from
2869 * the current input source, return FICL_FALSE.
2870 * When the input source is a string from EVALUATE, return FICL_FALSE and
2871 * perform no other action.
2872 */
2873 static void
ficlPrimitiveRefill(ficlVm * vm)2874 ficlPrimitiveRefill(ficlVm *vm)
2875 {
2876 ficlInteger ret = (vm->sourceId.i == -1) ? FICL_FALSE : FICL_TRUE;
2877 if (ret && (vm->restart == 0))
2878 ficlVmThrow(vm, FICL_VM_STATUS_RESTART);
2879
2880 ficlStackPushInteger(vm->dataStack, ret);
2881 }
2882
2883 /*
2884 * freebsd exception handling words
2885 * Catch, from ANS Forth standard. Installs a safety net, then EXECUTE
2886 * the word in ToS. If an exception happens, restore the state to what
2887 * it was before, and pushes the exception value on the stack. If not,
2888 * push zero.
2889 *
2890 * Notice that Catch implements an inner interpreter. This is ugly,
2891 * but given how Ficl works, it cannot be helped. The problem is that
2892 * colon definitions will be executed *after* the function returns,
2893 * while "code" definitions will be executed immediately. I considered
2894 * other solutions to this problem, but all of them shared the same
2895 * basic problem (with added disadvantages): if Ficl ever changes it's
2896 * inner thread modus operandi, one would have to fix this word.
2897 *
2898 * More comments can be found throughout catch's code.
2899 *
2900 * Daniel C. Sobral Jan 09/1999
2901 * sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
2902 */
2903 static void
ficlPrimitiveCatch(ficlVm * vm)2904 ficlPrimitiveCatch(ficlVm *vm)
2905 {
2906 int except;
2907 jmp_buf vmState;
2908 ficlVm vmCopy;
2909 ficlStack dataStackCopy;
2910 ficlStack returnStackCopy;
2911 ficlWord *word;
2912
2913 FICL_VM_ASSERT(vm, vm);
2914 FICL_VM_ASSERT(vm, vm->callback.system->exitInnerWord);
2915
2916 /*
2917 * Get xt.
2918 * We need this *before* we save the stack pointer, or
2919 * we'll have to pop one element out of the stack after
2920 * an exception. I prefer to get done with it up front. :-)
2921 */
2922
2923 FICL_STACK_CHECK(vm->dataStack, 1, 0);
2924
2925 word = ficlStackPopPointer(vm->dataStack);
2926
2927 /*
2928 * Save vm's state -- a catch will not back out environmental
2929 * changes.
2930 *
2931 * We are *not* saving dictionary state, since it is
2932 * global instead of per vm, and we are not saving
2933 * stack contents, since we are not required to (and,
2934 * thus, it would be useless). We save vm, and vm
2935 * "stacks" (a structure containing general information
2936 * about it, including the current stack pointer).
2937 */
2938 memcpy((void*)&vmCopy, (void*)vm, sizeof (ficlVm));
2939 memcpy((void*)&dataStackCopy, (void*)vm->dataStack, sizeof (ficlStack));
2940 memcpy((void*)&returnStackCopy, (void*)vm->returnStack,
2941 sizeof (ficlStack));
2942
2943 /*
2944 * Give vm a jmp_buf
2945 */
2946 vm->exceptionHandler = &vmState;
2947
2948 /*
2949 * Safety net
2950 */
2951 except = setjmp(vmState);
2952
2953 switch (except) {
2954 /*
2955 * Setup condition - push poison pill so that the VM throws
2956 * VM_INNEREXIT if the XT terminates normally, then execute
2957 * the XT
2958 */
2959 case 0:
2960 /* Open mouth, insert emetic */
2961 ficlVmPushIP(vm, &(vm->callback.system->exitInnerWord));
2962 ficlVmExecuteWord(vm, word);
2963 ficlVmInnerLoop(vm, 0);
2964 break;
2965
2966 /*
2967 * Normal exit from XT - lose the poison pill,
2968 * restore old setjmp vector and push a zero.
2969 */
2970 case FICL_VM_STATUS_INNER_EXIT:
2971 ficlVmPopIP(vm); /* Gack - hurl poison pill */
2972 /* Restore just the setjmp vector */
2973 vm->exceptionHandler = vmCopy.exceptionHandler;
2974 /* Push 0 -- everything is ok */
2975 ficlStackPushInteger(vm->dataStack, 0);
2976 break;
2977
2978 /*
2979 * Some other exception got thrown - restore pre-existing VM state
2980 * and push the exception code
2981 */
2982 default:
2983 /* Restore vm's state */
2984 memcpy((void*)vm, (void*)&vmCopy, sizeof (ficlVm));
2985 memcpy((void*)vm->dataStack, (void*)&dataStackCopy,
2986 sizeof (ficlStack));
2987 memcpy((void*)vm->returnStack, (void*)&returnStackCopy,
2988 sizeof (ficlStack));
2989
2990 ficlStackPushInteger(vm->dataStack, except); /* Push error */
2991 break;
2992 }
2993 }
2994
2995 /*
2996 * t h r o w
2997 * EXCEPTION
2998 * Throw -- From ANS Forth standard.
2999 *
3000 * Throw takes the ToS and, if that's different from zero,
3001 * returns to the last executed catch context. Further throws will
3002 * unstack previously executed "catches", in LIFO mode.
3003 *
3004 * Daniel C. Sobral Jan 09/1999
3005 */
3006 static void
ficlPrimitiveThrow(ficlVm * vm)3007 ficlPrimitiveThrow(ficlVm *vm)
3008 {
3009 int except;
3010
3011 except = ficlStackPopInteger(vm->dataStack);
3012
3013 if (except)
3014 ficlVmThrow(vm, except);
3015 }
3016
3017 /*
3018 * a l l o c a t e
3019 * MEMORY
3020 */
3021 static void
ficlPrimitiveAllocate(ficlVm * vm)3022 ficlPrimitiveAllocate(ficlVm *vm)
3023 {
3024 size_t size;
3025 void *p;
3026
3027 size = ficlStackPopInteger(vm->dataStack);
3028 p = ficlMalloc(size);
3029 ficlStackPushPointer(vm->dataStack, p);
3030 if (p != NULL)
3031 ficlStackPushInteger(vm->dataStack, 0);
3032 else
3033 ficlStackPushInteger(vm->dataStack, 1);
3034 }
3035
3036 /*
3037 * f r e e
3038 * MEMORY
3039 */
3040 static void
ficlPrimitiveFree(ficlVm * vm)3041 ficlPrimitiveFree(ficlVm *vm)
3042 {
3043 void *p;
3044
3045 p = ficlStackPopPointer(vm->dataStack);
3046 ficlFree(p);
3047 ficlStackPushInteger(vm->dataStack, 0);
3048 }
3049
3050 /*
3051 * r e s i z e
3052 * MEMORY
3053 */
3054 static void
ficlPrimitiveResize(ficlVm * vm)3055 ficlPrimitiveResize(ficlVm *vm)
3056 {
3057 size_t size;
3058 void *new, *old;
3059
3060 size = ficlStackPopInteger(vm->dataStack);
3061 old = ficlStackPopPointer(vm->dataStack);
3062 new = ficlRealloc(old, size);
3063
3064 if (new) {
3065 ficlStackPushPointer(vm->dataStack, new);
3066 ficlStackPushInteger(vm->dataStack, 0);
3067 } else {
3068 ficlStackPushPointer(vm->dataStack, old);
3069 ficlStackPushInteger(vm->dataStack, 1);
3070 }
3071 }
3072
3073 /*
3074 * e x i t - i n n e r
3075 * Signals execXT that an inner loop has completed
3076 */
3077 static void
ficlPrimitiveExitInner(ficlVm * vm)3078 ficlPrimitiveExitInner(ficlVm *vm)
3079 {
3080 ficlVmThrow(vm, FICL_VM_STATUS_INNER_EXIT);
3081 }
3082
3083 #if 0
3084 static void
3085 ficlPrimitiveName(ficlVm *vm)
3086 {
3087 FICL_IGNORE(vm);
3088 }
3089 #endif
3090
3091 /*
3092 * f i c l C o m p i l e C o r e
3093 * Builds the primitive wordset and the environment-query namespace.
3094 */
3095 void
ficlSystemCompileCore(ficlSystem * system)3096 ficlSystemCompileCore(ficlSystem *system)
3097 {
3098 ficlWord *interpret;
3099 ficlDictionary *dictionary = ficlSystemGetDictionary(system);
3100 ficlDictionary *environment = ficlSystemGetEnvironment(system);
3101
3102 FICL_SYSTEM_ASSERT(system, dictionary);
3103 FICL_SYSTEM_ASSERT(system, environment);
3104
3105 #define FICL_TOKEN(token, description)
3106 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \
3107 ficlDictionarySetInstruction(dictionary, description, token, flags);
3108 #include "ficltokens.h"
3109 #undef FICL_TOKEN
3110 #undef FICL_INSTRUCTION_TOKEN
3111
3112 /*
3113 * The Core word set
3114 * see softcore.c for definitions of: abs bl space spaces abort"
3115 */
3116 ficlDictionarySetPrimitive(dictionary, "#", ficlPrimitiveNumberSign,
3117 FICL_WORD_DEFAULT);
3118 ficlDictionarySetPrimitive(dictionary, "#>",
3119 ficlPrimitiveNumberSignGreater, FICL_WORD_DEFAULT);
3120 ficlDictionarySetPrimitive(dictionary, "#s", ficlPrimitiveNumberSignS,
3121 FICL_WORD_DEFAULT);
3122 ficlDictionarySetPrimitive(dictionary, "\'", ficlPrimitiveTick,
3123 FICL_WORD_DEFAULT);
3124 ficlDictionarySetPrimitive(dictionary, "(", ficlPrimitiveParenthesis,
3125 FICL_WORD_IMMEDIATE);
3126 ficlDictionarySetPrimitive(dictionary, "+loop",
3127 ficlPrimitivePlusLoopCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3128 ficlDictionarySetPrimitive(dictionary, ".", ficlPrimitiveDot,
3129 FICL_WORD_DEFAULT);
3130 ficlDictionarySetPrimitive(dictionary, ".\"",
3131 ficlPrimitiveDotQuoteCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3132 ficlDictionarySetPrimitive(dictionary, ":", ficlPrimitiveColon,
3133 FICL_WORD_DEFAULT);
3134 ficlDictionarySetPrimitive(dictionary, ";", ficlPrimitiveSemicolonCoIm,
3135 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3136 ficlDictionarySetPrimitive(dictionary, "<#",
3137 ficlPrimitiveLessNumberSign, FICL_WORD_DEFAULT);
3138 ficlDictionarySetPrimitive(dictionary, ">body", ficlPrimitiveToBody,
3139 FICL_WORD_DEFAULT);
3140 ficlDictionarySetPrimitive(dictionary, ">in", ficlPrimitiveToIn,
3141 FICL_WORD_DEFAULT);
3142 ficlDictionarySetPrimitive(dictionary, ">number", ficlPrimitiveToNumber,
3143 FICL_WORD_DEFAULT);
3144 ficlDictionarySetPrimitive(dictionary, "abort", ficlPrimitiveAbort,
3145 FICL_WORD_DEFAULT);
3146 ficlDictionarySetPrimitive(dictionary, "accept", ficlPrimitiveAccept,
3147 FICL_WORD_DEFAULT);
3148 ficlDictionarySetPrimitive(dictionary, "align", ficlPrimitiveAlign,
3149 FICL_WORD_DEFAULT);
3150 ficlDictionarySetPrimitive(dictionary, "aligned", ficlPrimitiveAligned,
3151 FICL_WORD_DEFAULT);
3152 ficlDictionarySetPrimitive(dictionary, "allot", ficlPrimitiveAllot,
3153 FICL_WORD_DEFAULT);
3154 ficlDictionarySetPrimitive(dictionary, "base", ficlPrimitiveBase,
3155 FICL_WORD_DEFAULT);
3156 ficlDictionarySetPrimitive(dictionary, "begin", ficlPrimitiveBeginCoIm,
3157 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3158 ficlDictionarySetPrimitive(dictionary, "case", ficlPrimitiveCaseCoIm,
3159 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3160 ficlDictionarySetPrimitive(dictionary, "char", ficlPrimitiveChar,
3161 FICL_WORD_DEFAULT);
3162 ficlDictionarySetPrimitive(dictionary, "char+", ficlPrimitiveCharPlus,
3163 FICL_WORD_DEFAULT);
3164 ficlDictionarySetPrimitive(dictionary, "chars", ficlPrimitiveChars,
3165 FICL_WORD_DEFAULT);
3166 ficlDictionarySetPrimitive(dictionary, "constant",
3167 ficlPrimitiveConstant, FICL_WORD_DEFAULT);
3168 ficlDictionarySetPrimitive(dictionary, "count", ficlPrimitiveCount,
3169 FICL_WORD_DEFAULT);
3170 ficlDictionarySetPrimitive(dictionary, "cr", ficlPrimitiveCR,
3171 FICL_WORD_DEFAULT);
3172 ficlDictionarySetPrimitive(dictionary, "create", ficlPrimitiveCreate,
3173 FICL_WORD_DEFAULT);
3174 ficlDictionarySetPrimitive(dictionary, "decimal", ficlPrimitiveDecimal,
3175 FICL_WORD_DEFAULT);
3176 ficlDictionarySetPrimitive(dictionary, "depth", ficlPrimitiveDepth,
3177 FICL_WORD_DEFAULT);
3178 ficlDictionarySetPrimitive(dictionary, "do", ficlPrimitiveDoCoIm,
3179 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3180 ficlDictionarySetPrimitive(dictionary, "does>", ficlPrimitiveDoesCoIm,
3181 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3182 ficlDictionarySetPrimitive(dictionary, "else", ficlPrimitiveElseCoIm,
3183 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3184 ficlDictionarySetPrimitive(dictionary, "emit", ficlPrimitiveEmit,
3185 FICL_WORD_DEFAULT);
3186 ficlDictionarySetPrimitive(dictionary, "endcase",
3187 ficlPrimitiveEndcaseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3188 ficlDictionarySetPrimitive(dictionary, "endof", ficlPrimitiveEndofCoIm,
3189 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3190 ficlDictionarySetPrimitive(dictionary, "environment?",
3191 ficlPrimitiveEnvironmentQ, FICL_WORD_DEFAULT);
3192 ficlDictionarySetPrimitive(dictionary, "evaluate",
3193 ficlPrimitiveEvaluate, FICL_WORD_DEFAULT);
3194 ficlDictionarySetPrimitive(dictionary, "execute", ficlPrimitiveExecute,
3195 FICL_WORD_DEFAULT);
3196 ficlDictionarySetPrimitive(dictionary, "exit", ficlPrimitiveExitCoIm,
3197 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3198 ficlDictionarySetPrimitive(dictionary, "fallthrough",
3199 ficlPrimitiveFallthroughCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3200 ficlDictionarySetPrimitive(dictionary, "find", ficlPrimitiveCFind,
3201 FICL_WORD_DEFAULT);
3202 ficlDictionarySetPrimitive(dictionary, "fm/mod",
3203 ficlPrimitiveFMSlashMod, FICL_WORD_DEFAULT);
3204 ficlDictionarySetPrimitive(dictionary, "here", ficlPrimitiveHere,
3205 FICL_WORD_DEFAULT);
3206 ficlDictionarySetPrimitive(dictionary, "hold", ficlPrimitiveHold,
3207 FICL_WORD_DEFAULT);
3208 ficlDictionarySetPrimitive(dictionary, "if", ficlPrimitiveIfCoIm,
3209 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3210 ficlDictionarySetPrimitive(dictionary, "immediate",
3211 ficlPrimitiveImmediate, FICL_WORD_DEFAULT);
3212 ficlDictionarySetPrimitive(dictionary, "literal",
3213 ficlPrimitiveLiteralIm, FICL_WORD_IMMEDIATE);
3214 ficlDictionarySetPrimitive(dictionary, "loop", ficlPrimitiveLoopCoIm,
3215 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3216 ficlDictionarySetPrimitive(dictionary, "m*", ficlPrimitiveMStar,
3217 FICL_WORD_DEFAULT);
3218 ficlDictionarySetPrimitive(dictionary, "mod", ficlPrimitiveMod,
3219 FICL_WORD_DEFAULT);
3220 ficlDictionarySetPrimitive(dictionary, "of", ficlPrimitiveOfCoIm,
3221 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3222 ficlDictionarySetPrimitive(dictionary, "postpone",
3223 ficlPrimitivePostponeCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3224 ficlDictionarySetPrimitive(dictionary, "quit", ficlPrimitiveQuit,
3225 FICL_WORD_DEFAULT);
3226 ficlDictionarySetPrimitive(dictionary, "recurse",
3227 ficlPrimitiveRecurseCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3228 ficlDictionarySetPrimitive(dictionary, "repeat",
3229 ficlPrimitiveRepeatCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3230 ficlDictionarySetPrimitive(dictionary, "s\"",
3231 ficlPrimitiveStringQuoteIm, FICL_WORD_IMMEDIATE);
3232 ficlDictionarySetPrimitive(dictionary, "sign", ficlPrimitiveSign,
3233 FICL_WORD_DEFAULT);
3234 ficlDictionarySetPrimitive(dictionary, "sm/rem",
3235 ficlPrimitiveSMSlashRem, FICL_WORD_DEFAULT);
3236 ficlDictionarySetPrimitive(dictionary, "source", ficlPrimitiveSource,
3237 FICL_WORD_DEFAULT);
3238 ficlDictionarySetPrimitive(dictionary, "state", ficlPrimitiveState,
3239 FICL_WORD_DEFAULT);
3240 ficlDictionarySetPrimitive(dictionary, "then", ficlPrimitiveEndifCoIm,
3241 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3242 ficlDictionarySetPrimitive(dictionary, "type", ficlPrimitiveType,
3243 FICL_WORD_DEFAULT);
3244 ficlDictionarySetPrimitive(dictionary, "u.", ficlPrimitiveUDot,
3245 FICL_WORD_DEFAULT);
3246 ficlDictionarySetPrimitive(dictionary, "um*", ficlPrimitiveUMStar,
3247 FICL_WORD_DEFAULT);
3248 ficlDictionarySetPrimitive(dictionary, "um/mod",
3249 ficlPrimitiveUMSlashMod, FICL_WORD_DEFAULT);
3250 ficlDictionarySetPrimitive(dictionary, "until",
3251 ficlPrimitiveUntilCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3252 ficlDictionarySetPrimitive(dictionary, "variable",
3253 ficlPrimitiveVariable, FICL_WORD_DEFAULT);
3254 ficlDictionarySetPrimitive(dictionary, "while",
3255 ficlPrimitiveWhileCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3256 ficlDictionarySetPrimitive(dictionary, "word", ficlPrimitiveWord,
3257 FICL_WORD_DEFAULT);
3258 ficlDictionarySetPrimitive(dictionary, "[",
3259 ficlPrimitiveLeftBracketCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3260 ficlDictionarySetPrimitive(dictionary, "[\']",
3261 ficlPrimitiveBracketTickCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3262 ficlDictionarySetPrimitive(dictionary, "[char]", ficlPrimitiveCharCoIm,
3263 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3264 ficlDictionarySetPrimitive(dictionary, "]", ficlPrimitiveRightBracket,
3265 FICL_WORD_DEFAULT);
3266 /*
3267 * The Core Extensions word set...
3268 * see softcore.fr for other definitions
3269 */
3270 /* "#tib" */
3271 ficlDictionarySetPrimitive(dictionary, ".(", ficlPrimitiveDotParen,
3272 FICL_WORD_IMMEDIATE);
3273 /* ".r" is in softcore */
3274 ficlDictionarySetPrimitive(dictionary, ":noname",
3275 ficlPrimitiveColonNoName, FICL_WORD_DEFAULT);
3276 ficlDictionarySetPrimitive(dictionary, "?do", ficlPrimitiveQDoCoIm,
3277 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3278 ficlDictionarySetPrimitive(dictionary, "again", ficlPrimitiveAgainCoIm,
3279 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3280 ficlDictionarySetPrimitive(dictionary, "c\"",
3281 ficlPrimitiveCountedStringQuoteIm, FICL_WORD_IMMEDIATE);
3282 ficlDictionarySetPrimitive(dictionary, "hex", ficlPrimitiveHex,
3283 FICL_WORD_DEFAULT);
3284 ficlDictionarySetPrimitive(dictionary, "pad", ficlPrimitivePad,
3285 FICL_WORD_DEFAULT);
3286 ficlDictionarySetPrimitive(dictionary, "parse", ficlPrimitiveParse,
3287 FICL_WORD_DEFAULT);
3288
3289 /*
3290 * query restore-input save-input tib u.r u> unused
3291 * [FICL_VM_STATE_COMPILE]
3292 */
3293 ficlDictionarySetPrimitive(dictionary, "refill", ficlPrimitiveRefill,
3294 FICL_WORD_DEFAULT);
3295 ficlDictionarySetPrimitive(dictionary, "source-id",
3296 ficlPrimitiveSourceID, FICL_WORD_DEFAULT);
3297 ficlDictionarySetPrimitive(dictionary, "to", ficlPrimitiveToValue,
3298 FICL_WORD_IMMEDIATE);
3299 ficlDictionarySetPrimitive(dictionary, "value", ficlPrimitiveConstant,
3300 FICL_WORD_DEFAULT);
3301 ficlDictionarySetPrimitive(dictionary, "\\", ficlPrimitiveBackslash,
3302 FICL_WORD_IMMEDIATE);
3303
3304 /*
3305 * Environment query values for the Core word set
3306 */
3307 ficlDictionarySetConstant(environment, "/counted-string",
3308 FICL_COUNTED_STRING_MAX);
3309 ficlDictionarySetConstant(environment, "/hold", FICL_PAD_SIZE);
3310 ficlDictionarySetConstant(environment, "/pad", FICL_PAD_SIZE);
3311 ficlDictionarySetConstant(environment, "address-unit-bits", 8);
3312 ficlDictionarySetConstant(environment, "core", FICL_TRUE);
3313 ficlDictionarySetConstant(environment, "core-ext", FICL_FALSE);
3314 ficlDictionarySetConstant(environment, "floored", FICL_FALSE);
3315 ficlDictionarySetConstant(environment, "max-char", UCHAR_MAX);
3316 ficlDictionarySetConstant(environment, "max-n", LONG_MAX);
3317 ficlDictionarySetConstant(environment, "max-u", ULONG_MAX);
3318
3319 {
3320 ficl2Integer id;
3321 ficlInteger low, high;
3322
3323 low = ULONG_MAX;
3324 high = LONG_MAX;
3325 FICL_2INTEGER_SET(high, low, id);
3326 ficlDictionarySet2Constant(environment, "max-d", id);
3327 high = ULONG_MAX;
3328 FICL_2INTEGER_SET(high, low, id);
3329 ficlDictionarySet2Constant(environment, "max-ud", id);
3330 }
3331
3332 ficlDictionarySetConstant(environment, "return-stack-cells",
3333 FICL_DEFAULT_STACK_SIZE);
3334 ficlDictionarySetConstant(environment, "stack-cells",
3335 FICL_DEFAULT_STACK_SIZE);
3336
3337 /*
3338 * The optional Double-Number word set (partial)
3339 */
3340 ficlDictionarySetPrimitive(dictionary, "2constant",
3341 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE);
3342 ficlDictionarySetPrimitive(dictionary, "2literal",
3343 ficlPrimitive2LiteralIm, FICL_WORD_IMMEDIATE);
3344 ficlDictionarySetPrimitive(dictionary, "2variable",
3345 ficlPrimitive2Variable, FICL_WORD_IMMEDIATE);
3346 /*
3347 * D+ D- D. D.R D0< D0= D2* D2/ in softcore
3348 * D< D= D>S DABS DMAX DMIN DNEGATE in softcore
3349 * m-star-slash is TODO
3350 * M+ in softcore
3351 */
3352
3353 /*
3354 * DOUBLE EXT
3355 */
3356 ficlDictionarySetPrimitive(dictionary, "2rot",
3357 ficlPrimitive2Rot, FICL_WORD_DEFAULT);
3358 ficlDictionarySetPrimitive(dictionary, "2value",
3359 ficlPrimitive2Constant, FICL_WORD_IMMEDIATE);
3360 /* du< in softcore */
3361 /*
3362 * The optional Exception and Exception Extensions word set
3363 */
3364 ficlDictionarySetPrimitive(dictionary, "catch", ficlPrimitiveCatch,
3365 FICL_WORD_DEFAULT);
3366 ficlDictionarySetPrimitive(dictionary, "throw", ficlPrimitiveThrow,
3367 FICL_WORD_DEFAULT);
3368
3369 ficlDictionarySetConstant(environment, "exception", FICL_TRUE);
3370 ficlDictionarySetConstant(environment, "exception-ext", FICL_TRUE);
3371
3372 /*
3373 * The optional Locals and Locals Extensions word set
3374 * see softcore.c for implementation of locals|
3375 */
3376 #if FICL_WANT_LOCALS
3377 ficlDictionarySetPrimitive(dictionary, "doLocal",
3378 ficlPrimitiveDoLocalIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3379 ficlDictionarySetPrimitive(dictionary, "(local)",
3380 ficlPrimitiveLocalParen, FICL_WORD_COMPILE_ONLY);
3381 ficlDictionarySetPrimitive(dictionary, "(2local)",
3382 ficlPrimitive2LocalParen, FICL_WORD_COMPILE_ONLY);
3383
3384 ficlDictionarySetConstant(environment, "locals", FICL_TRUE);
3385 ficlDictionarySetConstant(environment, "locals-ext", FICL_TRUE);
3386 ficlDictionarySetConstant(environment, "#locals", FICL_MAX_LOCALS);
3387 #endif
3388
3389 /*
3390 * The optional Memory-Allocation word set
3391 */
3392
3393 ficlDictionarySetPrimitive(dictionary, "allocate",
3394 ficlPrimitiveAllocate, FICL_WORD_DEFAULT);
3395 ficlDictionarySetPrimitive(dictionary, "free", ficlPrimitiveFree,
3396 FICL_WORD_DEFAULT);
3397 ficlDictionarySetPrimitive(dictionary, "resize", ficlPrimitiveResize,
3398 FICL_WORD_DEFAULT);
3399
3400 ficlDictionarySetConstant(environment, "memory-alloc", FICL_TRUE);
3401
3402 /*
3403 * The optional Search-Order word set
3404 */
3405 ficlSystemCompileSearch(system);
3406
3407 /*
3408 * The optional Programming-Tools and Programming-Tools
3409 * Extensions word set
3410 */
3411 ficlSystemCompileTools(system);
3412
3413 /*
3414 * The optional File-Access and File-Access Extensions word set
3415 */
3416 #if FICL_WANT_FILE
3417 ficlSystemCompileFile(system);
3418 #endif
3419
3420 /*
3421 * Ficl extras
3422 */
3423 ficlDictionarySetPrimitive(dictionary, ".ver", ficlPrimitiveVersion,
3424 FICL_WORD_DEFAULT);
3425 ficlDictionarySetPrimitive(dictionary, ">name", ficlPrimitiveToName,
3426 FICL_WORD_DEFAULT);
3427 ficlDictionarySetPrimitive(dictionary, "add-parse-step",
3428 ficlPrimitiveAddParseStep, FICL_WORD_DEFAULT);
3429 ficlDictionarySetPrimitive(dictionary, "body>", ficlPrimitiveFromBody,
3430 FICL_WORD_DEFAULT);
3431 ficlDictionarySetPrimitive(dictionary, "compile-only",
3432 ficlPrimitiveCompileOnly, FICL_WORD_DEFAULT);
3433 ficlDictionarySetPrimitive(dictionary, "endif", ficlPrimitiveEndifCoIm,
3434 FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3435 ficlDictionarySetPrimitive(dictionary, "last-word",
3436 ficlPrimitiveLastWord, FICL_WORD_DEFAULT);
3437 ficlDictionarySetPrimitive(dictionary, "hash", ficlPrimitiveHash,
3438 FICL_WORD_DEFAULT);
3439 ficlDictionarySetPrimitive(dictionary, "objectify",
3440 ficlPrimitiveSetObjectFlag, FICL_WORD_DEFAULT);
3441 ficlDictionarySetPrimitive(dictionary, "?object",
3442 ficlPrimitiveIsObject, FICL_WORD_DEFAULT);
3443 ficlDictionarySetPrimitive(dictionary, "parse-word",
3444 ficlPrimitiveParseNoCopy, FICL_WORD_DEFAULT);
3445 ficlDictionarySetPrimitive(dictionary, "sfind", ficlPrimitiveSFind,
3446 FICL_WORD_DEFAULT);
3447 ficlDictionarySetPrimitive(dictionary, "sliteral",
3448 ficlPrimitiveSLiteralCoIm, FICL_WORD_COMPILE_ONLY_IMMEDIATE);
3449 ficlDictionarySetPrimitive(dictionary, "sprintf", ficlPrimitiveSprintf,
3450 FICL_WORD_DEFAULT);
3451 ficlDictionarySetPrimitive(dictionary, "strlen", ficlPrimitiveStrlen,
3452 FICL_WORD_DEFAULT);
3453 ficlDictionarySetPrimitive(dictionary, "x.", ficlPrimitiveHexDot,
3454 FICL_WORD_DEFAULT);
3455 #if FICL_WANT_USER
3456 ficlDictionarySetPrimitive(dictionary, "user", ficlPrimitiveUser,
3457 FICL_WORD_DEFAULT);
3458 #endif
3459
3460 /*
3461 * internal support words
3462 */
3463 interpret = ficlDictionarySetPrimitive(dictionary, "interpret",
3464 ficlPrimitiveInterpret, FICL_WORD_DEFAULT);
3465 ficlDictionarySetPrimitive(dictionary, "lookup", ficlPrimitiveLookup,
3466 FICL_WORD_DEFAULT);
3467 ficlDictionarySetPrimitive(dictionary, "(parse-step)",
3468 ficlPrimitiveParseStepParen, FICL_WORD_DEFAULT);
3469 system->exitInnerWord = ficlDictionarySetPrimitive(dictionary,
3470 "exit-inner", ficlPrimitiveExitInner, FICL_WORD_DEFAULT);
3471
3472 /*
3473 * Set constants representing the internal instruction words
3474 * If you want all of 'em, turn that "#if 0" to "#if 1".
3475 * By default you only get the numbers (fi0, fiNeg1, etc).
3476 */
3477 #define FICL_TOKEN(token, description) \
3478 ficlDictionarySetConstant(dictionary, #token, token);
3479 #if 0
3480 #define FICL_INSTRUCTION_TOKEN(token, description, flags) \
3481 ficlDictionarySetConstant(dictionary, #token, token);
3482 #else
3483 #define FICL_INSTRUCTION_TOKEN(token, description, flags)
3484 #endif /* 0 */
3485 #include "ficltokens.h"
3486 #undef FICL_TOKEN
3487 #undef FICL_INSTRUCTION_TOKEN
3488
3489 /*
3490 * Set up system's outer interpreter loop - maybe this should
3491 * be in initSystem?
3492 */
3493 system->interpreterLoop[0] = interpret;
3494 system->interpreterLoop[1] = (ficlWord *)ficlInstructionBranchParen;
3495 system->interpreterLoop[2] = (ficlWord *)(void *)(-2);
3496
3497 FICL_SYSTEM_ASSERT(system,
3498 ficlDictionaryCellsAvailable(dictionary) > 0);
3499 }
3500