xref: /titanic_52/usr/src/common/ficl/system.c (revision a1bf3f785ae05c419b339c3a2061f2b18c024f61)
1*a1bf3f78SToomas Soome /*
2*a1bf3f78SToomas Soome  * f i c l . c
3*a1bf3f78SToomas Soome  * Forth Inspired Command Language - external interface
4*a1bf3f78SToomas Soome  * Author: John Sadler (john_sadler@alum.mit.edu)
5*a1bf3f78SToomas Soome  * Created: 19 July 1997
6*a1bf3f78SToomas Soome  * $Id: system.c,v 1.2 2010/09/10 10:35:54 asau Exp $
7*a1bf3f78SToomas Soome  */
8*a1bf3f78SToomas Soome /*
9*a1bf3f78SToomas Soome  * This is an ANS Forth interpreter written in C.
10*a1bf3f78SToomas Soome  * Ficl uses Forth syntax for its commands, but turns the Forth
11*a1bf3f78SToomas Soome  * model on its head in other respects.
12*a1bf3f78SToomas Soome  * Ficl provides facilities for interoperating
13*a1bf3f78SToomas Soome  * with programs written in C: C functions can be exported to Ficl,
14*a1bf3f78SToomas Soome  * and Ficl commands can be executed via a C calling interface. The
15*a1bf3f78SToomas Soome  * interpreter is re-entrant, so it can be used in multiple instances
16*a1bf3f78SToomas Soome  * in a multitasking system. Unlike Forth, Ficl's outer interpreter
17*a1bf3f78SToomas Soome  * expects a text block as input, and returns to the caller after each
18*a1bf3f78SToomas Soome  * text block, so the data pump is somewhere in external code in the
19*a1bf3f78SToomas Soome  * style of TCL.
20*a1bf3f78SToomas Soome  *
21*a1bf3f78SToomas Soome  * Code is written in ANSI C for portability.
22*a1bf3f78SToomas Soome  */
23*a1bf3f78SToomas Soome /*
24*a1bf3f78SToomas Soome  * Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
25*a1bf3f78SToomas Soome  * All rights reserved.
26*a1bf3f78SToomas Soome  *
27*a1bf3f78SToomas Soome  * Get the latest Ficl release at http://ficl.sourceforge.net
28*a1bf3f78SToomas Soome  *
29*a1bf3f78SToomas Soome  * I am interested in hearing from anyone who uses Ficl. If you have
30*a1bf3f78SToomas Soome  * a problem, a success story, a defect, an enhancement request, or
31*a1bf3f78SToomas Soome  * if you would like to contribute to the Ficl release, please
32*a1bf3f78SToomas Soome  * contact me by email at the address above.
33*a1bf3f78SToomas Soome  *
34*a1bf3f78SToomas Soome  * L I C E N S E  and  D I S C L A I M E R
35*a1bf3f78SToomas Soome  *
36*a1bf3f78SToomas Soome  * Redistribution and use in source and binary forms, with or without
37*a1bf3f78SToomas Soome  * modification, are permitted provided that the following conditions
38*a1bf3f78SToomas Soome  * are met:
39*a1bf3f78SToomas Soome  * 1. Redistributions of source code must retain the above copyright
40*a1bf3f78SToomas Soome  *    notice, this list of conditions and the following disclaimer.
41*a1bf3f78SToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
42*a1bf3f78SToomas Soome  *    notice, this list of conditions and the following disclaimer in the
43*a1bf3f78SToomas Soome  *    documentation and/or other materials provided with the distribution.
44*a1bf3f78SToomas Soome  *
45*a1bf3f78SToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46*a1bf3f78SToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47*a1bf3f78SToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48*a1bf3f78SToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49*a1bf3f78SToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50*a1bf3f78SToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51*a1bf3f78SToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52*a1bf3f78SToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53*a1bf3f78SToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54*a1bf3f78SToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55*a1bf3f78SToomas Soome  * SUCH DAMAGE.
56*a1bf3f78SToomas Soome  */
57*a1bf3f78SToomas Soome 
58*a1bf3f78SToomas Soome #include "ficl.h"
59*a1bf3f78SToomas Soome 
60*a1bf3f78SToomas Soome /*
61*a1bf3f78SToomas Soome  * System statics
62*a1bf3f78SToomas Soome  * Each ficlSystem builds a global dictionary during its start
63*a1bf3f78SToomas Soome  * sequence. This is shared by all virtual machines of that system.
64*a1bf3f78SToomas Soome  * Therefore only one VM can update the dictionary
65*a1bf3f78SToomas Soome  * at a time. The system imports a locking function that
66*a1bf3f78SToomas Soome  * you can override in order to control update access to
67*a1bf3f78SToomas Soome  * the dictionary. The function is stubbed out by default,
68*a1bf3f78SToomas Soome  * but you can insert one: #define FICL_WANT_MULTITHREADED 1
69*a1bf3f78SToomas Soome  * and supply your own version of ficlDictionaryLock.
70*a1bf3f78SToomas Soome  */
71*a1bf3f78SToomas Soome 
72*a1bf3f78SToomas Soome ficlSystem *ficlSystemGlobal = NULL;
73*a1bf3f78SToomas Soome 
74*a1bf3f78SToomas Soome /*
75*a1bf3f78SToomas Soome  * f i c l S e t V e r s i o n E n v
76*a1bf3f78SToomas Soome  * Create a double ficlCell environment constant for the version ID
77*a1bf3f78SToomas Soome  */
78*a1bf3f78SToomas Soome static void
79*a1bf3f78SToomas Soome ficlSystemSetVersion(ficlSystem *system)
80*a1bf3f78SToomas Soome {
81*a1bf3f78SToomas Soome 	int major = FICL_VERSION_MAJOR;
82*a1bf3f78SToomas Soome 	int minor = FICL_VERSION_MINOR;
83*a1bf3f78SToomas Soome 	ficl2Integer combined;
84*a1bf3f78SToomas Soome 	ficlDictionary *environment = ficlSystemGetEnvironment(system);
85*a1bf3f78SToomas Soome 	FICL_2INTEGER_SET(major, minor, combined);
86*a1bf3f78SToomas Soome 	ficlDictionarySet2Constant(environment, "ficl-version", combined);
87*a1bf3f78SToomas Soome 	ficlDictionarySetConstant(environment, "ficl-robust",  FICL_ROBUST);
88*a1bf3f78SToomas Soome }
89*a1bf3f78SToomas Soome 
90*a1bf3f78SToomas Soome /*
91*a1bf3f78SToomas Soome  * f i c l I n i t S y s t e m
92*a1bf3f78SToomas Soome  * Binds a global dictionary to the interpreter system.
93*a1bf3f78SToomas Soome  * You specify the address and size of the allocated area.
94*a1bf3f78SToomas Soome  * After that, Ficl manages it.
95*a1bf3f78SToomas Soome  * First step is to set up the static pointers to the area.
96*a1bf3f78SToomas Soome  * Then write the "precompiled" portion of the dictionary in.
97*a1bf3f78SToomas Soome  * The dictionary needs to be at least large enough to hold the
98*a1bf3f78SToomas Soome  * precompiled part. Try 1K cells minimum. Use "words" to find
99*a1bf3f78SToomas Soome  * out how much of the dictionary is used at any time.
100*a1bf3f78SToomas Soome  */
101*a1bf3f78SToomas Soome ficlSystem *
102*a1bf3f78SToomas Soome ficlSystemCreate(ficlSystemInformation *fsi)
103*a1bf3f78SToomas Soome {
104*a1bf3f78SToomas Soome 	ficlInteger dictionarySize;
105*a1bf3f78SToomas Soome 	ficlInteger environmentSize;
106*a1bf3f78SToomas Soome 	ficlInteger stackSize;
107*a1bf3f78SToomas Soome 	ficlSystem *system;
108*a1bf3f78SToomas Soome 	ficlCallback callback;
109*a1bf3f78SToomas Soome 	ficlSystemInformation fauxInfo;
110*a1bf3f78SToomas Soome 	ficlDictionary *environment;
111*a1bf3f78SToomas Soome 
112*a1bf3f78SToomas Soome 	if (fsi == NULL) {
113*a1bf3f78SToomas Soome 		fsi = &fauxInfo;
114*a1bf3f78SToomas Soome 		ficlSystemInformationInitialize(fsi);
115*a1bf3f78SToomas Soome 	}
116*a1bf3f78SToomas Soome 
117*a1bf3f78SToomas Soome 	callback.context = fsi->context;
118*a1bf3f78SToomas Soome 	callback.textOut = fsi->textOut;
119*a1bf3f78SToomas Soome 	callback.errorOut = fsi->errorOut;
120*a1bf3f78SToomas Soome 	callback.system = NULL;
121*a1bf3f78SToomas Soome 	callback.vm = NULL;
122*a1bf3f78SToomas Soome 
123*a1bf3f78SToomas Soome 	FICL_ASSERT(&callback, sizeof (ficlInteger) >= sizeof (void *));
124*a1bf3f78SToomas Soome 	FICL_ASSERT(&callback, sizeof (ficlUnsigned) >= sizeof (void *));
125*a1bf3f78SToomas Soome #if (FICL_WANT_FLOAT)
126*a1bf3f78SToomas Soome 	FICL_ASSERT(&callback, sizeof (ficlFloat) <= sizeof (ficlInteger));
127*a1bf3f78SToomas Soome #endif
128*a1bf3f78SToomas Soome 
129*a1bf3f78SToomas Soome 	system = ficlMalloc(sizeof (ficlSystem));
130*a1bf3f78SToomas Soome 
131*a1bf3f78SToomas Soome 	FICL_ASSERT(&callback, system);
132*a1bf3f78SToomas Soome 
133*a1bf3f78SToomas Soome 	memset(system, 0, sizeof (ficlSystem));
134*a1bf3f78SToomas Soome 
135*a1bf3f78SToomas Soome 	dictionarySize = fsi->dictionarySize;
136*a1bf3f78SToomas Soome 	if (dictionarySize <= 0)
137*a1bf3f78SToomas Soome 		dictionarySize = FICL_DEFAULT_DICTIONARY_SIZE;
138*a1bf3f78SToomas Soome 
139*a1bf3f78SToomas Soome 	environmentSize = fsi->environmentSize;
140*a1bf3f78SToomas Soome 	if (environmentSize <= 0)
141*a1bf3f78SToomas Soome 		environmentSize = FICL_DEFAULT_ENVIRONMENT_SIZE;
142*a1bf3f78SToomas Soome 
143*a1bf3f78SToomas Soome 	stackSize = fsi->stackSize;
144*a1bf3f78SToomas Soome 	if (stackSize < FICL_DEFAULT_STACK_SIZE)
145*a1bf3f78SToomas Soome 		stackSize = FICL_DEFAULT_STACK_SIZE;
146*a1bf3f78SToomas Soome 
147*a1bf3f78SToomas Soome 	system->dictionary = ficlDictionaryCreateHashed(system,
148*a1bf3f78SToomas Soome 	    (unsigned)dictionarySize, FICL_HASH_SIZE);
149*a1bf3f78SToomas Soome 	system->dictionary->forthWordlist->name = "forth-wordlist";
150*a1bf3f78SToomas Soome 
151*a1bf3f78SToomas Soome 	environment = ficlDictionaryCreate(system, (unsigned)environmentSize);
152*a1bf3f78SToomas Soome 	system->environment = environment;
153*a1bf3f78SToomas Soome 	system->environment->forthWordlist->name = "environment";
154*a1bf3f78SToomas Soome 
155*a1bf3f78SToomas Soome 	system->callback.textOut = fsi->textOut;
156*a1bf3f78SToomas Soome 	system->callback.errorOut = fsi->errorOut;
157*a1bf3f78SToomas Soome 	system->callback.context = fsi->context;
158*a1bf3f78SToomas Soome 	system->callback.system = system;
159*a1bf3f78SToomas Soome 	system->callback.vm = NULL;
160*a1bf3f78SToomas Soome 	system->stackSize = stackSize;
161*a1bf3f78SToomas Soome 
162*a1bf3f78SToomas Soome #if FICL_WANT_LOCALS
163*a1bf3f78SToomas Soome 	/*
164*a1bf3f78SToomas Soome 	 * The locals dictionary is only searched while compiling,
165*a1bf3f78SToomas Soome 	 * but this is where speed is most important. On the other
166*a1bf3f78SToomas Soome 	 * hand, the dictionary gets emptied after each use of locals
167*a1bf3f78SToomas Soome 	 * The need to balance search speed with the cost of the 'empty'
168*a1bf3f78SToomas Soome 	 * operation led me to select a single-threaded list...
169*a1bf3f78SToomas Soome 	 */
170*a1bf3f78SToomas Soome 	system->locals = ficlDictionaryCreate(system,
171*a1bf3f78SToomas Soome 	    (unsigned)FICL_MAX_LOCALS * FICL_CELLS_PER_WORD);
172*a1bf3f78SToomas Soome #endif /* FICL_WANT_LOCALS */
173*a1bf3f78SToomas Soome 
174*a1bf3f78SToomas Soome 	/*
175*a1bf3f78SToomas Soome 	 * Build the precompiled dictionary and load softwords. We need
176*a1bf3f78SToomas Soome 	 * a temporary VM to do this - ficlNewVM links one to the head of
177*a1bf3f78SToomas Soome 	 * the system VM list. ficlCompilePlatform (defined in win32.c,
178*a1bf3f78SToomas Soome 	 * for example) adds platform specific words.
179*a1bf3f78SToomas Soome 	 */
180*a1bf3f78SToomas Soome 	ficlSystemCompileCore(system);
181*a1bf3f78SToomas Soome 	ficlSystemCompilePrefix(system);
182*a1bf3f78SToomas Soome 
183*a1bf3f78SToomas Soome #if FICL_WANT_FLOAT
184*a1bf3f78SToomas Soome 	ficlSystemCompileFloat(system);
185*a1bf3f78SToomas Soome #endif /* FICL_WANT_FLOAT */
186*a1bf3f78SToomas Soome 
187*a1bf3f78SToomas Soome #if FICL_WANT_PLATFORM
188*a1bf3f78SToomas Soome 	ficlSystemCompilePlatform(system);
189*a1bf3f78SToomas Soome #endif /* FICL_WANT_PLATFORM */
190*a1bf3f78SToomas Soome 
191*a1bf3f78SToomas Soome 	ficlSystemSetVersion(system);
192*a1bf3f78SToomas Soome 
193*a1bf3f78SToomas Soome 	/*
194*a1bf3f78SToomas Soome 	 * Establish the parse order. Note that prefixes precede numbers -
195*a1bf3f78SToomas Soome 	 * this allows constructs like "0b101010" which might parse as a
196*a1bf3f78SToomas Soome 	 * hex value otherwise.
197*a1bf3f78SToomas Soome 	 */
198*a1bf3f78SToomas Soome 	ficlSystemAddPrimitiveParseStep(system, "?word", ficlVmParseWord);
199*a1bf3f78SToomas Soome 	ficlSystemAddPrimitiveParseStep(system, "?prefix", ficlVmParsePrefix);
200*a1bf3f78SToomas Soome 	ficlSystemAddPrimitiveParseStep(system, "?number", ficlVmParseNumber);
201*a1bf3f78SToomas Soome #if FICL_WANT_FLOAT
202*a1bf3f78SToomas Soome 	ficlSystemAddPrimitiveParseStep(system, "?float",
203*a1bf3f78SToomas Soome 	    ficlVmParseFloatNumber);
204*a1bf3f78SToomas Soome #endif
205*a1bf3f78SToomas Soome 
206*a1bf3f78SToomas Soome 	/*
207*a1bf3f78SToomas Soome 	 * Now create a temporary VM to compile the softwords. Since all VMs
208*a1bf3f78SToomas Soome 	 * are linked into the vmList of ficlSystem, we don't have to pass
209*a1bf3f78SToomas Soome 	 * the VM to ficlCompileSoftCore -- it just hijacks whatever it finds
210*a1bf3f78SToomas Soome 	 * in the VM list. Ficl 2.05: vmCreate no longer depends on the
211*a1bf3f78SToomas Soome 	 * presence of INTERPRET in the dictionary, so a VM can be created
212*a1bf3f78SToomas Soome 	 * before the dictionary is built. It just can't do much...
213*a1bf3f78SToomas Soome 	 */
214*a1bf3f78SToomas Soome 	ficlSystemCreateVm(system);
215*a1bf3f78SToomas Soome #define	ADD_COMPILE_FLAG(name)	\
216*a1bf3f78SToomas Soome 	ficlDictionarySetConstant(environment, #name, name)
217*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_LZ4_SOFTCORE);
218*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_FILE);
219*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_FLOAT);
220*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_DEBUGGER);
221*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_EXTENDED_PREFIX);
222*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_USER);
223*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_LOCALS);
224*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_OOP);
225*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_SOFTWORDS);
226*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_MULTITHREADED);
227*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_OPTIMIZE);
228*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_WANT_VCALL);
229*a1bf3f78SToomas Soome 
230*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_PLATFORM_ALIGNMENT);
231*a1bf3f78SToomas Soome 
232*a1bf3f78SToomas Soome 	ADD_COMPILE_FLAG(FICL_ROBUST);
233*a1bf3f78SToomas Soome 
234*a1bf3f78SToomas Soome #define	ADD_COMPILE_STRING(name)	\
235*a1bf3f78SToomas Soome 	ficlDictionarySetConstantString(environment, #name, name)
236*a1bf3f78SToomas Soome 	ADD_COMPILE_STRING(FICL_PLATFORM_ARCHITECTURE);
237*a1bf3f78SToomas Soome 	ADD_COMPILE_STRING(FICL_PLATFORM_OS);
238*a1bf3f78SToomas Soome 
239*a1bf3f78SToomas Soome 	ficlSystemCompileSoftCore(system);
240*a1bf3f78SToomas Soome 	ficlSystemDestroyVm(system->vmList);
241*a1bf3f78SToomas Soome 
242*a1bf3f78SToomas Soome 	if (ficlSystemGlobal == NULL)
243*a1bf3f78SToomas Soome 		ficlSystemGlobal = system;
244*a1bf3f78SToomas Soome 
245*a1bf3f78SToomas Soome 	return (system);
246*a1bf3f78SToomas Soome }
247*a1bf3f78SToomas Soome 
248*a1bf3f78SToomas Soome /*
249*a1bf3f78SToomas Soome  * f i c l T e r m S y s t e m
250*a1bf3f78SToomas Soome  * Tear the system down by deleting the dictionaries and all VMs.
251*a1bf3f78SToomas Soome  * This saves you from having to keep track of all that stuff.
252*a1bf3f78SToomas Soome  */
253*a1bf3f78SToomas Soome void
254*a1bf3f78SToomas Soome ficlSystemDestroy(ficlSystem *system)
255*a1bf3f78SToomas Soome {
256*a1bf3f78SToomas Soome 	if (system->dictionary)
257*a1bf3f78SToomas Soome 		ficlDictionaryDestroy(system->dictionary);
258*a1bf3f78SToomas Soome 	system->dictionary = NULL;
259*a1bf3f78SToomas Soome 
260*a1bf3f78SToomas Soome 	if (system->environment)
261*a1bf3f78SToomas Soome 		ficlDictionaryDestroy(system->environment);
262*a1bf3f78SToomas Soome 	system->environment = NULL;
263*a1bf3f78SToomas Soome 
264*a1bf3f78SToomas Soome #if FICL_WANT_LOCALS
265*a1bf3f78SToomas Soome 	if (system->locals)
266*a1bf3f78SToomas Soome 		ficlDictionaryDestroy(system->locals);
267*a1bf3f78SToomas Soome 	system->locals = NULL;
268*a1bf3f78SToomas Soome #endif
269*a1bf3f78SToomas Soome 
270*a1bf3f78SToomas Soome 	while (system->vmList != NULL) {
271*a1bf3f78SToomas Soome 		ficlVm *vm = system->vmList;
272*a1bf3f78SToomas Soome 		system->vmList = system->vmList->link;
273*a1bf3f78SToomas Soome 		ficlVmDestroy(vm);
274*a1bf3f78SToomas Soome 	}
275*a1bf3f78SToomas Soome 
276*a1bf3f78SToomas Soome 	if (ficlSystemGlobal == system)
277*a1bf3f78SToomas Soome 		ficlSystemGlobal = NULL;
278*a1bf3f78SToomas Soome 
279*a1bf3f78SToomas Soome 	ficlFree(system);
280*a1bf3f78SToomas Soome 	system = NULL;
281*a1bf3f78SToomas Soome }
282*a1bf3f78SToomas Soome 
283*a1bf3f78SToomas Soome /*
284*a1bf3f78SToomas Soome  * f i c l A d d P a r s e S t e p
285*a1bf3f78SToomas Soome  * Appends a parse step function to the end of the parse list (see
286*a1bf3f78SToomas Soome  * ficlParseStep notes in ficl.h for details). Returns 0 if successful,
287*a1bf3f78SToomas Soome  * nonzero if there's no more room in the list.
288*a1bf3f78SToomas Soome  */
289*a1bf3f78SToomas Soome int
290*a1bf3f78SToomas Soome ficlSystemAddParseStep(ficlSystem *system, ficlWord *word)
291*a1bf3f78SToomas Soome {
292*a1bf3f78SToomas Soome 	int i;
293*a1bf3f78SToomas Soome 	for (i = 0; i < FICL_MAX_PARSE_STEPS; i++) {
294*a1bf3f78SToomas Soome 		if (system->parseList[i] == NULL) {
295*a1bf3f78SToomas Soome 			system->parseList[i] = word;
296*a1bf3f78SToomas Soome 			return (0);
297*a1bf3f78SToomas Soome 		}
298*a1bf3f78SToomas Soome 	}
299*a1bf3f78SToomas Soome 
300*a1bf3f78SToomas Soome 	return (1);
301*a1bf3f78SToomas Soome }
302*a1bf3f78SToomas Soome 
303*a1bf3f78SToomas Soome /*
304*a1bf3f78SToomas Soome  * Compile a word into the dictionary that invokes the specified ficlParseStep
305*a1bf3f78SToomas Soome  * function. It is up to the user (as usual in Forth) to make sure the stack
306*a1bf3f78SToomas Soome  * preconditions are valid (there needs to be a counted string on top of the
307*a1bf3f78SToomas Soome  * stack) before using the resulting word.
308*a1bf3f78SToomas Soome  */
309*a1bf3f78SToomas Soome void
310*a1bf3f78SToomas Soome ficlSystemAddPrimitiveParseStep(ficlSystem *system, char *name,
311*a1bf3f78SToomas Soome     ficlParseStep pStep)
312*a1bf3f78SToomas Soome {
313*a1bf3f78SToomas Soome 	ficlDictionary *dictionary = system->dictionary;
314*a1bf3f78SToomas Soome 	ficlWord *word;
315*a1bf3f78SToomas Soome 	ficlCell c;
316*a1bf3f78SToomas Soome 
317*a1bf3f78SToomas Soome 	word = ficlDictionaryAppendPrimitive(dictionary, name,
318*a1bf3f78SToomas Soome 	    ficlPrimitiveParseStepParen, FICL_WORD_DEFAULT);
319*a1bf3f78SToomas Soome 
320*a1bf3f78SToomas Soome 	c.fn = (void (*)(void))pStep;
321*a1bf3f78SToomas Soome 	ficlDictionaryAppendCell(dictionary, c);
322*a1bf3f78SToomas Soome 	ficlSystemAddParseStep(system, word);
323*a1bf3f78SToomas Soome }
324*a1bf3f78SToomas Soome 
325*a1bf3f78SToomas Soome /*
326*a1bf3f78SToomas Soome  * f i c l N e w V M
327*a1bf3f78SToomas Soome  * Create a new virtual machine and link it into the system list
328*a1bf3f78SToomas Soome  * of VMs for later cleanup by ficlTermSystem.
329*a1bf3f78SToomas Soome  */
330*a1bf3f78SToomas Soome ficlVm *
331*a1bf3f78SToomas Soome ficlSystemCreateVm(ficlSystem *system)
332*a1bf3f78SToomas Soome {
333*a1bf3f78SToomas Soome 	ficlVm *vm = ficlVmCreate(NULL, system->stackSize, system->stackSize);
334*a1bf3f78SToomas Soome 	vm->link = system->vmList;
335*a1bf3f78SToomas Soome 
336*a1bf3f78SToomas Soome 	memcpy(&(vm->callback), &(system->callback), sizeof (system->callback));
337*a1bf3f78SToomas Soome 	vm->callback.vm = vm;
338*a1bf3f78SToomas Soome 	vm->callback.system = system;
339*a1bf3f78SToomas Soome 
340*a1bf3f78SToomas Soome 	system->vmList = vm;
341*a1bf3f78SToomas Soome 	return (vm);
342*a1bf3f78SToomas Soome }
343*a1bf3f78SToomas Soome 
344*a1bf3f78SToomas Soome /*
345*a1bf3f78SToomas Soome  * f i c l F r e e V M
346*a1bf3f78SToomas Soome  * Removes the VM in question from the system VM list and deletes the
347*a1bf3f78SToomas Soome  * memory allocated to it. This is an optional call, since ficlTermSystem
348*a1bf3f78SToomas Soome  * will do this cleanup for you. This function is handy if you're going to
349*a1bf3f78SToomas Soome  * do a lot of dynamic creation of VMs.
350*a1bf3f78SToomas Soome  */
351*a1bf3f78SToomas Soome void
352*a1bf3f78SToomas Soome ficlSystemDestroyVm(ficlVm *vm)
353*a1bf3f78SToomas Soome {
354*a1bf3f78SToomas Soome 	ficlSystem *system = vm->callback.system;
355*a1bf3f78SToomas Soome 	ficlVm *pList = system->vmList;
356*a1bf3f78SToomas Soome 
357*a1bf3f78SToomas Soome 	FICL_VM_ASSERT(vm, vm != NULL);
358*a1bf3f78SToomas Soome 
359*a1bf3f78SToomas Soome 	if (system->vmList == vm) {
360*a1bf3f78SToomas Soome 		system->vmList = system->vmList->link;
361*a1bf3f78SToomas Soome 	} else
362*a1bf3f78SToomas Soome 		for (; pList != NULL; pList = pList->link) {
363*a1bf3f78SToomas Soome 			if (pList->link == vm) {
364*a1bf3f78SToomas Soome 				pList->link = vm->link;
365*a1bf3f78SToomas Soome 				break;
366*a1bf3f78SToomas Soome 			}
367*a1bf3f78SToomas Soome 		}
368*a1bf3f78SToomas Soome 
369*a1bf3f78SToomas Soome 	if (pList)
370*a1bf3f78SToomas Soome 		ficlVmDestroy(vm);
371*a1bf3f78SToomas Soome }
372*a1bf3f78SToomas Soome 
373*a1bf3f78SToomas Soome /*
374*a1bf3f78SToomas Soome  * f i c l L o o k u p
375*a1bf3f78SToomas Soome  * Look in the system dictionary for a match to the given name. If
376*a1bf3f78SToomas Soome  * found, return the address of the corresponding ficlWord. Otherwise
377*a1bf3f78SToomas Soome  * return NULL.
378*a1bf3f78SToomas Soome  */
379*a1bf3f78SToomas Soome ficlWord *
380*a1bf3f78SToomas Soome ficlSystemLookup(ficlSystem *system, char *name)
381*a1bf3f78SToomas Soome {
382*a1bf3f78SToomas Soome 	ficlString s;
383*a1bf3f78SToomas Soome 	FICL_STRING_SET_FROM_CSTRING(s, name);
384*a1bf3f78SToomas Soome 	return (ficlDictionaryLookup(system->dictionary, s));
385*a1bf3f78SToomas Soome }
386*a1bf3f78SToomas Soome 
387*a1bf3f78SToomas Soome /*
388*a1bf3f78SToomas Soome  * f i c l G e t D i c t
389*a1bf3f78SToomas Soome  * Returns the address of the system dictionary
390*a1bf3f78SToomas Soome  */
391*a1bf3f78SToomas Soome ficlDictionary *
392*a1bf3f78SToomas Soome ficlSystemGetDictionary(ficlSystem *system)
393*a1bf3f78SToomas Soome {
394*a1bf3f78SToomas Soome 	return (system->dictionary);
395*a1bf3f78SToomas Soome }
396*a1bf3f78SToomas Soome 
397*a1bf3f78SToomas Soome /*
398*a1bf3f78SToomas Soome  * f i c l G e t E n v
399*a1bf3f78SToomas Soome  * Returns the address of the system environment space
400*a1bf3f78SToomas Soome  */
401*a1bf3f78SToomas Soome ficlDictionary *
402*a1bf3f78SToomas Soome ficlSystemGetEnvironment(ficlSystem *system)
403*a1bf3f78SToomas Soome {
404*a1bf3f78SToomas Soome 	return (system->environment);
405*a1bf3f78SToomas Soome }
406*a1bf3f78SToomas Soome 
407*a1bf3f78SToomas Soome /*
408*a1bf3f78SToomas Soome  * f i c l G e t L o c
409*a1bf3f78SToomas Soome  * Returns the address of the system locals dictionary. This dictionary is
410*a1bf3f78SToomas Soome  * only used during compilation, and is shared by all VMs.
411*a1bf3f78SToomas Soome  */
412*a1bf3f78SToomas Soome #if FICL_WANT_LOCALS
413*a1bf3f78SToomas Soome ficlDictionary *
414*a1bf3f78SToomas Soome ficlSystemGetLocals(ficlSystem *system)
415*a1bf3f78SToomas Soome {
416*a1bf3f78SToomas Soome 	return (system->locals);
417*a1bf3f78SToomas Soome }
418*a1bf3f78SToomas Soome #endif
419*a1bf3f78SToomas Soome 
420*a1bf3f78SToomas Soome /*
421*a1bf3f78SToomas Soome  * f i c l L o o k u p L o c
422*a1bf3f78SToomas Soome  * Same as dictLookup, but looks in system locals dictionary first...
423*a1bf3f78SToomas Soome  * Assumes locals dictionary has only one wordlist...
424*a1bf3f78SToomas Soome  */
425*a1bf3f78SToomas Soome #if FICL_WANT_LOCALS
426*a1bf3f78SToomas Soome ficlWord *
427*a1bf3f78SToomas Soome ficlSystemLookupLocal(ficlSystem *system, ficlString name)
428*a1bf3f78SToomas Soome {
429*a1bf3f78SToomas Soome 	ficlWord *word = NULL;
430*a1bf3f78SToomas Soome 	ficlDictionary *dictionary = system->dictionary;
431*a1bf3f78SToomas Soome 	ficlHash *hash = ficlSystemGetLocals(system)->forthWordlist;
432*a1bf3f78SToomas Soome 	int i;
433*a1bf3f78SToomas Soome 	ficlUnsigned16 hashCode = ficlHashCode(name);
434*a1bf3f78SToomas Soome 
435*a1bf3f78SToomas Soome 	FICL_SYSTEM_ASSERT(system, hash);
436*a1bf3f78SToomas Soome 	FICL_SYSTEM_ASSERT(system, dictionary);
437*a1bf3f78SToomas Soome 
438*a1bf3f78SToomas Soome 	ficlDictionaryLock(dictionary, FICL_TRUE);
439*a1bf3f78SToomas Soome 	/*
440*a1bf3f78SToomas Soome 	 * check the locals dictionary first...
441*a1bf3f78SToomas Soome 	 */
442*a1bf3f78SToomas Soome 	word = ficlHashLookup(hash, name, hashCode);
443*a1bf3f78SToomas Soome 
444*a1bf3f78SToomas Soome 	/*
445*a1bf3f78SToomas Soome 	 * If no joy, (!word) ------------------------------v
446*a1bf3f78SToomas Soome 	 * iterate over the search list in the main dictionary
447*a1bf3f78SToomas Soome 	 */
448*a1bf3f78SToomas Soome 	for (i = (int)dictionary->wordlistCount - 1; (i >= 0) && (!word); --i) {
449*a1bf3f78SToomas Soome 		hash = dictionary->wordlists[i];
450*a1bf3f78SToomas Soome 		word = ficlHashLookup(hash, name, hashCode);
451*a1bf3f78SToomas Soome 	}
452*a1bf3f78SToomas Soome 
453*a1bf3f78SToomas Soome 	ficlDictionaryLock(dictionary, FICL_FALSE);
454*a1bf3f78SToomas Soome 	return (word);
455*a1bf3f78SToomas Soome }
456*a1bf3f78SToomas Soome #endif
457