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