xref: /illumos-gate/usr/src/common/ficl/vm.c (revision 89fbfe0d2fbdaef52447ae1ca77634c69a3cf220)
1 /*
2  * v m . c
3  * Forth Inspired Command Language - virtual machine methods
4  * Author: John Sadler (john_sadler@alum.mit.edu)
5  * Created: 19 July 1997
6  * $Id: vm.c,v 1.17 2010/09/13 18:43:04 asau Exp $
7  */
8 /*
9  * This file implements the virtual machine of Ficl. Each virtual
10  * machine retains the state of an interpreter. A virtual machine
11  * owns a pair of stacks for parameters and return addresses, as
12  * well as a pile of state variables and the two dedicated registers
13  * of the interpreter.
14  */
15 /*
16  * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
17  * All rights reserved.
18  *
19  * Get the latest Ficl release at http://ficl.sourceforge.net
20  *
21  * I am interested in hearing from anyone who uses Ficl. If you have
22  * a problem, a success story, a defect, an enhancement request, or
23  * if you would like to contribute to the Ficl release, please
24  * contact me by email at the address above.
25  *
26  * L I C E N S E  and  D I S C L A I M E R
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  *    notice, this list of conditions and the following disclaimer.
33  * 2. Redistributions in binary form must reproduce the above copyright
34  *    notice, this list of conditions and the following disclaimer in the
35  *    documentation and/or other materials provided with the distribution.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  */
49 
50 /*
51  * Copyright 2019 Joyent, Inc.
52  */
53 
54 #include "ficl.h"
55 
56 #if FICL_ROBUST >= 2
57 #define	FICL_VM_CHECK(vm)	\
58 	FICL_VM_ASSERT(vm, (*(vm->ip - 1)) == vm->runningWord)
59 #else
60 #define	FICL_VM_CHECK(vm)
61 #endif
62 
63 /*
64  * v m B r a n c h R e l a t i v e
65  */
66 void
67 ficlVmBranchRelative(ficlVm *vm, int offset)
68 {
69 	vm->ip += offset;
70 }
71 
72 /*
73  * v m C r e a t e
74  * Creates a virtual machine either from scratch (if vm is NULL on entry)
75  * or by resizing and reinitializing an existing VM to the specified stack
76  * sizes.
77  */
78 ficlVm *
79 ficlVmCreate(ficlVm *vm, unsigned nPStack, unsigned nRStack)
80 {
81 	if (vm == NULL) {
82 		vm = (ficlVm *)ficlMalloc(sizeof (ficlVm));
83 		FICL_ASSERT(NULL, vm);
84 		memset(vm, 0, sizeof (ficlVm));
85 	}
86 
87 	if (vm->dataStack)
88 		ficlStackDestroy(vm->dataStack);
89 	vm->dataStack = ficlStackCreate(vm, "data", nPStack);
90 
91 	if (vm->returnStack)
92 		ficlStackDestroy(vm->returnStack);
93 	vm->returnStack = ficlStackCreate(vm, "return", nRStack);
94 
95 #if FICL_WANT_FLOAT
96 	if (vm->floatStack)
97 		ficlStackDestroy(vm->floatStack);
98 	vm->floatStack = ficlStackCreate(vm, "float", nPStack);
99 #endif
100 
101 	ficlVmReset(vm);
102 	return (vm);
103 }
104 
105 /*
106  * v m D e l e t e
107  * Free all memory allocated to the specified VM and its subordinate
108  * structures.
109  */
110 void
111 ficlVmDestroy(ficlVm *vm)
112 {
113 	if (vm) {
114 		ficlFree(vm->dataStack);
115 		ficlFree(vm->returnStack);
116 #if FICL_WANT_FLOAT
117 		ficlFree(vm->floatStack);
118 #endif
119 		ficlFree(vm);
120 	}
121 }
122 
123 /*
124  * v m E x e c u t e
125  * Sets up the specified word to be run by the inner interpreter.
126  * Executes the word's code part immediately, but in the case of
127  * colon definition, the definition itself needs the inner interpreter
128  * to complete. This does not happen until control reaches ficlExec
129  */
130 void
131 ficlVmExecuteWord(ficlVm *vm, ficlWord *pWord)
132 {
133 	ficlVmInnerLoop(vm, pWord);
134 }
135 
136 static void
137 ficlVmOptimizeJumpToJump(ficlVm *vm, ficlIp ip)
138 {
139 	ficlIp destination;
140 	switch ((ficlInstruction)(*ip)) {
141 	case ficlInstructionBranchParenWithCheck:
142 		*ip = (ficlWord *)ficlInstructionBranchParen;
143 		goto RUNTIME_FIXUP;
144 
145 	case ficlInstructionBranch0ParenWithCheck:
146 		*ip = (ficlWord *)ficlInstructionBranch0Paren;
147 RUNTIME_FIXUP:
148 		ip++;
149 		destination = ip + *(ficlInteger *)ip;
150 		switch ((ficlInstruction)*destination) {
151 		case ficlInstructionBranchParenWithCheck:
152 			/* preoptimize where we're jumping to */
153 			ficlVmOptimizeJumpToJump(vm, destination);
154 			/* FALLTHROUGH */
155 		case ficlInstructionBranchParen:
156 			destination++;
157 			destination += *(ficlInteger *)destination;
158 			*ip = (ficlWord *)(destination - ip);
159 		break;
160 		}
161 	}
162 }
163 
164 /*
165  * v m I n n e r L o o p
166  * the mysterious inner interpreter...
167  * This loop is the address interpreter that makes colon definitions
168  * work. Upon entry, it assumes that the IP points to an entry in
169  * a definition (the body of a colon word). It runs one word at a time
170  * until something does vmThrow. The catcher for this is expected to exist
171  * in the calling code.
172  * vmThrow gets you out of this loop with a longjmp()
173  */
174 
175 #if FICL_ROBUST <= 1
176 	/* turn off stack checking for primitives */
177 #define	_CHECK_STACK(stack, top, pop, push)
178 #else
179 
180 #define	_CHECK_STACK(stack, top, pop, push)	\
181 	ficlStackCheckNospill(stack, top, pop, push)
182 
183 static FICL_PLATFORM_INLINE void
184 ficlStackCheckNospill(ficlStack *stack, ficlCell *top, int popCells,
185     int pushCells)
186 {
187 	/*
188 	 * Why save and restore stack->top?
189 	 * So the simple act of stack checking doesn't force a "register" spill,
190 	 * which might mask bugs (places where we needed to spill but didn't).
191 	 * --lch
192 	 */
193 	ficlCell *oldTop = stack->top;
194 	stack->top = top;
195 	ficlStackCheck(stack, popCells, pushCells);
196 	stack->top = oldTop;
197 }
198 
199 #endif /* FICL_ROBUST <= 1 */
200 
201 #define	CHECK_STACK(pop, push)		\
202 	_CHECK_STACK(vm->dataStack, dataTop, pop, push)
203 #define	CHECK_FLOAT_STACK(pop, push)	\
204 	_CHECK_STACK(vm->floatStack, floatTop, pop, push)
205 #define	CHECK_RETURN_STACK(pop, push)	\
206 	_CHECK_STACK(vm->returnStack, returnTop, pop, push)
207 
208 #if FICL_WANT_FLOAT
209 #define	FLOAT_LOCAL_VARIABLE_SPILL	\
210 	vm->floatStack->top = floatTop;
211 #define	FLOAT_LOCAL_VARIABLE_REFILL	\
212 	floatTop = vm->floatStack->top;
213 #else
214 #define	FLOAT_LOCAL_VARIABLE_SPILL
215 #define	FLOAT_LOCAL_VARIABLE_REFILL
216 #endif  /* FICL_WANT_FLOAT */
217 
218 #if FICL_WANT_LOCALS
219 #define	LOCALS_LOCAL_VARIABLE_SPILL	\
220 	vm->returnStack->frame = frame;
221 #define	LOCALS_LOCAL_VARIABLE_REFILL \
222 	frame = vm->returnStack->frame;
223 #else
224 #define	LOCALS_LOCAL_VARIABLE_SPILL
225 #define	LOCALS_LOCAL_VARIABLE_REFILL
226 #endif  /* FICL_WANT_FLOAT */
227 
228 #define	LOCAL_VARIABLE_SPILL	\
229 		vm->ip = (ficlIp)ip;	\
230 		vm->dataStack->top = dataTop;	\
231 		vm->returnStack->top = returnTop;	\
232 		FLOAT_LOCAL_VARIABLE_SPILL \
233 		LOCALS_LOCAL_VARIABLE_SPILL
234 
235 #define	LOCAL_VARIABLE_REFILL	\
236 		ip = (ficlInstruction *)vm->ip; \
237 		dataTop = vm->dataStack->top;	\
238 		returnTop = vm->returnStack->top;	\
239 		FLOAT_LOCAL_VARIABLE_REFILL	\
240 		LOCALS_LOCAL_VARIABLE_REFILL
241 
242 void
243 ficlVmInnerLoop(ficlVm *vm, ficlWord *fw)
244 {
245 	register ficlInstruction *ip;
246 	register ficlCell *dataTop;
247 	register ficlCell *returnTop;
248 #if FICL_WANT_FLOAT
249 	register ficlCell *floatTop;
250 	ficlFloat f;
251 #endif  /* FICL_WANT_FLOAT */
252 #if FICL_WANT_LOCALS
253 	register ficlCell *frame;
254 #endif  /* FICL_WANT_LOCALS */
255 	jmp_buf *oldExceptionHandler;
256 	jmp_buf exceptionHandler;
257 	int except;
258 	int once;
259 	volatile int count;	/* volatile because of longjmp */
260 	ficlInstruction instruction;
261 	ficlInteger i;
262 	ficlUnsigned u;
263 	ficlCell c;
264 	ficlCountedString *s;
265 	ficlCell *cell;
266 	char *cp;
267 
268 	once = (fw != NULL);
269 	if (once)
270 		count = 1;
271 
272 	oldExceptionHandler = vm->exceptionHandler;
273 	/* This has to come before the setjmp! */
274 	vm->exceptionHandler = &exceptionHandler;
275 	except = setjmp(exceptionHandler);
276 
277 	LOCAL_VARIABLE_REFILL;
278 
279 	if (except) {
280 		LOCAL_VARIABLE_SPILL;
281 		vm->exceptionHandler = oldExceptionHandler;
282 		ficlVmThrow(vm, except);
283 	}
284 
285 	for (;;) {
286 		if (once) {
287 			if (!count--)
288 				break;
289 			instruction = (ficlInstruction)((void *)fw);
290 		} else {
291 			instruction = *ip++;
292 			fw = (ficlWord *)instruction;
293 		}
294 
295 AGAIN:
296 		switch (instruction) {
297 		case ficlInstructionInvalid:
298 			ficlVmThrowError(vm,
299 			    "Error: NULL instruction executed!");
300 			break;
301 
302 		case ficlInstruction1:
303 		case ficlInstruction2:
304 		case ficlInstruction3:
305 		case ficlInstruction4:
306 		case ficlInstruction5:
307 		case ficlInstruction6:
308 		case ficlInstruction7:
309 		case ficlInstruction8:
310 		case ficlInstruction9:
311 		case ficlInstruction10:
312 		case ficlInstruction11:
313 		case ficlInstruction12:
314 		case ficlInstruction13:
315 		case ficlInstruction14:
316 		case ficlInstruction15:
317 		case ficlInstruction16:
318 			CHECK_STACK(0, 1);
319 			(++dataTop)->i = instruction;
320 			continue;
321 
322 		case ficlInstruction0:
323 		case ficlInstructionNeg1:
324 		case ficlInstructionNeg2:
325 		case ficlInstructionNeg3:
326 		case ficlInstructionNeg4:
327 		case ficlInstructionNeg5:
328 		case ficlInstructionNeg6:
329 		case ficlInstructionNeg7:
330 		case ficlInstructionNeg8:
331 		case ficlInstructionNeg9:
332 		case ficlInstructionNeg10:
333 		case ficlInstructionNeg11:
334 		case ficlInstructionNeg12:
335 		case ficlInstructionNeg13:
336 		case ficlInstructionNeg14:
337 		case ficlInstructionNeg15:
338 		case ficlInstructionNeg16:
339 			CHECK_STACK(0, 1);
340 			(++dataTop)->i = ficlInstruction0 - instruction;
341 			continue;
342 
343 		/*
344 		 * stringlit: Fetch the count from the dictionary, then push
345 		 * the address and count on the stack. Finally, update ip to
346 		 * point to the first aligned address after the string text.
347 		 */
348 		case ficlInstructionStringLiteralParen: {
349 			ficlUnsigned8 length;
350 			CHECK_STACK(0, 2);
351 
352 			s = (ficlCountedString *)(ip);
353 			length = s->length;
354 			cp = s->text;
355 			(++dataTop)->p = cp;
356 			(++dataTop)->i = length;
357 
358 			cp += length + 1;
359 			cp = ficlAlignPointer(cp);
360 			ip = (void *)cp;
361 			continue;
362 		}
363 
364 		case ficlInstructionCStringLiteralParen:
365 			CHECK_STACK(0, 1);
366 
367 			s = (ficlCountedString *)(ip);
368 			cp = s->text + s->length + 1;
369 			cp = ficlAlignPointer(cp);
370 			ip = (void *)cp;
371 			(++dataTop)->p = s;
372 			continue;
373 
374 #if FICL_WANT_OPTIMIZE == FICL_OPTIMIZE_FOR_SIZE
375 #if FICL_WANT_FLOAT
376 FLOAT_PUSH_CELL_POINTER_DOUBLE_MINIPROC:
377 			*++floatTop = cell[1];
378 			/* intentional fall-through */
379 FLOAT_PUSH_CELL_POINTER_MINIPROC:
380 			*++floatTop = cell[0];
381 			continue;
382 
383 FLOAT_POP_CELL_POINTER_MINIPROC:
384 			cell[0] = *floatTop--;
385 			continue;
386 
387 FLOAT_POP_CELL_POINTER_DOUBLE_MINIPROC:
388 			cell[0] = *floatTop--;
389 			cell[1] = *floatTop--;
390 			continue;
391 
392 #define	FLOAT_PUSH_CELL_POINTER_DOUBLE(cp)	\
393 	cell = (cp); goto FLOAT_PUSH_CELL_POINTER_DOUBLE_MINIPROC
394 #define	FLOAT_PUSH_CELL_POINTER(cp)		\
395 	cell = (cp); goto FLOAT_PUSH_CELL_POINTER_MINIPROC
396 #define	FLOAT_POP_CELL_POINTER_DOUBLE(cp)	\
397 	cell = (cp); goto FLOAT_POP_CELL_POINTER_DOUBLE_MINIPROC
398 #define	FLOAT_POP_CELL_POINTER(cp)		\
399 	cell = (cp); goto FLOAT_POP_CELL_POINTER_MINIPROC
400 #endif /* FICL_WANT_FLOAT */
401 
402 		/*
403 		 * Think of these as little mini-procedures.
404 		 * --lch
405 		 */
406 PUSH_CELL_POINTER_DOUBLE_MINIPROC:
407 			*++dataTop = cell[1];
408 			/* intentional fall-through */
409 PUSH_CELL_POINTER_MINIPROC:
410 			*++dataTop = cell[0];
411 			continue;
412 
413 POP_CELL_POINTER_MINIPROC:
414 			cell[0] = *dataTop--;
415 			continue;
416 POP_CELL_POINTER_DOUBLE_MINIPROC:
417 			cell[0] = *dataTop--;
418 			cell[1] = *dataTop--;
419 			continue;
420 
421 #define	PUSH_CELL_POINTER_DOUBLE(cp)	\
422 	cell = (cp); goto PUSH_CELL_POINTER_DOUBLE_MINIPROC
423 #define	PUSH_CELL_POINTER(cp)		\
424 	cell = (cp); goto PUSH_CELL_POINTER_MINIPROC
425 #define	POP_CELL_POINTER_DOUBLE(cp)	\
426 	cell = (cp); goto POP_CELL_POINTER_DOUBLE_MINIPROC
427 #define	POP_CELL_POINTER(cp)		\
428 	cell = (cp); goto POP_CELL_POINTER_MINIPROC
429 
430 BRANCH_MINIPROC:
431 			ip += *(ficlInteger *)ip;
432 			continue;
433 
434 #define	BRANCH()	goto BRANCH_MINIPROC
435 
436 EXIT_FUNCTION_MINIPROC:
437 			ip = (ficlInstruction *)((returnTop--)->p);
438 			continue;
439 
440 #define	EXIT_FUNCTION	goto EXIT_FUNCTION_MINIPROC
441 
442 #else /* FICL_WANT_SIZE */
443 
444 #if FICL_WANT_FLOAT
445 #define	FLOAT_PUSH_CELL_POINTER_DOUBLE(cp)	\
446 	cell = (cp); *++floatTop = cell[1]; *++floatTop = *cell; continue
447 #define	FLOAT_PUSH_CELL_POINTER(cp)		\
448 	cell = (cp); *++floatTop = *cell; continue
449 #define	FLOAT_POP_CELL_POINTER_DOUBLE(cp)	\
450 	cell = (cp); *cell = *floatTop--; cell[1] = *floatTop--; continue
451 #define	FLOAT_POP_CELL_POINTER(cp)		\
452 	cell = (cp); *cell = *floatTop--; continue
453 #endif /* FICL_WANT_FLOAT */
454 
455 #define	PUSH_CELL_POINTER_DOUBLE(cp)	\
456 	cell = (cp); *++dataTop = cell[1]; *++dataTop = *cell; continue
457 #define	PUSH_CELL_POINTER(cp)		\
458 	cell = (cp); *++dataTop = *cell; continue
459 #define	POP_CELL_POINTER_DOUBLE(cp)	\
460 	cell = (cp); *cell = *dataTop--; cell[1] = *dataTop--; continue
461 #define	POP_CELL_POINTER(cp)		\
462 	cell = (cp); *cell = *dataTop--; continue
463 
464 #define	BRANCH()	ip += *(ficlInteger *)ip; continue
465 #define	EXIT_FUNCTION()	ip = (ficlInstruction *)((returnTop--)->p); continue
466 
467 #endif /* FICL_WANT_SIZE */
468 
469 
470 		/*
471 		 * This is the runtime for (literal). It assumes that it is
472 		 * part of a colon definition, and that the next ficlCell
473 		 * contains a value to be pushed on the parameter stack at
474 		 * runtime. This code is compiled by "literal".
475 		 */
476 
477 		case ficlInstructionLiteralParen:
478 			CHECK_STACK(0, 1);
479 			(++dataTop)->i = *ip++;
480 			continue;
481 
482 		case ficlInstruction2LiteralParen:
483 			CHECK_STACK(0, 2);
484 			(++dataTop)->i = ip[1];
485 			(++dataTop)->i = ip[0];
486 			ip += 2;
487 			continue;
488 
489 #if FICL_WANT_LOCALS
490 		/*
491 		 * Link a frame on the return stack, reserving nCells of space
492 		 * for locals - the value of nCells is the next ficlCell in
493 		 * the instruction stream.
494 		 * 1) Push frame onto returnTop
495 		 * 2) frame = returnTop
496 		 * 3) returnTop += nCells
497 		 */
498 		case ficlInstructionLinkParen: {
499 			ficlInteger nCells = *ip++;
500 			(++returnTop)->p = frame;
501 			frame = returnTop + 1;
502 			returnTop += nCells;
503 			continue;
504 		}
505 
506 		/*
507 		 * Unink a stack frame previously created by stackLink
508 		 * 1) dataTop = frame
509 		 * 2) frame = pop()
510 		 */
511 		case ficlInstructionUnlinkParen:
512 			returnTop = frame - 1;
513 			frame = (returnTop--)->p;
514 			continue;
515 
516 		/*
517 		 * Immediate - cfa of a local while compiling - when executed,
518 		 * compiles code to fetch the value of a local given the
519 		 * local's index in the word's pfa
520 		 */
521 #if FICL_WANT_FLOAT
522 		case ficlInstructionGetF2LocalParen:
523 			FLOAT_PUSH_CELL_POINTER_DOUBLE(frame + *ip++);
524 
525 		case ficlInstructionGetFLocalParen:
526 			FLOAT_PUSH_CELL_POINTER(frame + *ip++);
527 
528 		case ficlInstructionToF2LocalParen:
529 			FLOAT_POP_CELL_POINTER_DOUBLE(frame + *ip++);
530 
531 		case ficlInstructionToFLocalParen:
532 			FLOAT_POP_CELL_POINTER(frame + *ip++);
533 #endif /* FICL_WANT_FLOAT */
534 
535 		case ficlInstructionGet2LocalParen:
536 			PUSH_CELL_POINTER_DOUBLE(frame + *ip++);
537 
538 		case ficlInstructionGetLocalParen:
539 			PUSH_CELL_POINTER(frame + *ip++);
540 
541 		/*
542 		 * Immediate - cfa of a local while compiling - when executed,
543 		 * compiles code to store the value of a local given the
544 		 * local's index in the word's pfa
545 		 */
546 
547 		case ficlInstructionTo2LocalParen:
548 			POP_CELL_POINTER_DOUBLE(frame + *ip++);
549 
550 		case ficlInstructionToLocalParen:
551 			POP_CELL_POINTER(frame + *ip++);
552 
553 		/*
554 		 * Silly little minor optimizations.
555 		 * --lch
556 		 */
557 		case ficlInstructionGetLocal0:
558 			PUSH_CELL_POINTER(frame);
559 
560 		case ficlInstructionGetLocal1:
561 			PUSH_CELL_POINTER(frame + 1);
562 
563 		case ficlInstructionGet2Local0:
564 			PUSH_CELL_POINTER_DOUBLE(frame);
565 
566 		case ficlInstructionToLocal0:
567 			POP_CELL_POINTER(frame);
568 
569 		case ficlInstructionToLocal1:
570 			POP_CELL_POINTER(frame + 1);
571 
572 		case ficlInstructionTo2Local0:
573 			POP_CELL_POINTER_DOUBLE(frame);
574 
575 #endif /* FICL_WANT_LOCALS */
576 
577 		case ficlInstructionPlus:
578 			CHECK_STACK(2, 1);
579 			i = (dataTop--)->i;
580 			dataTop->i += i;
581 			continue;
582 
583 		case ficlInstructionMinus:
584 			CHECK_STACK(2, 1);
585 			i = (dataTop--)->i;
586 			dataTop->i -= i;
587 			continue;
588 
589 		case ficlInstruction1Plus:
590 			CHECK_STACK(1, 1);
591 			dataTop->i++;
592 			continue;
593 
594 		case ficlInstruction1Minus:
595 			CHECK_STACK(1, 1);
596 			dataTop->i--;
597 			continue;
598 
599 		case ficlInstruction2Plus:
600 			CHECK_STACK(1, 1);
601 			dataTop->i += 2;
602 			continue;
603 
604 		case ficlInstruction2Minus:
605 			CHECK_STACK(1, 1);
606 			dataTop->i -= 2;
607 			continue;
608 
609 		case ficlInstructionDup: {
610 			ficlInteger i = dataTop->i;
611 			CHECK_STACK(0, 1);
612 			(++dataTop)->i = i;
613 			continue;
614 		}
615 
616 		case ficlInstructionQuestionDup:
617 			CHECK_STACK(1, 2);
618 
619 			if (dataTop->i != 0) {
620 				dataTop[1] = dataTop[0];
621 				dataTop++;
622 			}
623 
624 			continue;
625 
626 		case ficlInstructionSwap: {
627 			ficlCell swap;
628 			CHECK_STACK(2, 2);
629 			swap = dataTop[0];
630 			dataTop[0] = dataTop[-1];
631 			dataTop[-1] = swap;
632 			continue;
633 		}
634 
635 		case ficlInstructionDrop:
636 			CHECK_STACK(1, 0);
637 			dataTop--;
638 			continue;
639 
640 		case ficlInstruction2Drop:
641 			CHECK_STACK(2, 0);
642 			dataTop -= 2;
643 			continue;
644 
645 		case ficlInstruction2Dup:
646 			CHECK_STACK(2, 4);
647 			dataTop[1] = dataTop[-1];
648 			dataTop[2] = *dataTop;
649 			dataTop += 2;
650 			continue;
651 
652 		case ficlInstructionOver:
653 			CHECK_STACK(2, 3);
654 			dataTop[1] = dataTop[-1];
655 			dataTop++;
656 			continue;
657 
658 		case ficlInstruction2Over:
659 			CHECK_STACK(4, 6);
660 			dataTop[1] = dataTop[-3];
661 			dataTop[2] = dataTop[-2];
662 			dataTop += 2;
663 			continue;
664 
665 		case ficlInstructionPick:
666 			CHECK_STACK(1, 0);
667 			i = dataTop->i;
668 			if (i < 0)
669 				continue;
670 			CHECK_STACK(i + 2, i + 3);
671 			*dataTop = dataTop[-i - 1];
672 			continue;
673 
674 		/*
675 		 * Do stack rot.
676 		 * rot ( 1 2 3  -- 2 3 1 )
677 		 */
678 		case ficlInstructionRot:
679 			i = 2;
680 			goto ROLL;
681 
682 		/*
683 		 * Do stack roll.
684 		 * roll ( n -- )
685 		 */
686 		case ficlInstructionRoll:
687 			CHECK_STACK(1, 0);
688 			i = (dataTop--)->i;
689 
690 			if (i < 1)
691 				continue;
692 
693 ROLL:
694 			CHECK_STACK(i+1, i+2);
695 			c = dataTop[-i];
696 			memmove(dataTop - i, dataTop - (i - 1),
697 			    i * sizeof (ficlCell));
698 			*dataTop = c;
699 			continue;
700 
701 		/*
702 		 * Do stack -rot.
703 		 * -rot ( 1 2 3  -- 3 1 2 )
704 		 */
705 		case ficlInstructionMinusRot:
706 			i = 2;
707 			goto MINUSROLL;
708 
709 		/*
710 		 * Do stack -roll.
711 		 * -roll ( n -- )
712 		 */
713 		case ficlInstructionMinusRoll:
714 			CHECK_STACK(1, 0);
715 			i = (dataTop--)->i;
716 
717 			if (i < 1)
718 				continue;
719 
720 MINUSROLL:
721 			CHECK_STACK(i+1, i+2);
722 			c = *dataTop;
723 			memmove(dataTop - (i - 1), dataTop - i,
724 			    i * sizeof (ficlCell));
725 			dataTop[-i] = c;
726 
727 			continue;
728 
729 		/*
730 		 * Do stack 2swap
731 		 * 2swap ( 1 2 3 4  -- 3 4 1 2 )
732 		 */
733 		case ficlInstruction2Swap: {
734 			ficlCell c2;
735 			CHECK_STACK(4, 4);
736 
737 			c = *dataTop;
738 			c2 = dataTop[-1];
739 
740 			*dataTop = dataTop[-2];
741 			dataTop[-1] = dataTop[-3];
742 
743 			dataTop[-2] = c;
744 			dataTop[-3] = c2;
745 			continue;
746 		}
747 
748 		case ficlInstructionPlusStore: {
749 			ficlCell *cell;
750 			CHECK_STACK(2, 0);
751 			cell = (ficlCell *)(dataTop--)->p;
752 			cell->i += (dataTop--)->i;
753 			continue;
754 		}
755 
756 		case ficlInstructionQuadFetch: {
757 			ficlUnsigned32 *integer32;
758 			CHECK_STACK(1, 1);
759 			integer32 = (ficlUnsigned32 *)dataTop->i;
760 			dataTop->u = (ficlUnsigned)*integer32;
761 			continue;
762 		}
763 
764 		case ficlInstructionQuadStore: {
765 			ficlUnsigned32 *integer32;
766 			CHECK_STACK(2, 0);
767 			integer32 = (ficlUnsigned32 *)(dataTop--)->p;
768 			*integer32 = (ficlUnsigned32)((dataTop--)->u);
769 			continue;
770 		}
771 
772 		case ficlInstructionWFetch: {
773 			ficlUnsigned16 *integer16;
774 			CHECK_STACK(1, 1);
775 			integer16 = (ficlUnsigned16 *)dataTop->p;
776 			dataTop->u = ((ficlUnsigned)*integer16);
777 			continue;
778 		}
779 
780 		case ficlInstructionWStore: {
781 			ficlUnsigned16 *integer16;
782 			CHECK_STACK(2, 0);
783 			integer16 = (ficlUnsigned16 *)(dataTop--)->p;
784 			*integer16 = (ficlUnsigned16)((dataTop--)->u);
785 			continue;
786 		}
787 
788 		case ficlInstructionCFetch: {
789 			ficlUnsigned8 *integer8;
790 			CHECK_STACK(1, 1);
791 			integer8 = (ficlUnsigned8 *)dataTop->p;
792 			dataTop->u = ((ficlUnsigned)*integer8);
793 			continue;
794 		}
795 
796 		case ficlInstructionCStore: {
797 			ficlUnsigned8 *integer8;
798 			CHECK_STACK(2, 0);
799 			integer8 = (ficlUnsigned8 *)(dataTop--)->p;
800 			*integer8 = (ficlUnsigned8)((dataTop--)->u);
801 			continue;
802 		}
803 
804 
805 		/*
806 		 * l o g i c   a n d   c o m p a r i s o n s
807 		 */
808 
809 		case ficlInstruction0Equals:
810 			CHECK_STACK(1, 1);
811 			dataTop->i = FICL_BOOL(dataTop->i == 0);
812 			continue;
813 
814 		case ficlInstruction0Less:
815 			CHECK_STACK(1, 1);
816 			dataTop->i = FICL_BOOL(dataTop->i < 0);
817 			continue;
818 
819 		case ficlInstruction0Greater:
820 			CHECK_STACK(1, 1);
821 			dataTop->i = FICL_BOOL(dataTop->i > 0);
822 			continue;
823 
824 		case ficlInstructionEquals:
825 			CHECK_STACK(2, 1);
826 			i = (dataTop--)->i;
827 			dataTop->i = FICL_BOOL(dataTop->i == i);
828 			continue;
829 
830 		case ficlInstructionLess:
831 			CHECK_STACK(2, 1);
832 			i = (dataTop--)->i;
833 			dataTop->i = FICL_BOOL(dataTop->i < i);
834 			continue;
835 
836 		case ficlInstructionULess:
837 			CHECK_STACK(2, 1);
838 			u = (dataTop--)->u;
839 			dataTop->i = FICL_BOOL(dataTop->u < u);
840 			continue;
841 
842 		case ficlInstructionAnd:
843 			CHECK_STACK(2, 1);
844 			i = (dataTop--)->i;
845 			dataTop->i = dataTop->i & i;
846 			continue;
847 
848 		case ficlInstructionOr:
849 			CHECK_STACK(2, 1);
850 			i = (dataTop--)->i;
851 			dataTop->i = dataTop->i | i;
852 			continue;
853 
854 		case ficlInstructionXor:
855 			CHECK_STACK(2, 1);
856 			i = (dataTop--)->i;
857 			dataTop->i = dataTop->i ^ i;
858 			continue;
859 
860 		case ficlInstructionInvert:
861 			CHECK_STACK(1, 1);
862 			dataTop->i = ~dataTop->i;
863 			continue;
864 
865 		/*
866 		 * r e t u r n   s t a c k
867 		 */
868 		case ficlInstructionToRStack:
869 			CHECK_STACK(1, 0);
870 			CHECK_RETURN_STACK(0, 1);
871 			*++returnTop = *dataTop--;
872 			continue;
873 
874 		case ficlInstructionFromRStack:
875 			CHECK_STACK(0, 1);
876 			CHECK_RETURN_STACK(1, 0);
877 			*++dataTop = *returnTop--;
878 			continue;
879 
880 		case ficlInstructionFetchRStack:
881 			CHECK_STACK(0, 1);
882 			CHECK_RETURN_STACK(1, 1);
883 			*++dataTop = *returnTop;
884 			continue;
885 
886 		case ficlInstruction2ToR:
887 			CHECK_STACK(2, 0);
888 			CHECK_RETURN_STACK(0, 2);
889 			*++returnTop = dataTop[-1];
890 			*++returnTop = dataTop[0];
891 			dataTop -= 2;
892 			continue;
893 
894 		case ficlInstruction2RFrom:
895 			CHECK_STACK(0, 2);
896 			CHECK_RETURN_STACK(2, 0);
897 			*++dataTop = returnTop[-1];
898 			*++dataTop = returnTop[0];
899 			returnTop -= 2;
900 			continue;
901 
902 		case ficlInstruction2RFetch:
903 			CHECK_STACK(0, 2);
904 			CHECK_RETURN_STACK(2, 2);
905 			*++dataTop = returnTop[-1];
906 			*++dataTop = returnTop[0];
907 			continue;
908 
909 		/*
910 		 * f i l l
911 		 * CORE ( c-addr u char -- )
912 		 * If u is greater than zero, store char in each of u
913 		 * consecutive characters of memory beginning at c-addr.
914 		 */
915 		case ficlInstructionFill: {
916 			char c;
917 			char *memory;
918 			CHECK_STACK(3, 0);
919 			c = (char)(dataTop--)->i;
920 			u = (dataTop--)->u;
921 			memory = (char *)(dataTop--)->p;
922 
923 			/*
924 			 * memset() is faster than the previous hand-rolled
925 			 * solution.  --lch
926 			 */
927 			memset(memory, c, u);
928 			continue;
929 		}
930 
931 		/*
932 		 * l s h i f t
933 		 * l-shift CORE ( x1 u -- x2 )
934 		 * Perform a logical left shift of u bit-places on x1,
935 		 * giving x2. Put zeroes into the least significant bits
936 		 * vacated by the shift. An ambiguous condition exists if
937 		 * u is greater than or equal to the number of bits in a
938 		 * ficlCell.
939 		 *
940 		 * r-shift CORE ( x1 u -- x2 )
941 		 * Perform a logical right shift of u bit-places on x1,
942 		 * giving x2. Put zeroes into the most significant bits
943 		 * vacated by the shift. An ambiguous condition exists
944 		 * if u is greater than or equal to the number of bits
945 		 * in a ficlCell.
946 		 */
947 		case ficlInstructionLShift: {
948 			ficlUnsigned nBits;
949 			ficlUnsigned x1;
950 			CHECK_STACK(2, 1);
951 
952 			nBits = (dataTop--)->u;
953 			x1 = dataTop->u;
954 			dataTop->u = x1 << nBits;
955 			continue;
956 		}
957 
958 		case ficlInstructionRShift: {
959 			ficlUnsigned nBits;
960 			ficlUnsigned x1;
961 			CHECK_STACK(2, 1);
962 
963 			nBits = (dataTop--)->u;
964 			x1 = dataTop->u;
965 			dataTop->u = x1 >> nBits;
966 			continue;
967 		}
968 
969 		/*
970 		 * m a x   &   m i n
971 		 */
972 		case ficlInstructionMax: {
973 			ficlInteger n2;
974 			ficlInteger n1;
975 			CHECK_STACK(2, 1);
976 
977 			n2 = (dataTop--)->i;
978 			n1 = dataTop->i;
979 
980 			dataTop->i = ((n1 > n2) ? n1 : n2);
981 			continue;
982 		}
983 
984 		case ficlInstructionMin: {
985 			ficlInteger n2;
986 			ficlInteger n1;
987 			CHECK_STACK(2, 1);
988 
989 			n2 = (dataTop--)->i;
990 			n1 = dataTop->i;
991 
992 			dataTop->i = ((n1 < n2) ? n1 : n2);
993 			continue;
994 		}
995 
996 		/*
997 		 * m o v e
998 		 * CORE ( addr1 addr2 u -- )
999 		 * If u is greater than zero, copy the contents of u
1000 		 * consecutive address units at addr1 to the u consecutive
1001 		 * address units at addr2. After MOVE completes, the u
1002 		 * consecutive address units at addr2 contain exactly
1003 		 * what the u consecutive address units at addr1 contained
1004 		 * before the move.
1005 		 * NOTE! This implementation assumes that a char is the same
1006 		 * size as an address unit.
1007 		 */
1008 		case ficlInstructionMove: {
1009 			ficlUnsigned u;
1010 			char *addr2;
1011 			char *addr1;
1012 			CHECK_STACK(3, 0);
1013 
1014 			u = (dataTop--)->u;
1015 			addr2 = (dataTop--)->p;
1016 			addr1 = (dataTop--)->p;
1017 
1018 			if (u == 0)
1019 				continue;
1020 			/*
1021 			 * Do the copy carefully, so as to be
1022 			 * correct even if the two ranges overlap
1023 			 */
1024 			/* Which ANSI C's memmove() does for you! Yay!  --lch */
1025 			memmove(addr2, addr1, u);
1026 			continue;
1027 		}
1028 
1029 		/*
1030 		 * s t o d
1031 		 * s-to-d CORE ( n -- d )
1032 		 * Convert the number n to the double-ficlCell number d with
1033 		 * the same numerical value.
1034 		 */
1035 		case ficlInstructionSToD: {
1036 			ficlInteger s;
1037 			CHECK_STACK(1, 2);
1038 
1039 			s = dataTop->i;
1040 
1041 			/* sign extend to 64 bits.. */
1042 			(++dataTop)->i = (s < 0) ? -1 : 0;
1043 			continue;
1044 		}
1045 
1046 		/*
1047 		 * c o m p a r e
1048 		 * STRING ( c-addr1 u1 c-addr2 u2 -- n )
1049 		 * Compare the string specified by c-addr1 u1 to the string
1050 		 * specified by c-addr2 u2. The strings are compared, beginning
1051 		 * at the given addresses, character by character, up to the
1052 		 * length of the shorter string or until a difference is found.
1053 		 * If the two strings are identical, n is zero. If the two
1054 		 * strings are identical up to the length of the shorter string,
1055 		 * n is minus-one (-1) if u1 is less than u2 and one (1)
1056 		 * otherwise. If the two strings are not identical up to the
1057 		 * length of the shorter string, n is minus-one (-1) if the
1058 		 * first non-matching character in the string specified by
1059 		 * c-addr1 u1 has a lesser numeric value than the corresponding
1060 		 * character in the string specified by c-addr2 u2 and
1061 		 * one (1) otherwise.
1062 		 */
1063 		case ficlInstructionCompare:
1064 			i = FICL_FALSE;
1065 		goto COMPARE;
1066 
1067 
1068 		case ficlInstructionCompareInsensitive:
1069 			i = FICL_TRUE;
1070 		goto COMPARE;
1071 
1072 COMPARE:
1073 		{
1074 			char *cp1, *cp2;
1075 			ficlUnsigned u1, u2, uMin;
1076 			int n = 0;
1077 
1078 			CHECK_STACK(4, 1);
1079 			u2  = (dataTop--)->u;
1080 			cp2 = (char *)(dataTop--)->p;
1081 			u1  = (dataTop--)->u;
1082 			cp1 = (char *)(dataTop--)->p;
1083 
1084 			uMin = (u1 < u2)? u1 : u2;
1085 			for (; (uMin > 0) && (n == 0); uMin--) {
1086 				int c1 = (unsigned char)*cp1++;
1087 				int c2 = (unsigned char)*cp2++;
1088 
1089 				if (i) {
1090 					c1 = tolower(c1);
1091 					c2 = tolower(c2);
1092 				}
1093 				n = (c1 - c2);
1094 			}
1095 
1096 			if (n == 0)
1097 				n = (int)(u1 - u2);
1098 
1099 			if (n < 0)
1100 				n = -1;
1101 			else if (n > 0)
1102 				n = 1;
1103 
1104 			(++dataTop)->i = n;
1105 			continue;
1106 		}
1107 
1108 		/*
1109 		 * r a n d o m
1110 		 * Ficl-specific
1111 		 */
1112 		case ficlInstructionRandom:
1113 			(++dataTop)->i = random();
1114 		continue;
1115 
1116 		/*
1117 		 * s e e d - r a n d o m
1118 		 * Ficl-specific
1119 		 */
1120 		case ficlInstructionSeedRandom:
1121 			srandom((dataTop--)->i);
1122 		continue;
1123 
1124 		case ficlInstructionGreaterThan: {
1125 			ficlInteger x, y;
1126 			CHECK_STACK(2, 1);
1127 			y = (dataTop--)->i;
1128 			x = dataTop->i;
1129 			dataTop->i = FICL_BOOL(x > y);
1130 			continue;
1131 		}
1132 
1133 		case ficlInstructionUGreaterThan:
1134 			CHECK_STACK(2, 1);
1135 			u = (dataTop--)->u;
1136 			dataTop->i = FICL_BOOL(dataTop->u > u);
1137 			continue;
1138 
1139 		/*
1140 		 * This function simply pops the previous instruction
1141 		 * pointer and returns to the "next" loop. Used for exiting
1142 		 * from within a definition. Note that exitParen is identical
1143 		 * to semiParen - they are in two different functions so that
1144 		 * "see" can correctly identify the end of a colon definition,
1145 		 * even if it uses "exit".
1146 		 */
1147 		case ficlInstructionExitParen:
1148 		case ficlInstructionSemiParen:
1149 			EXIT_FUNCTION();
1150 
1151 		/*
1152 		 * The first time we run "(branch)", perform a "peephole
1153 		 * optimization" to see if we're jumping to another
1154 		 * unconditional jump.  If so, just jump directly there.
1155 		 */
1156 		case ficlInstructionBranchParenWithCheck:
1157 			LOCAL_VARIABLE_SPILL;
1158 			ficlVmOptimizeJumpToJump(vm, vm->ip - 1);
1159 			LOCAL_VARIABLE_REFILL;
1160 		goto BRANCH_PAREN;
1161 
1162 		/*
1163 		 * Same deal with branch0.
1164 		 */
1165 		case ficlInstructionBranch0ParenWithCheck:
1166 			LOCAL_VARIABLE_SPILL;
1167 			ficlVmOptimizeJumpToJump(vm, vm->ip - 1);
1168 			LOCAL_VARIABLE_REFILL;
1169 			/* intentional fall-through */
1170 
1171 		/*
1172 		 * Runtime code for "(branch0)"; pop a flag from the stack,
1173 		 * branch if 0. fall through otherwise.
1174 		 * The heart of "if" and "until".
1175 		 */
1176 		case ficlInstructionBranch0Paren:
1177 			CHECK_STACK(1, 0);
1178 
1179 			if ((dataTop--)->i) {
1180 				/*
1181 				 * don't branch, but skip over branch
1182 				 * relative address
1183 				 */
1184 				ip += 1;
1185 				continue;
1186 			}
1187 			/* otherwise, take branch (to else/endif/begin) */
1188 			/* intentional fall-through! */
1189 
1190 		/*
1191 		 * Runtime for "(branch)" -- expects a literal offset in the
1192 		 * next compilation address, and branches to that location.
1193 		 */
1194 		case ficlInstructionBranchParen:
1195 BRANCH_PAREN:
1196 			BRANCH();
1197 
1198 		case ficlInstructionOfParen: {
1199 			ficlUnsigned a, b;
1200 
1201 			CHECK_STACK(2, 1);
1202 
1203 			a = (dataTop--)->u;
1204 			b = dataTop->u;
1205 
1206 			if (a == b) {
1207 				/* fall through */
1208 				ip++;
1209 				/* remove CASE argument */
1210 				dataTop--;
1211 			} else {
1212 				/* take branch to next of or endcase */
1213 				BRANCH();
1214 			}
1215 
1216 			continue;
1217 		}
1218 
1219 		case ficlInstructionDoParen: {
1220 			ficlCell index, limit;
1221 
1222 			CHECK_STACK(2, 0);
1223 
1224 			index = *dataTop--;
1225 			limit = *dataTop--;
1226 
1227 			/* copy "leave" target addr to stack */
1228 			(++returnTop)->i = *(ip++);
1229 			*++returnTop = limit;
1230 			*++returnTop = index;
1231 
1232 			continue;
1233 		}
1234 
1235 		case ficlInstructionQDoParen: {
1236 			ficlCell index, limit, leave;
1237 
1238 			CHECK_STACK(2, 0);
1239 
1240 			index = *dataTop--;
1241 			limit = *dataTop--;
1242 
1243 			leave.i = *ip;
1244 
1245 			if (limit.u == index.u) {
1246 				ip = leave.p;
1247 			} else {
1248 				ip++;
1249 				*++returnTop = leave;
1250 				*++returnTop = limit;
1251 				*++returnTop = index;
1252 			}
1253 
1254 			continue;
1255 		}
1256 
1257 		case ficlInstructionLoopParen:
1258 		case ficlInstructionPlusLoopParen: {
1259 			ficlInteger index;
1260 			ficlInteger limit;
1261 			int direction = 0;
1262 
1263 			index = returnTop->i;
1264 			limit = returnTop[-1].i;
1265 
1266 			if (instruction == ficlInstructionLoopParen)
1267 				index++;
1268 			else {
1269 				ficlInteger increment;
1270 				CHECK_STACK(1, 0);
1271 				increment = (dataTop--)->i;
1272 				index += increment;
1273 				direction = (increment < 0);
1274 			}
1275 
1276 			if (direction ^ (index >= limit)) {
1277 				/* nuke the loop indices & "leave" addr */
1278 				returnTop -= 3;
1279 				ip++;  /* fall through the loop */
1280 			} else {	/* update index, branch to loop head */
1281 				returnTop->i = index;
1282 				BRANCH();
1283 			}
1284 
1285 			continue;
1286 		}
1287 
1288 
1289 		/*
1290 		 * Runtime code to break out of a do..loop construct
1291 		 * Drop the loop control variables; the branch address
1292 		 * past "loop" is next on the return stack.
1293 		 */
1294 		case ficlInstructionLeave:
1295 			/* almost unloop */
1296 			returnTop -= 2;
1297 			/* exit */
1298 			EXIT_FUNCTION();
1299 
1300 		case ficlInstructionUnloop:
1301 			returnTop -= 3;
1302 			continue;
1303 
1304 		case ficlInstructionI:
1305 			*++dataTop = *returnTop;
1306 			continue;
1307 
1308 		case ficlInstructionJ:
1309 			*++dataTop = returnTop[-3];
1310 			continue;
1311 
1312 		case ficlInstructionK:
1313 			*++dataTop = returnTop[-6];
1314 			continue;
1315 
1316 		case ficlInstructionDoesParen: {
1317 			ficlDictionary *dictionary = ficlVmGetDictionary(vm);
1318 			dictionary->smudge->code =
1319 			    (ficlPrimitive)ficlInstructionDoDoes;
1320 			dictionary->smudge->param[0].p = ip;
1321 			ip = (ficlInstruction *)((returnTop--)->p);
1322 			continue;
1323 		}
1324 
1325 		case ficlInstructionDoDoes: {
1326 			ficlCell *cell;
1327 			ficlIp tempIP;
1328 
1329 			CHECK_STACK(0, 1);
1330 
1331 			cell = fw->param;
1332 			tempIP = (ficlIp)((*cell).p);
1333 			(++dataTop)->p = (cell + 1);
1334 			(++returnTop)->p = (void *)ip;
1335 			ip = (ficlInstruction *)tempIP;
1336 			continue;
1337 		}
1338 
1339 #if FICL_WANT_FLOAT
1340 		case ficlInstructionF2Fetch:
1341 			CHECK_FLOAT_STACK(0, 2);
1342 			CHECK_STACK(1, 0);
1343 			FLOAT_PUSH_CELL_POINTER_DOUBLE((dataTop--)->p);
1344 
1345 		case ficlInstructionFFetch:
1346 			CHECK_FLOAT_STACK(0, 1);
1347 			CHECK_STACK(1, 0);
1348 			FLOAT_PUSH_CELL_POINTER((dataTop--)->p);
1349 
1350 		case ficlInstructionF2Store:
1351 			CHECK_FLOAT_STACK(2, 0);
1352 			CHECK_STACK(1, 0);
1353 			FLOAT_POP_CELL_POINTER_DOUBLE((dataTop--)->p);
1354 
1355 		case ficlInstructionFStore:
1356 			CHECK_FLOAT_STACK(1, 0);
1357 			CHECK_STACK(1, 0);
1358 			FLOAT_POP_CELL_POINTER((dataTop--)->p);
1359 #endif /* FICL_WANT_FLOAT */
1360 
1361 		/*
1362 		 * two-fetch CORE ( a-addr -- x1 x2 )
1363 		 *
1364 		 * Fetch the ficlCell pair x1 x2 stored at a-addr.
1365 		 * x2 is stored at a-addr and x1 at the next consecutive
1366 		 * ficlCell. It is equivalent to the sequence
1367 		 * DUP ficlCell+ @ SWAP @ .
1368 		 */
1369 		case ficlInstruction2Fetch:
1370 			CHECK_STACK(1, 2);
1371 			PUSH_CELL_POINTER_DOUBLE((dataTop--)->p);
1372 
1373 		/*
1374 		 * fetch CORE ( a-addr -- x )
1375 		 *
1376 		 * x is the value stored at a-addr.
1377 		 */
1378 		case ficlInstructionFetch:
1379 			CHECK_STACK(1, 1);
1380 			PUSH_CELL_POINTER((dataTop--)->p);
1381 
1382 		/*
1383 		 * two-store    CORE ( x1 x2 a-addr -- )
1384 		 * Store the ficlCell pair x1 x2 at a-addr, with x2 at a-addr
1385 		 * and x1 at the next consecutive ficlCell. It is equivalent
1386 		 * to the sequence SWAP OVER ! ficlCell+ !
1387 		 */
1388 		case ficlInstruction2Store:
1389 			CHECK_STACK(3, 0);
1390 			POP_CELL_POINTER_DOUBLE((dataTop--)->p);
1391 
1392 		/*
1393 		 * store	CORE ( x a-addr -- )
1394 		 * Store x at a-addr.
1395 		 */
1396 		case ficlInstructionStore:
1397 			CHECK_STACK(2, 0);
1398 			POP_CELL_POINTER((dataTop--)->p);
1399 
1400 		case ficlInstructionComma: {
1401 			ficlDictionary *dictionary;
1402 			CHECK_STACK(1, 0);
1403 
1404 			dictionary = ficlVmGetDictionary(vm);
1405 			ficlDictionaryAppendCell(dictionary, *dataTop--);
1406 			continue;
1407 		}
1408 
1409 		case ficlInstructionCComma: {
1410 			ficlDictionary *dictionary;
1411 			char c;
1412 			CHECK_STACK(1, 0);
1413 
1414 			dictionary = ficlVmGetDictionary(vm);
1415 			c = (char)(dataTop--)->i;
1416 			ficlDictionaryAppendCharacter(dictionary, c);
1417 			continue;
1418 		}
1419 
1420 		case ficlInstructionCells:
1421 			CHECK_STACK(1, 1);
1422 			dataTop->i *= sizeof (ficlCell);
1423 			continue;
1424 
1425 		case ficlInstructionCellPlus:
1426 			CHECK_STACK(1, 1);
1427 			dataTop->i += sizeof (ficlCell);
1428 			continue;
1429 
1430 		case ficlInstructionStar:
1431 			CHECK_STACK(2, 1);
1432 			i = (dataTop--)->i;
1433 			dataTop->i *= i;
1434 			continue;
1435 
1436 		case ficlInstructionNegate:
1437 			CHECK_STACK(1, 1);
1438 			dataTop->i = - dataTop->i;
1439 			continue;
1440 
1441 		case ficlInstructionSlash:
1442 			CHECK_STACK(2, 1);
1443 			i = (dataTop--)->i;
1444 			dataTop->i /= i;
1445 			continue;
1446 
1447 		/*
1448 		 * slash-mod	CORE ( n1 n2 -- n3 n4 )
1449 		 * Divide n1 by n2, giving the single-ficlCell remainder n3
1450 		 * and the single-ficlCell quotient n4. An ambiguous condition
1451 		 * exists if n2 is zero. If n1 and n2 differ in sign, the
1452 		 * implementation-defined result returned will be the
1453 		 * same as that returned by either the phrase
1454 		 * >R S>D R> FM/MOD or the phrase >R S>D R> SM/REM.
1455 		 * NOTE: Ficl complies with the second phrase
1456 		 * (symmetric division)
1457 		 */
1458 		case ficlInstructionSlashMod: {
1459 			ficl2Integer n1;
1460 			ficlInteger n2;
1461 			ficl2IntegerQR qr;
1462 
1463 			CHECK_STACK(2, 2);
1464 			n2    = dataTop[0].i;
1465 			FICL_INTEGER_TO_2INTEGER(dataTop[-1].i, n1);
1466 
1467 			qr = ficl2IntegerDivideSymmetric(n1, n2);
1468 			dataTop[-1].i = qr.remainder;
1469 			dataTop[0].i = FICL_2UNSIGNED_GET_LOW(qr.quotient);
1470 			continue;
1471 		}
1472 
1473 		case ficlInstruction2Star:
1474 			CHECK_STACK(1, 1);
1475 			dataTop->i <<= 1;
1476 			continue;
1477 
1478 		case ficlInstruction2Slash:
1479 			CHECK_STACK(1, 1);
1480 			dataTop->i >>= 1;
1481 			continue;
1482 
1483 		case ficlInstructionStarSlash: {
1484 			ficlInteger x, y, z;
1485 			ficl2Integer prod;
1486 			CHECK_STACK(3, 1);
1487 
1488 			z = (dataTop--)->i;
1489 			y = (dataTop--)->i;
1490 			x = dataTop->i;
1491 
1492 			prod = ficl2IntegerMultiply(x, y);
1493 			dataTop->i = FICL_2UNSIGNED_GET_LOW(
1494 			    ficl2IntegerDivideSymmetric(prod, z).quotient);
1495 			continue;
1496 		}
1497 
1498 		case ficlInstructionStarSlashMod: {
1499 			ficlInteger x, y, z;
1500 			ficl2Integer prod;
1501 			ficl2IntegerQR qr;
1502 
1503 			CHECK_STACK(3, 2);
1504 
1505 			z = (dataTop--)->i;
1506 			y = dataTop[0].i;
1507 			x = dataTop[-1].i;
1508 
1509 			prod = ficl2IntegerMultiply(x, y);
1510 			qr   = ficl2IntegerDivideSymmetric(prod, z);
1511 
1512 			dataTop[-1].i = qr.remainder;
1513 			dataTop[0].i = FICL_2UNSIGNED_GET_LOW(qr.quotient);
1514 			continue;
1515 		}
1516 
1517 #if FICL_WANT_FLOAT
1518 		case ficlInstructionF0:
1519 			CHECK_FLOAT_STACK(0, 1);
1520 			(++floatTop)->f = 0.0f;
1521 			continue;
1522 
1523 		case ficlInstructionF1:
1524 			CHECK_FLOAT_STACK(0, 1);
1525 			(++floatTop)->f = 1.0f;
1526 			continue;
1527 
1528 		case ficlInstructionFNeg1:
1529 			CHECK_FLOAT_STACK(0, 1);
1530 			(++floatTop)->f = -1.0f;
1531 			continue;
1532 
1533 		/*
1534 		 * Floating point literal execution word.
1535 		 */
1536 		case ficlInstructionFLiteralParen:
1537 			CHECK_FLOAT_STACK(0, 1);
1538 
1539 			/*
1540 			 * Yes, I'm using ->i here,
1541 			 * but it's really a float.  --lch
1542 			 */
1543 			(++floatTop)->i = *ip++;
1544 			continue;
1545 
1546 		/*
1547 		 * Do float addition r1 + r2.
1548 		 * f+ ( r1 r2 -- r )
1549 		 */
1550 		case ficlInstructionFPlus:
1551 			CHECK_FLOAT_STACK(2, 1);
1552 
1553 			f = (floatTop--)->f;
1554 			floatTop->f += f;
1555 			continue;
1556 
1557 		/*
1558 		 * Do float subtraction r1 - r2.
1559 		 * f- ( r1 r2 -- r )
1560 		 */
1561 		case ficlInstructionFMinus:
1562 			CHECK_FLOAT_STACK(2, 1);
1563 
1564 			f = (floatTop--)->f;
1565 			floatTop->f -= f;
1566 			continue;
1567 
1568 		/*
1569 		 * Do float multiplication r1 * r2.
1570 		 * f* ( r1 r2 -- r )
1571 		 */
1572 		case ficlInstructionFStar:
1573 			CHECK_FLOAT_STACK(2, 1);
1574 
1575 			f = (floatTop--)->f;
1576 			floatTop->f *= f;
1577 			continue;
1578 
1579 		/*
1580 		 * Do float negation.
1581 		 * fnegate ( r -- r )
1582 		 */
1583 		case ficlInstructionFNegate:
1584 			CHECK_FLOAT_STACK(1, 1);
1585 
1586 			floatTop->f = -(floatTop->f);
1587 			continue;
1588 
1589 		/*
1590 		 * Do float division r1 / r2.
1591 		 * f/ ( r1 r2 -- r )
1592 		 */
1593 		case ficlInstructionFSlash:
1594 			CHECK_FLOAT_STACK(2, 1);
1595 
1596 			f = (floatTop--)->f;
1597 			floatTop->f /= f;
1598 			continue;
1599 
1600 		/*
1601 		 * Do float + integer r + n.
1602 		 * f+i ( r n -- r )
1603 		 */
1604 		case ficlInstructionFPlusI:
1605 			CHECK_FLOAT_STACK(1, 1);
1606 			CHECK_STACK(1, 0);
1607 
1608 			f = (ficlFloat)(dataTop--)->f;
1609 			floatTop->f += f;
1610 			continue;
1611 
1612 		/*
1613 		 * Do float - integer r - n.
1614 		 * f-i ( r n -- r )
1615 		 */
1616 		case ficlInstructionFMinusI:
1617 			CHECK_FLOAT_STACK(1, 1);
1618 			CHECK_STACK(1, 0);
1619 
1620 			f = (ficlFloat)(dataTop--)->f;
1621 			floatTop->f -= f;
1622 			continue;
1623 
1624 		/*
1625 		 * Do float * integer r * n.
1626 		 * f*i ( r n -- r )
1627 		 */
1628 		case ficlInstructionFStarI:
1629 			CHECK_FLOAT_STACK(1, 1);
1630 			CHECK_STACK(1, 0);
1631 
1632 			f = (ficlFloat)(dataTop--)->f;
1633 			floatTop->f *= f;
1634 			continue;
1635 
1636 		/*
1637 		 * Do float / integer r / n.
1638 		 * f/i ( r n -- r )
1639 		 */
1640 		case ficlInstructionFSlashI:
1641 			CHECK_FLOAT_STACK(1, 1);
1642 			CHECK_STACK(1, 0);
1643 
1644 			f = (ficlFloat)(dataTop--)->f;
1645 			floatTop->f /= f;
1646 			continue;
1647 
1648 		/*
1649 		 * Do integer - float n - r.
1650 		 * i-f ( n r -- r )
1651 		 */
1652 		case ficlInstructionIMinusF:
1653 			CHECK_FLOAT_STACK(1, 1);
1654 			CHECK_STACK(1, 0);
1655 
1656 			f = (ficlFloat)(dataTop--)->f;
1657 			floatTop->f = f - floatTop->f;
1658 			continue;
1659 
1660 		/*
1661 		 * Do integer / float n / r.
1662 		 * i/f ( n r -- r )
1663 		 */
1664 		case ficlInstructionISlashF:
1665 			CHECK_FLOAT_STACK(1, 1);
1666 			CHECK_STACK(1, 0);
1667 
1668 			f = (ficlFloat)(dataTop--)->f;
1669 			floatTop->f = f / floatTop->f;
1670 			continue;
1671 
1672 		/*
1673 		 * Do integer to float conversion.
1674 		 * int>float ( n -- r )
1675 		 */
1676 		case ficlInstructionIntToFloat:
1677 			CHECK_STACK(1, 0);
1678 			CHECK_FLOAT_STACK(0, 1);
1679 
1680 			(++floatTop)->f = ((dataTop--)->f);
1681 			continue;
1682 
1683 		/*
1684 		 * Do float to integer conversion.
1685 		 * float>int ( r -- n )
1686 		 */
1687 		case ficlInstructionFloatToInt:
1688 			CHECK_STACK(0, 1);
1689 			CHECK_FLOAT_STACK(1, 0);
1690 
1691 			(++dataTop)->i = ((floatTop--)->i);
1692 			continue;
1693 
1694 		/*
1695 		 * Add a floating point number to contents of a variable.
1696 		 * f+! ( r n -- )
1697 		 */
1698 		case ficlInstructionFPlusStore: {
1699 			ficlCell *cell;
1700 
1701 			CHECK_STACK(1, 0);
1702 			CHECK_FLOAT_STACK(1, 0);
1703 
1704 			cell = (ficlCell *)(dataTop--)->p;
1705 			cell->f += (floatTop--)->f;
1706 			continue;
1707 		}
1708 
1709 		/*
1710 		 * Do float stack drop.
1711 		 * fdrop ( r -- )
1712 		 */
1713 		case ficlInstructionFDrop:
1714 			CHECK_FLOAT_STACK(1, 0);
1715 			floatTop--;
1716 			continue;
1717 
1718 		/*
1719 		 * Do float stack ?dup.
1720 		 * f?dup ( r -- r )
1721 		 */
1722 		case ficlInstructionFQuestionDup:
1723 			CHECK_FLOAT_STACK(1, 2);
1724 
1725 			if (floatTop->f != 0)
1726 				goto FDUP;
1727 
1728 			continue;
1729 
1730 		/*
1731 		 * Do float stack dup.
1732 		 * fdup ( r -- r r )
1733 		 */
1734 		case ficlInstructionFDup:
1735 			CHECK_FLOAT_STACK(1, 2);
1736 
1737 FDUP:
1738 			floatTop[1] = floatTop[0];
1739 			floatTop++;
1740 			continue;
1741 
1742 		/*
1743 		 * Do float stack swap.
1744 		 * fswap ( r1 r2 -- r2 r1 )
1745 		 */
1746 		case ficlInstructionFSwap:
1747 			CHECK_FLOAT_STACK(2, 2);
1748 
1749 			c = floatTop[0];
1750 			floatTop[0] = floatTop[-1];
1751 			floatTop[-1] = c;
1752 			continue;
1753 
1754 		/*
1755 		 * Do float stack 2drop.
1756 		 * f2drop ( r r -- )
1757 		 */
1758 		case ficlInstructionF2Drop:
1759 			CHECK_FLOAT_STACK(2, 0);
1760 
1761 			floatTop -= 2;
1762 			continue;
1763 
1764 		/*
1765 		 * Do float stack 2dup.
1766 		 * f2dup ( r1 r2 -- r1 r2 r1 r2 )
1767 		 */
1768 		case ficlInstructionF2Dup:
1769 			CHECK_FLOAT_STACK(2, 4);
1770 
1771 			floatTop[1] = floatTop[-1];
1772 			floatTop[2] = *floatTop;
1773 			floatTop += 2;
1774 			continue;
1775 
1776 		/*
1777 		 * Do float stack over.
1778 		 * fover ( r1 r2 -- r1 r2 r1 )
1779 		 */
1780 		case ficlInstructionFOver:
1781 			CHECK_FLOAT_STACK(2, 3);
1782 
1783 			floatTop[1] = floatTop[-1];
1784 			floatTop++;
1785 			continue;
1786 
1787 		/*
1788 		 * Do float stack 2over.
1789 		 * f2over ( r1 r2 r3 -- r1 r2 r3 r1 r2 )
1790 		 */
1791 		case ficlInstructionF2Over:
1792 			CHECK_FLOAT_STACK(4, 6);
1793 
1794 			floatTop[1] = floatTop[-2];
1795 			floatTop[2] = floatTop[-1];
1796 			floatTop += 2;
1797 			continue;
1798 
1799 		/*
1800 		 * Do float stack pick.
1801 		 * fpick ( n -- r )
1802 		 */
1803 		case ficlInstructionFPick:
1804 			CHECK_STACK(1, 0);
1805 			c = *dataTop--;
1806 			CHECK_FLOAT_STACK(c.i+2, c.i+3);
1807 
1808 			floatTop[1] = floatTop[- c.i - 1];
1809 			continue;
1810 
1811 		/*
1812 		 * Do float stack rot.
1813 		 * frot ( r1 r2 r3  -- r2 r3 r1 )
1814 		 */
1815 		case ficlInstructionFRot:
1816 			i = 2;
1817 		goto FROLL;
1818 
1819 		/*
1820 		 * Do float stack roll.
1821 		 * froll ( n -- )
1822 		 */
1823 		case ficlInstructionFRoll:
1824 			CHECK_STACK(1, 0);
1825 			i = (dataTop--)->i;
1826 
1827 			if (i < 1)
1828 				continue;
1829 
1830 FROLL:
1831 			CHECK_FLOAT_STACK(i+1, i+2);
1832 			c = floatTop[-i];
1833 			memmove(floatTop - i, floatTop - (i - 1),
1834 			    i * sizeof (ficlCell));
1835 			*floatTop = c;
1836 
1837 			continue;
1838 
1839 		/*
1840 		 * Do float stack -rot.
1841 		 * f-rot ( r1 r2 r3  -- r3 r1 r2 )
1842 		 */
1843 		case ficlInstructionFMinusRot:
1844 			i = 2;
1845 			goto FMINUSROLL;
1846 
1847 
1848 		/*
1849 		 * Do float stack -roll.
1850 		 * f-roll ( n -- )
1851 		 */
1852 		case ficlInstructionFMinusRoll:
1853 			CHECK_STACK(1, 0);
1854 			i = (dataTop--)->i;
1855 
1856 			if (i < 1)
1857 				continue;
1858 
1859 FMINUSROLL:
1860 			CHECK_FLOAT_STACK(i+1, i+2);
1861 			c = *floatTop;
1862 			memmove(floatTop - (i - 1), floatTop - i,
1863 			    i * sizeof (ficlCell));
1864 			floatTop[-i] = c;
1865 
1866 			continue;
1867 
1868 		/*
1869 		 * Do float stack 2swap
1870 		 * f2swap ( r1 r2 r3 r4  -- r3 r4 r1 r2 )
1871 		 */
1872 		case ficlInstructionF2Swap: {
1873 			ficlCell c2;
1874 			CHECK_FLOAT_STACK(4, 4);
1875 
1876 			c = *floatTop;
1877 			c2 = floatTop[-1];
1878 
1879 			*floatTop = floatTop[-2];
1880 			floatTop[-1] = floatTop[-3];
1881 
1882 			floatTop[-2] = c;
1883 			floatTop[-3] = c2;
1884 			continue;
1885 		}
1886 
1887 		/*
1888 		 * Do float 0= comparison r = 0.0.
1889 		 * f0= ( r -- T/F )
1890 		 */
1891 		case ficlInstructionF0Equals:
1892 			CHECK_FLOAT_STACK(1, 0);
1893 			CHECK_STACK(0, 1);
1894 
1895 			(++dataTop)->i = FICL_BOOL((floatTop--)->f != 0.0f);
1896 			continue;
1897 
1898 		/*
1899 		 * Do float 0< comparison r < 0.0.
1900 		 * f0< ( r -- T/F )
1901 		 */
1902 		case ficlInstructionF0Less:
1903 			CHECK_FLOAT_STACK(1, 0);
1904 			CHECK_STACK(0, 1);
1905 
1906 			(++dataTop)->i = FICL_BOOL((floatTop--)->f < 0.0f);
1907 			continue;
1908 
1909 		/*
1910 		 * Do float 0> comparison r > 0.0.
1911 		 * f0> ( r -- T/F )
1912 		 */
1913 		case ficlInstructionF0Greater:
1914 			CHECK_FLOAT_STACK(1, 0);
1915 			CHECK_STACK(0, 1);
1916 
1917 			(++dataTop)->i = FICL_BOOL((floatTop--)->f > 0.0f);
1918 			continue;
1919 
1920 		/*
1921 		 * Do float = comparison r1 = r2.
1922 		 * f= ( r1 r2 -- T/F )
1923 		 */
1924 		case ficlInstructionFEquals:
1925 			CHECK_FLOAT_STACK(2, 0);
1926 			CHECK_STACK(0, 1);
1927 
1928 			f = (floatTop--)->f;
1929 			(++dataTop)->i = FICL_BOOL((floatTop--)->f == f);
1930 			continue;
1931 
1932 		/*
1933 		 * Do float < comparison r1 < r2.
1934 		 * f< ( r1 r2 -- T/F )
1935 		 */
1936 		case ficlInstructionFLess:
1937 			CHECK_FLOAT_STACK(2, 0);
1938 			CHECK_STACK(0, 1);
1939 
1940 			f = (floatTop--)->f;
1941 			(++dataTop)->i = FICL_BOOL((floatTop--)->f < f);
1942 			continue;
1943 
1944 		/*
1945 		 * Do float > comparison r1 > r2.
1946 		 * f> ( r1 r2 -- T/F )
1947 		 */
1948 		case ficlInstructionFGreater:
1949 			CHECK_FLOAT_STACK(2, 0);
1950 			CHECK_STACK(0, 1);
1951 
1952 			f = (floatTop--)->f;
1953 			(++dataTop)->i = FICL_BOOL((floatTop--)->f > f);
1954 			continue;
1955 
1956 
1957 		/*
1958 		 * Move float to param stack (assumes they both fit in a
1959 		 * single ficlCell) f>s
1960 		 */
1961 		case ficlInstructionFFrom:
1962 			CHECK_FLOAT_STACK(1, 0);
1963 			CHECK_STACK(0, 1);
1964 
1965 			*++dataTop = *floatTop--;
1966 			continue;
1967 
1968 		case ficlInstructionToF:
1969 			CHECK_FLOAT_STACK(0, 1);
1970 			CHECK_STACK(1, 0);
1971 
1972 			*++floatTop = *dataTop--;
1973 			continue;
1974 
1975 #endif /* FICL_WANT_FLOAT */
1976 
1977 		/*
1978 		 * c o l o n P a r e n
1979 		 * This is the code that executes a colon definition. It
1980 		 * assumes that the virtual machine is running a "next" loop
1981 		 * (See the vm.c for its implementation of member function
1982 		 * vmExecute()). The colon code simply copies the address of
1983 		 * the first word in the list of words to interpret into IP
1984 		 * after saving its old value. When we return to the "next"
1985 		 * loop, the virtual machine will call the code for each
1986 		 * word in turn.
1987 		 */
1988 		case ficlInstructionColonParen:
1989 			(++returnTop)->p = (void *)ip;
1990 			ip = (ficlInstruction *)(fw->param);
1991 			continue;
1992 
1993 		case ficlInstructionCreateParen:
1994 			CHECK_STACK(0, 1);
1995 			(++dataTop)->p = (fw->param + 1);
1996 			continue;
1997 
1998 		case ficlInstructionVariableParen:
1999 			CHECK_STACK(0, 1);
2000 			(++dataTop)->p = fw->param;
2001 			continue;
2002 
2003 		/*
2004 		 * c o n s t a n t P a r e n
2005 		 * This is the run-time code for "constant". It simply returns
2006 		 * the contents of its word's first data ficlCell.
2007 		 */
2008 
2009 #if FICL_WANT_FLOAT
2010 		case ficlInstructionF2ConstantParen:
2011 			CHECK_FLOAT_STACK(0, 2);
2012 			FLOAT_PUSH_CELL_POINTER_DOUBLE(fw->param);
2013 
2014 		case ficlInstructionFConstantParen:
2015 			CHECK_FLOAT_STACK(0, 1);
2016 			FLOAT_PUSH_CELL_POINTER(fw->param);
2017 #endif /* FICL_WANT_FLOAT */
2018 
2019 		case ficlInstruction2ConstantParen:
2020 			CHECK_STACK(0, 2);
2021 			PUSH_CELL_POINTER_DOUBLE(fw->param);
2022 
2023 		case ficlInstructionConstantParen:
2024 			CHECK_STACK(0, 1);
2025 			PUSH_CELL_POINTER(fw->param);
2026 
2027 #if FICL_WANT_USER
2028 		case ficlInstructionUserParen: {
2029 			ficlInteger i = fw->param[0].i;
2030 			(++dataTop)->p = &vm->user[i];
2031 			continue;
2032 		}
2033 #endif
2034 
2035 		default:
2036 		/*
2037 		 * Clever hack, or evil coding?  You be the judge.
2038 		 *
2039 		 * If the word we've been asked to execute is in fact
2040 		 * an *instruction*, we grab the instruction, stow it
2041 		 * in "i" (our local cache of *ip), and *jump* to the
2042 		 * top of the switch statement.  --lch
2043 		 */
2044 			if (((ficlInstruction)fw->code >
2045 			    ficlInstructionInvalid) &&
2046 			    ((ficlInstruction)fw->code < ficlInstructionLast)) {
2047 				instruction = (ficlInstruction)fw->code;
2048 				goto AGAIN;
2049 			}
2050 
2051 			LOCAL_VARIABLE_SPILL;
2052 			(vm)->runningWord = fw;
2053 			fw->code(vm);
2054 			LOCAL_VARIABLE_REFILL;
2055 			continue;
2056 		}
2057 	}
2058 
2059 	LOCAL_VARIABLE_SPILL;
2060 	vm->exceptionHandler = oldExceptionHandler;
2061 }
2062 
2063 /*
2064  * v m G e t D i c t
2065  * Returns the address dictionary for this VM's system
2066  */
2067 ficlDictionary *
2068 ficlVmGetDictionary(ficlVm *vm)
2069 {
2070 	FICL_VM_ASSERT(vm, vm);
2071 	return (vm->callback.system->dictionary);
2072 }
2073 
2074 /*
2075  * v m G e t S t r i n g
2076  * Parses a string out of the VM input buffer and copies up to the first
2077  * FICL_COUNTED_STRING_MAX characters to the supplied destination buffer, a
2078  * ficlCountedString. The destination string is NULL terminated.
2079  *
2080  * Returns the address of the first unused character in the dest buffer.
2081  */
2082 char *
2083 ficlVmGetString(ficlVm *vm, ficlCountedString *counted, char delimiter)
2084 {
2085 	ficlString s = ficlVmParseStringEx(vm, delimiter, 0);
2086 
2087 	if (FICL_STRING_GET_LENGTH(s) > FICL_COUNTED_STRING_MAX) {
2088 		FICL_STRING_SET_LENGTH(s, FICL_COUNTED_STRING_MAX);
2089 	}
2090 
2091 	(void) strncpy(counted->text, FICL_STRING_GET_POINTER(s),
2092 	    FICL_STRING_GET_LENGTH(s));
2093 	counted->text[FICL_STRING_GET_LENGTH(s)] = '\0';
2094 	counted->length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(s);
2095 
2096 	return (counted->text + FICL_STRING_GET_LENGTH(s) + 1);
2097 }
2098 
2099 /*
2100  * v m G e t W o r d
2101  * vmGetWord calls vmGetWord0 repeatedly until it gets a string with
2102  * non-zero length.
2103  */
2104 ficlString
2105 ficlVmGetWord(ficlVm *vm)
2106 {
2107 	ficlString s = ficlVmGetWord0(vm);
2108 
2109 	if (FICL_STRING_GET_LENGTH(s) == 0) {
2110 		ficlVmThrow(vm, FICL_VM_STATUS_RESTART);
2111 	}
2112 
2113 	return (s);
2114 }
2115 
2116 /*
2117  * v m G e t W o r d 0
2118  * Skip leading whitespace and parse a space delimited word from the tib.
2119  * Returns the start address and length of the word. Updates the tib
2120  * to reflect characters consumed, including the trailing delimiter.
2121  * If there's nothing of interest in the tib, returns zero. This function
2122  * does not use vmParseString because it uses isspace() rather than a
2123  * single  delimiter character.
2124  */
2125 ficlString
2126 ficlVmGetWord0(ficlVm *vm)
2127 {
2128 	char *trace = ficlVmGetInBuf(vm);
2129 	char *stop = ficlVmGetInBufEnd(vm);
2130 	ficlString s;
2131 	ficlUnsigned length = 0;
2132 	char c = 0;
2133 
2134 	trace = ficlStringSkipSpace(trace, stop);
2135 	FICL_STRING_SET_POINTER(s, trace);
2136 
2137 	/* Please leave this loop this way; it makes Purify happier.  --lch */
2138 	for (;;) {
2139 		if (trace == stop)
2140 			break;
2141 		c = *trace;
2142 		if (isspace((unsigned char)c))
2143 			break;
2144 		length++;
2145 		trace++;
2146 	}
2147 
2148 	FICL_STRING_SET_LENGTH(s, length);
2149 
2150 	/* skip one trailing delimiter */
2151 	if ((trace != stop) && isspace((unsigned char)c))
2152 		trace++;
2153 
2154 	ficlVmUpdateTib(vm, trace);
2155 
2156 	return (s);
2157 }
2158 
2159 /*
2160  * v m G e t W o r d T o P a d
2161  * Does vmGetWord and copies the result to the pad as a NULL terminated
2162  * string. Returns the length of the string. If the string is too long
2163  * to fit in the pad, it is truncated.
2164  */
2165 int
2166 ficlVmGetWordToPad(ficlVm *vm)
2167 {
2168 	ficlString s;
2169 	char *pad = (char *)vm->pad;
2170 	s = ficlVmGetWord(vm);
2171 
2172 	if (FICL_STRING_GET_LENGTH(s) >= FICL_PAD_SIZE)
2173 		FICL_STRING_SET_LENGTH(s, FICL_PAD_SIZE - 1);
2174 
2175 	(void) strncpy(pad, FICL_STRING_GET_POINTER(s),
2176 	    FICL_STRING_GET_LENGTH(s));
2177 	pad[FICL_STRING_GET_LENGTH(s)] = '\0';
2178 	return ((int)(FICL_STRING_GET_LENGTH(s)));
2179 }
2180 
2181 /*
2182  * v m P a r s e S t r i n g
2183  * Parses a string out of the input buffer using the delimiter
2184  * specified. Skips leading delimiters, marks the start of the string,
2185  * and counts characters to the next delimiter it encounters. It then
2186  * updates the vm input buffer to consume all these chars, including the
2187  * trailing delimiter.
2188  * Returns the address and length of the parsed string, not including the
2189  * trailing delimiter.
2190  */
2191 ficlString
2192 ficlVmParseString(ficlVm *vm, char delimiter)
2193 {
2194 	return (ficlVmParseStringEx(vm, delimiter, 1));
2195 }
2196 
2197 ficlString
2198 ficlVmParseStringEx(ficlVm *vm, char delimiter, char skipLeadingDelimiters)
2199 {
2200 	ficlString s;
2201 	char *trace = ficlVmGetInBuf(vm);
2202 	char *stop = ficlVmGetInBufEnd(vm);
2203 	char c;
2204 
2205 	if (skipLeadingDelimiters) {
2206 		while ((trace != stop) && (*trace == delimiter))
2207 			trace++;
2208 	}
2209 
2210 	FICL_STRING_SET_POINTER(s, trace);    /* mark start of text */
2211 
2212 	/* find next delimiter or end of line */
2213 	for (c = *trace;
2214 	    (trace != stop) && (c != delimiter) && (c != '\r') && (c != '\n');
2215 	    c = *++trace) {
2216 		;
2217 	}
2218 
2219 	/* set length of result */
2220 	FICL_STRING_SET_LENGTH(s, trace - FICL_STRING_GET_POINTER(s));
2221 
2222 	/* gobble trailing delimiter */
2223 	if ((trace != stop) && (*trace == delimiter))
2224 		trace++;
2225 
2226 	ficlVmUpdateTib(vm, trace);
2227 	return (s);
2228 }
2229 
2230 
2231 /*
2232  * v m P o p
2233  */
2234 ficlCell
2235 ficlVmPop(ficlVm *vm)
2236 {
2237 	return (ficlStackPop(vm->dataStack));
2238 }
2239 
2240 /*
2241  * v m P u s h
2242  */
2243 void
2244 ficlVmPush(ficlVm *vm, ficlCell c)
2245 {
2246 	ficlStackPush(vm->dataStack, c);
2247 }
2248 
2249 /*
2250  * v m P o p I P
2251  */
2252 void
2253 ficlVmPopIP(ficlVm *vm)
2254 {
2255 	vm->ip = (ficlIp)(ficlStackPopPointer(vm->returnStack));
2256 }
2257 
2258 /*
2259  * v m P u s h I P
2260  */
2261 void
2262 ficlVmPushIP(ficlVm *vm, ficlIp newIP)
2263 {
2264 	ficlStackPushPointer(vm->returnStack, (void *)vm->ip);
2265 	vm->ip = newIP;
2266 }
2267 
2268 /*
2269  * v m P u s h T i b
2270  * Binds the specified input string to the VM and clears >IN (the index)
2271  */
2272 void
2273 ficlVmPushTib(ficlVm *vm, char *text, ficlInteger nChars, ficlTIB *pSaveTib)
2274 {
2275 	if (pSaveTib) {
2276 		*pSaveTib = vm->tib;
2277 	}
2278 	vm->tib.text = text;
2279 	vm->tib.end = text + nChars;
2280 	vm->tib.index = 0;
2281 }
2282 
2283 void
2284 ficlVmPopTib(ficlVm *vm, ficlTIB *pTib)
2285 {
2286 	if (pTib) {
2287 		vm->tib = *pTib;
2288 	}
2289 }
2290 
2291 /*
2292  * v m Q u i t
2293  */
2294 void
2295 ficlVmQuit(ficlVm *vm)
2296 {
2297 	ficlStackReset(vm->returnStack);
2298 	vm->restart = 0;
2299 	vm->ip = NULL;
2300 	vm->runningWord = NULL;
2301 	vm->state = FICL_VM_STATE_INTERPRET;
2302 	vm->tib.text = NULL;
2303 	vm->tib.end = NULL;
2304 	vm->tib.index = 0;
2305 	vm->pad[0] = '\0';
2306 	vm->sourceId.i = 0;
2307 }
2308 
2309 /*
2310  * v m R e s e t
2311  */
2312 void
2313 ficlVmReset(ficlVm *vm)
2314 {
2315 	ficlVmQuit(vm);
2316 	ficlStackReset(vm->dataStack);
2317 #if FICL_WANT_FLOAT
2318 	ficlStackReset(vm->floatStack);
2319 #endif
2320 	vm->base = 10;
2321 }
2322 
2323 /*
2324  * v m S e t T e x t O u t
2325  * Binds the specified output callback to the vm. If you pass NULL,
2326  * binds the default output function (ficlTextOut)
2327  */
2328 void
2329 ficlVmSetTextOut(ficlVm *vm, ficlOutputFunction textOut)
2330 {
2331 	vm->callback.textOut = textOut;
2332 }
2333 
2334 void
2335 ficlVmTextOut(ficlVm *vm, char *text)
2336 {
2337 	ficlCallbackTextOut((ficlCallback *)vm, text);
2338 }
2339 
2340 
2341 void
2342 ficlVmErrorOut(ficlVm *vm, char *text)
2343 {
2344 	ficlCallbackErrorOut((ficlCallback *)vm, text);
2345 }
2346 
2347 
2348 /*
2349  * v m T h r o w
2350  */
2351 void
2352 ficlVmThrow(ficlVm *vm, int except)
2353 {
2354 	if (vm->exceptionHandler)
2355 		longjmp(*(vm->exceptionHandler), except);
2356 }
2357 
2358 void
2359 ficlVmThrowError(ficlVm *vm, char *fmt, ...)
2360 {
2361 	va_list list;
2362 
2363 	va_start(list, fmt);
2364 	(void) vsprintf(vm->pad, fmt, list);
2365 	va_end(list);
2366 	(void) strcat(vm->pad, "\n");
2367 
2368 	ficlVmErrorOut(vm, vm->pad);
2369 	longjmp(*(vm->exceptionHandler), FICL_VM_STATUS_ERROR_EXIT);
2370 }
2371 
2372 void
2373 ficlVmThrowErrorVararg(ficlVm *vm, char *fmt, va_list list)
2374 {
2375 	(void) vsprintf(vm->pad, fmt, list);
2376 	/*
2377 	 * well, we can try anyway, we're certainly not
2378 	 * returning to our caller!
2379 	 */
2380 	va_end(list);
2381 	(void) strcat(vm->pad, "\n");
2382 
2383 	ficlVmErrorOut(vm, vm->pad);
2384 	longjmp(*(vm->exceptionHandler), FICL_VM_STATUS_ERROR_EXIT);
2385 }
2386 
2387 /*
2388  * f i c l E v a l u a t e
2389  * Wrapper for ficlExec() which sets SOURCE-ID to -1.
2390  */
2391 int
2392 ficlVmEvaluate(ficlVm *vm, char *s)
2393 {
2394 	int returnValue;
2395 	ficlCell id = vm->sourceId;
2396 	ficlString string;
2397 	vm->sourceId.i = -1;
2398 	FICL_STRING_SET_FROM_CSTRING(string, s);
2399 	returnValue = ficlVmExecuteString(vm, string);
2400 	vm->sourceId = id;
2401 	return (returnValue);
2402 }
2403 
2404 /*
2405  * f i c l E x e c
2406  * Evaluates a block of input text in the context of the
2407  * specified interpreter. Emits any requested output to the
2408  * interpreter's output function.
2409  *
2410  * Contains the "inner interpreter" code in a tight loop
2411  *
2412  * Returns one of the VM_XXXX codes defined in ficl.h:
2413  * VM_OUTOFTEXT is the normal exit condition
2414  * VM_ERREXIT means that the interpreter encountered a syntax error
2415  *      and the vm has been reset to recover (some or all
2416  *      of the text block got ignored
2417  * VM_USEREXIT means that the user executed the "bye" command
2418  *      to shut down the interpreter. This would be a good
2419  *      time to delete the vm, etc -- or you can ignore this
2420  *      signal.
2421  */
2422 int
2423 ficlVmExecuteString(ficlVm *vm, ficlString s)
2424 {
2425 	ficlSystem *system = vm->callback.system;
2426 	ficlDictionary *dictionary = system->dictionary;
2427 
2428 	int except;
2429 	jmp_buf vmState;
2430 	jmp_buf *oldState;
2431 	ficlTIB saveficlTIB;
2432 
2433 	FICL_VM_ASSERT(vm, vm);
2434 	FICL_VM_ASSERT(vm, system->interpreterLoop[0]);
2435 
2436 	ficlVmPushTib(vm, FICL_STRING_GET_POINTER(s),
2437 	    FICL_STRING_GET_LENGTH(s), &saveficlTIB);
2438 
2439 	/*
2440 	 * Save and restore VM's jmp_buf to enable nested calls to ficlExec
2441 	 */
2442 	oldState = vm->exceptionHandler;
2443 
2444 	/* This has to come before the setjmp! */
2445 	vm->exceptionHandler = &vmState;
2446 	except = setjmp(vmState);
2447 
2448 	switch (except) {
2449 	case 0:
2450 		if (vm->restart) {
2451 			vm->runningWord->code(vm);
2452 			vm->restart = 0;
2453 		} else {	/* set VM up to interpret text */
2454 			ficlVmPushIP(vm, &(system->interpreterLoop[0]));
2455 		}
2456 
2457 		ficlVmInnerLoop(vm, 0);
2458 	break;
2459 
2460 	case FICL_VM_STATUS_RESTART:
2461 		vm->restart = 1;
2462 		except = FICL_VM_STATUS_OUT_OF_TEXT;
2463 	break;
2464 
2465 	case FICL_VM_STATUS_OUT_OF_TEXT:
2466 		ficlVmPopIP(vm);
2467 #if 0	/* we dont output prompt in loader */
2468 		if ((vm->state != FICL_VM_STATE_COMPILE) &&
2469 		    (vm->sourceId.i == 0))
2470 			ficlVmTextOut(vm, FICL_PROMPT);
2471 #endif
2472 	break;
2473 
2474 	case FICL_VM_STATUS_USER_EXIT:
2475 	case FICL_VM_STATUS_INNER_EXIT:
2476 	case FICL_VM_STATUS_BREAK:
2477 	break;
2478 
2479 	case FICL_VM_STATUS_QUIT:
2480 		if (vm->state == FICL_VM_STATE_COMPILE) {
2481 			ficlDictionaryAbortDefinition(dictionary);
2482 #if FICL_WANT_LOCALS
2483 			ficlDictionaryEmpty(system->locals,
2484 			    system->locals->forthWordlist->size);
2485 #endif
2486 		}
2487 		ficlVmQuit(vm);
2488 	break;
2489 
2490 	case FICL_VM_STATUS_ERROR_EXIT:
2491 	case FICL_VM_STATUS_ABORT:
2492 	case FICL_VM_STATUS_ABORTQ:
2493 	default:		/* user defined exit code?? */
2494 		if (vm->state == FICL_VM_STATE_COMPILE) {
2495 			ficlDictionaryAbortDefinition(dictionary);
2496 #if FICL_WANT_LOCALS
2497 			ficlDictionaryEmpty(system->locals,
2498 			    system->locals->forthWordlist->size);
2499 #endif
2500 		}
2501 		ficlDictionaryResetSearchOrder(dictionary);
2502 		ficlVmReset(vm);
2503 	break;
2504 	}
2505 
2506 	vm->exceptionHandler = oldState;
2507 	ficlVmPopTib(vm, &saveficlTIB);
2508 	return (except);
2509 }
2510 
2511 /*
2512  * f i c l E x e c X T
2513  * Given a pointer to a ficlWord, push an inner interpreter and
2514  * execute the word to completion. This is in contrast with vmExecute,
2515  * which does not guarantee that the word will have completed when
2516  * the function returns (ie in the case of colon definitions, which
2517  * need an inner interpreter to finish)
2518  *
2519  * Returns one of the VM_XXXX exception codes listed in ficl.h. Normal
2520  * exit condition is VM_INNEREXIT, Ficl's private signal to exit the
2521  * inner loop under normal circumstances. If another code is thrown to
2522  * exit the loop, this function will re-throw it if it's nested under
2523  * itself or ficlExec.
2524  *
2525  * NOTE: this function is intended so that C code can execute ficlWords
2526  * given their address in the dictionary (xt).
2527  */
2528 int
2529 ficlVmExecuteXT(ficlVm *vm, ficlWord *pWord)
2530 {
2531 	int except;
2532 	jmp_buf vmState;
2533 	jmp_buf *oldState;
2534 	ficlWord *oldRunningWord;
2535 
2536 	FICL_VM_ASSERT(vm, vm);
2537 	FICL_VM_ASSERT(vm, vm->callback.system->exitInnerWord);
2538 
2539 	/*
2540 	 * Save the runningword so that RESTART behaves correctly
2541 	 * over nested calls.
2542 	 */
2543 	oldRunningWord = vm->runningWord;
2544 	/*
2545 	 * Save and restore VM's jmp_buf to enable nested calls
2546 	 */
2547 	oldState = vm->exceptionHandler;
2548 	/* This has to come before the setjmp! */
2549 	vm->exceptionHandler = &vmState;
2550 	except = setjmp(vmState);
2551 
2552 	if (except)
2553 		ficlVmPopIP(vm);
2554 	else
2555 		ficlVmPushIP(vm, &(vm->callback.system->exitInnerWord));
2556 
2557 	switch (except) {
2558 	case 0:
2559 		ficlVmExecuteWord(vm, pWord);
2560 		ficlVmInnerLoop(vm, 0);
2561 	break;
2562 
2563 	case FICL_VM_STATUS_INNER_EXIT:
2564 	case FICL_VM_STATUS_BREAK:
2565 	break;
2566 
2567 	case FICL_VM_STATUS_RESTART:
2568 	case FICL_VM_STATUS_OUT_OF_TEXT:
2569 	case FICL_VM_STATUS_USER_EXIT:
2570 	case FICL_VM_STATUS_QUIT:
2571 	case FICL_VM_STATUS_ERROR_EXIT:
2572 	case FICL_VM_STATUS_ABORT:
2573 	case FICL_VM_STATUS_ABORTQ:
2574 	default:		/* user defined exit code?? */
2575 		if (oldState) {
2576 			vm->exceptionHandler = oldState;
2577 			ficlVmThrow(vm, except);
2578 		}
2579 	break;
2580 	}
2581 
2582 	vm->exceptionHandler = oldState;
2583 	vm->runningWord = oldRunningWord;
2584 	return (except);
2585 }
2586 
2587 /*
2588  * f i c l P a r s e N u m b e r
2589  * Attempts to convert the NULL terminated string in the VM's pad to
2590  * a number using the VM's current base. If successful, pushes the number
2591  * onto the param stack and returns FICL_TRUE. Otherwise, returns FICL_FALSE.
2592  * (jws 8/01) Trailing decimal point causes a zero ficlCell to be pushed. (See
2593  * the standard for DOUBLE wordset.
2594  */
2595 int
2596 ficlVmParseNumber(ficlVm *vm, ficlString s)
2597 {
2598 	ficlInteger accumulator = 0;
2599 	char isNegative = 0;
2600 	char isDouble = 0;
2601 	unsigned base = vm->base;
2602 	char *trace = FICL_STRING_GET_POINTER(s);
2603 	ficlUnsigned8 length = (ficlUnsigned8)FICL_STRING_GET_LENGTH(s);
2604 	unsigned c;
2605 	unsigned digit;
2606 
2607 	if (length > 1) {
2608 		switch (*trace) {
2609 		case '-':
2610 			trace++;
2611 			length--;
2612 			isNegative = 1;
2613 		break;
2614 		case '+':
2615 			trace++;
2616 			length--;
2617 			isNegative = 0;
2618 		break;
2619 		default:
2620 		break;
2621 		}
2622 	}
2623 
2624 	/* detect & remove trailing decimal */
2625 	if ((length > 0) && (trace[length - 1] == '.')) {
2626 		isDouble = 1;
2627 		length--;
2628 	}
2629 
2630 	if (length == 0)		/* detect "+", "-", ".", "+." etc */
2631 		return (0);		/* false */
2632 
2633 	while ((length--) && ((c = *trace++) != '\0')) {
2634 		if (!isalnum(c))
2635 			return (0);	/* false */
2636 
2637 		digit = c - '0';
2638 
2639 		if (digit > 9)
2640 			digit = tolower(c) - 'a' + 10;
2641 
2642 		if (digit >= base)
2643 			return (0);	/* false */
2644 
2645 		accumulator = accumulator * base + digit;
2646 	}
2647 
2648 	if (isNegative)
2649 		accumulator = -accumulator;
2650 
2651 	ficlStackPushInteger(vm->dataStack, accumulator);
2652 	if (vm->state == FICL_VM_STATE_COMPILE)
2653 		ficlPrimitiveLiteralIm(vm);
2654 
2655 	if (isDouble) {			/* simple (required) DOUBLE support */
2656 		if (isNegative)
2657 			ficlStackPushInteger(vm->dataStack, -1);
2658 		else
2659 			ficlStackPushInteger(vm->dataStack, 0);
2660 		if (vm->state == FICL_VM_STATE_COMPILE)
2661 			ficlPrimitiveLiteralIm(vm);
2662 	}
2663 
2664 	return (1); /* true */
2665 }
2666 
2667 /*
2668  * d i c t C h e c k
2669  * Checks the dictionary for corruption and throws appropriate
2670  * errors.
2671  * Input: +n number of ADDRESS UNITS (not ficlCells) proposed to allot
2672  *        -n number of ADDRESS UNITS proposed to de-allot
2673  *         0 just do a consistency check
2674  */
2675 void
2676 ficlVmDictionarySimpleCheck(ficlVm *vm, ficlDictionary *dictionary, int cells)
2677 {
2678 #if FICL_ROBUST >= 1
2679 	if ((cells >= 0) &&
2680 	    (ficlDictionaryCellsAvailable(dictionary) *
2681 	    (int)sizeof (ficlCell) < cells)) {
2682 		ficlVmThrowError(vm, "Error: dictionary full");
2683 	}
2684 
2685 	if ((cells <= 0) &&
2686 	    (ficlDictionaryCellsUsed(dictionary) *
2687 	    (int)sizeof (ficlCell) < -cells)) {
2688 		ficlVmThrowError(vm, "Error: dictionary underflow");
2689 	}
2690 #else /* FICL_ROBUST >= 1 */
2691 	FICL_IGNORE(vm);
2692 	FICL_IGNORE(dictionary);
2693 	FICL_IGNORE(cells);
2694 #endif /* FICL_ROBUST >= 1 */
2695 }
2696 
2697 void
2698 ficlVmDictionaryCheck(ficlVm *vm, ficlDictionary *dictionary, int cells)
2699 {
2700 #if FICL_ROBUST >= 1
2701 	ficlVmDictionarySimpleCheck(vm, dictionary, cells);
2702 
2703 	if (dictionary->wordlistCount > FICL_MAX_WORDLISTS) {
2704 		ficlDictionaryResetSearchOrder(dictionary);
2705 		ficlVmThrowError(vm, "Error: search order overflow");
2706 	} else if (dictionary->wordlistCount < 0) {
2707 		ficlDictionaryResetSearchOrder(dictionary);
2708 		ficlVmThrowError(vm, "Error: search order underflow");
2709 	}
2710 #else /* FICL_ROBUST >= 1 */
2711 	FICL_IGNORE(vm);
2712 	FICL_IGNORE(dictionary);
2713 	FICL_IGNORE(cells);
2714 #endif /* FICL_ROBUST >= 1 */
2715 }
2716 
2717 void
2718 ficlVmDictionaryAllot(ficlVm *vm, ficlDictionary *dictionary, int n)
2719 {
2720 	FICL_VM_DICTIONARY_SIMPLE_CHECK(vm, dictionary, n);
2721 	FICL_IGNORE(vm);
2722 	ficlDictionaryAllot(dictionary, n);
2723 }
2724 
2725 void
2726 ficlVmDictionaryAllotCells(ficlVm *vm, ficlDictionary *dictionary, int cells)
2727 {
2728 	FICL_VM_DICTIONARY_SIMPLE_CHECK(vm, dictionary, cells);
2729 	FICL_IGNORE(vm);
2730 	ficlDictionaryAllotCells(dictionary, cells);
2731 }
2732 
2733 /*
2734  * f i c l P a r s e W o r d
2735  * From the standard, section 3.4
2736  * b) Search the dictionary name space (see 3.4.2). If a definition name
2737  * matching the string is found:
2738  *  1.if interpreting, perform the interpretation semantics of the definition
2739  *  (see 3.4.3.2), and continue at a);
2740  *  2.if compiling, perform the compilation semantics of the definition
2741  *  (see 3.4.3.3), and continue at a).
2742  *
2743  * c) If a definition name matching the string is not found, attempt to
2744  * convert the string to a number (see 3.4.1.3). If successful:
2745  *  1.if interpreting, place the number on the data stack, and continue at a);
2746  *  2.if compiling, FICL_VM_STATE_COMPILE code that when executed will place
2747  *  the number on the stack (see 6.1.1780 LITERAL), and continue at a);
2748  *
2749  * d) If unsuccessful, an ambiguous condition exists (see 3.4.4).
2750  *
2751  * (jws 4/01) Modified to be a ficlParseStep
2752  */
2753 int
2754 ficlVmParseWord(ficlVm *vm, ficlString name)
2755 {
2756 	ficlDictionary *dictionary = ficlVmGetDictionary(vm);
2757 	ficlWord *tempFW;
2758 
2759 	FICL_VM_DICTIONARY_CHECK(vm, dictionary, 0);
2760 	FICL_STACK_CHECK(vm->dataStack, 0, 0);
2761 
2762 #if FICL_WANT_LOCALS
2763 	if (vm->callback.system->localsCount > 0) {
2764 		tempFW = ficlSystemLookupLocal(vm->callback.system, name);
2765 	} else
2766 #endif
2767 		tempFW = ficlDictionaryLookup(dictionary, name);
2768 
2769 	if (vm->state == FICL_VM_STATE_INTERPRET) {
2770 		if (tempFW != NULL) {
2771 			if (ficlWordIsCompileOnly(tempFW)) {
2772 				ficlVmThrowError(vm,
2773 				    "Error: FICL_VM_STATE_COMPILE only!");
2774 			}
2775 
2776 			ficlVmExecuteWord(vm, tempFW);
2777 			return (1); /* true */
2778 		}
2779 	} else {	/* (vm->state == FICL_VM_STATE_COMPILE) */
2780 		if (tempFW != NULL) {
2781 			if (ficlWordIsImmediate(tempFW)) {
2782 				ficlVmExecuteWord(vm, tempFW);
2783 			} else {
2784 				ficlCell c;
2785 				c.p = tempFW;
2786 				if (tempFW->flags & FICL_WORD_INSTRUCTION)
2787 					ficlDictionaryAppendUnsigned(dictionary,
2788 					    (ficlInteger)tempFW->code);
2789 				else
2790 					ficlDictionaryAppendCell(dictionary, c);
2791 			}
2792 			return (1); /* true */
2793 		}
2794 	}
2795 
2796 	return (0); /* false */
2797 }
2798