Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / boot / ficl / ficl.h
1 /*******************************************************************
2 ** f i c l . h
3 ** Forth Inspired Command Language
4 ** Author: John Sadler (john_sadler@alum.mit.edu)
5 ** Created: 19 July 1997
6 ** 
7 *******************************************************************/
8 /*
9 ** N O T I C E -- DISCLAIMER OF WARRANTY
10 ** 
11 ** Ficl is freeware. Use it in any way that you like, with
12 ** the understanding that the code is supported on a "best effort"
13 ** basis only.
14 ** 
15 ** Any third party may reproduce, distribute, or modify the ficl
16 ** software code or any derivative  works thereof without any 
17 ** compensation or license, provided that the author information
18 ** and this disclaimer text are retained in the source code files.
19 ** The ficl software code is provided on an "as is"  basis without
20 ** warranty of any kind, including, without limitation, the implied
21 ** warranties of merchantability and fitness for a particular purpose
22 ** and their equivalents under the laws of any jurisdiction.  
23 ** 
24 ** I am interested in hearing from anyone who uses ficl. If you have
25 ** a problem, a success story, a defect, an enhancement request, or
26 ** if you would like to contribute to the ficl release (yay!), please
27 ** send me email at the address above. 
28 */
29
30 /* $FreeBSD: src/sys/boot/ficl/ficl.h,v 1.11.2.1 2000/07/06 23:44:58 obrien Exp $ */
31
32 #if !defined (__FICL_H__)
33 #define __FICL_H__
34 /*
35 ** Ficl (Forth-inspired command language) is an ANS Forth
36 ** interpreter written in C. Unlike traditional Forths, this
37 ** interpreter is designed to be embedded into other systems
38 ** as a command/macro/development prototype language. 
39 **
40 ** Where Forths usually view themselves as the center of the system
41 ** and expect the rest of the system to be coded in Forth, Ficl
42 ** acts as a component of the system. It is easy to export 
43 ** code written in C or ASM to Ficl in the style of TCL, or to invoke
44 ** Ficl code from a compiled module. This allows you to do incremental
45 ** development in a way that combines the best features of threaded 
46 ** languages (rapid development, quick code/test/debug cycle,
47 ** reasonably fast) with the best features of C (everyone knows it,
48 ** easier to support large blocks of code, efficient, type checking).
49 **
50 ** Ficl provides facilities for interoperating
51 ** with programs written in C: C functions can be exported to Ficl,
52 ** and Ficl commands can be executed via a C calling interface. The
53 ** interpreter is re-entrant, so it can be used in multiple instances
54 ** in a multitasking system. Unlike Forth, Ficl's outer interpreter
55 ** expects a text block as input, and returns to the caller after each
56 ** text block, so the "data pump" is somewhere in external code. This
57 ** is more like TCL than Forth, which usually expcets to be at the center
58 ** of the system, requesting input at its convenience. Each Ficl virtual 
59 ** machine can be bound to a different I/O channel, and is independent
60 ** of all others in in the same address space except that all virtual
61 ** machines share a common dictionary (a sort or open symbol table that
62 ** defines all of the elements of the language).
63 **
64 ** Code is written in ANSI C for portability. 
65 **
66 ** Summary of Ficl features and constraints:
67 ** - Standard: Implements the ANSI Forth CORE word set and part 
68 **   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
69 **   TOOLS EXT, LOCAL and LOCAL ext and various extras.
70 ** - Extensible: you can export code written in Forth, C, 
71 **   or asm in a straightforward way. Ficl provides open
72 **   facilities for extending the language in an application
73 **   specific way. You can even add new control structures!
74 ** - Ficl and C can interact in two ways: Ficl can encapsulate
75 **   C code, or C code can invoke Ficl code.
76 ** - Thread-safe, re-entrant: The shared system dictionary 
77 **   uses a locking mechanism that you can either supply
78 **   or stub out to provide exclusive access. Each Ficl
79 **   virtual machine has an otherwise complete state, and
80 **   each can be bound to a separate I/O channel (or none at all).
81 ** - Simple encapsulation into existing systems: a basic implementation
82 **   requires three function calls (see the example program in testmain.c).
83 ** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
84 **   environments. It does require somewhat more memory than a pure
85 **   ROM implementation because it builds its system dictionary in 
86 **   RAM at startup time.
87 ** - Written an ANSI C to be as simple as I can make it to understand,
88 **   support, debug, and port. Compiles without complaint at /Az /W4 
89 **   (require ANSI C, max warnings) under Microsoft VC++ 5.
90 ** - Does full 32 bit math (but you need to implement
91 **   two mixed precision math primitives (see sysdep.c))
92 ** - Indirect threaded interpreter is not the fastest kind of
93 **   Forth there is (see pForth 68K for a really fast subroutine
94 **   threaded interpreter), but it's the cleanest match to a
95 **   pure C implementation.
96 **
97 ** P O R T I N G   F i c l
98 **
99 ** To install Ficl on your target system, you need an ANSI C compiler
100 ** and its runtime library. Inspect the system dependent macros and
101 ** functions in sysdep.h and sysdep.c and edit them to suit your
102 ** system. For example, INT16 is a short on some compilers and an
103 ** int on others. Check the default CELL alignment controlled by
104 ** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
105 ** ficlLockDictionary, and ficlTextOut to work with your operating system.
106 ** Finally, use testmain.c as a guide to installing the Ficl system and 
107 ** one or more virtual machines into your code. You do not need to include
108 ** testmain.c in your build.
109 **
110 ** T o   D o   L i s t
111 **
112 ** 1. Unimplemented system dependent CORE word: key
113 ** 2. Kludged CORE word: ACCEPT 
114 ** 3. Dictionary locking is full of holes - only one vm at a time
115 **    can alter the dict. 
116 ** 4. Ficl uses the pad in CORE words - this violates the standard,
117 **    but it's cleaner for a multithreaded system. I'll have to make a
118 **    second pad for reference by the word PAD to fix this.
119 **
120 ** F o r   M o r e   I n f o r m a t i o n
121 **
122 ** Web home of ficl
123 **   http://www.taygeta.com/forth/compilers
124 ** Check this website for Forth literature (including the ANSI standard)
125 **   http://www.taygeta.com/forthlit.html
126 ** and here for software and more links
127 **   http://www.taygeta.com/forth.html
128 **
129 ** Obvious Performance enhancement opportunities
130 ** Compile speed
131 ** - work on interpret speed
132 ** - turn off locals (FICL_WANT_LOCALS)
133 ** Interpret speed 
134 ** - Change inner interpreter (and everything else)
135 **   so that a definition is a list of pointers to functions
136 **   and inline data rather than pointers to words. This gets
137 **   rid of vm->runningWord and a level of indirection in the
138 **   inner loop. I'll look at it for ficl 3.0
139 ** - Make the main hash table a bigger prime (HASHSIZE)
140 ** - FORGET about twiddling the hash function - my experience is
141 **   that that is a waste of time.
142 ** - eliminate the need to pass the pVM parameter on the stack
143 **   by dedicating a register to it. Most words need access to the
144 **   vm, but the parameter passing overhead can be reduced. One way
145 **   requires that the host OS have a task switch callout. Create
146 **   a global variable for the running VM and refer to it in words
147 **   that need VM access. Alternative: use thread local storage. 
148 **   For single threaded implementations, you can just use a global.
149 **   The first two solutions create portability problems, so I
150 **   haven't considered doing them. Another possibility is to
151 **   declare the pVm parameter to be "register", and hope the compiler
152 **   pays attention.
153 **
154 */
155
156 /*
157 ** Revision History:
158 ** 
159 ** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and
160 ** counted strings in ficlExec. 
161 ** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
162 ** "end" field, and all words respect this. ficlExec is passed a "size"
163 ** of TIB, as well as vmPushTib. This size is used to calculate the "end"
164 ** of the string, ie, base+size. If the size is not known, pass -1.
165 **
166 ** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
167 ** words has been modified to conform to EXCEPTION EXT word set. 
168 **
169 ** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
170 **  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 
171 **  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
172 **  EMPTY to clear stack.
173 **
174 ** 29 jun 1998 (sadler) added variable sized hash table support
175 **  and ANS Forth optional SEARCH & SEARCH EXT word set.
176 ** 26 May 1998 (sadler) 
177 **  FICL_PROMPT macro
178 ** 14 April 1998 (sadler) V1.04
179 **  Ficlwin: Windows version, Skip Carter's Linux port
180 ** 5 March 1998 (sadler) V1.03
181 **  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
182 **
183 ** 24 February 1998 (sadler) V1.02
184 ** -Fixed bugs in <# # #>
185 ** -Changed FICL_WORD so that storage for the name characters
186 **  can be allocated from the dictionary as needed rather than 
187 **  reserving 32 bytes in each word whether needed or not - 
188 **  this saved 50% of the dictionary storage requirement.
189 ** -Added words in testmain for Win32 functions system,chdir,cwd,
190 **  also added a word that loads and evaluates a file.
191 **
192 ** December 1997 (sadler)
193 ** -Added VM_RESTART exception handling in ficlExec -- this lets words
194 **  that require additional text to succeed (like :, create, variable...)
195 **  recover gracefully from an empty input buffer rather than emitting
196 **  an error message. Definitions can span multiple input blocks with
197 **  no restrictions.
198 ** -Changed #include order so that <assert.h> is included in sysdep.h,
199 **  and sysdep is included in all other files. This lets you define
200 **  NDEBUG in sysdep.h to disable assertions if you want to.
201 ** -Make PC specific system dependent code conditional on _M_IX86
202 **  defined so that ports can coexist in sysdep.h/sysdep.c
203 */
204
205 #ifdef __cplusplus
206 extern "C" {
207 #endif
208
209 #include "sysdep.h"
210 #include <limits.h> /* UCHAR_MAX */
211
212 /*
213 ** Forward declarations... read on.
214 */
215 struct ficl_word;
216 struct vm;
217 struct ficl_dict;
218
219 /* 
220 ** the Good Stuff starts here...
221 */
222 #define FICL_VER    "2.03"
223 #if !defined (FICL_PROMPT)
224 #define FICL_PROMPT "ok> "
225 #endif
226
227 /*
228 ** ANS Forth requires false to be zero, and true to be the ones
229 ** complement of false... that unifies logical and bitwise operations
230 ** nicely.
231 */
232 #define FICL_TRUE  (~(0L))
233 #define FICL_FALSE (0)
234 #define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
235
236
237 /*
238 ** A CELL is the main storage type. It must be large enough
239 ** to contain a pointer or a scalar. In order to accommodate 
240 ** 32 bit and 64 bit processors, use abstract types for i and u.
241 */
242 typedef union _cell
243 {
244         FICL_INT i;
245     FICL_UNS u;
246         void *p;
247 } CELL;
248
249 /*
250 ** LVALUEtoCELL does a little pointer trickery to cast any 32 bit
251 ** lvalue (informal definition: an expression whose result has an
252 ** address) to CELL. Remember that constants and casts are NOT
253 ** themselves lvalues!
254 */
255 #define LVALUEtoCELL(v) (*(CELL *)&v)
256
257 /*
258 ** PTRtoCELL is a cast through void * intended to satisfy the
259 ** most outrageously pedantic compiler... (I won't mention 
260 ** its name)
261 */
262 #define PTRtoCELL (CELL *)(void *)
263 #define PTRtoSTRING (FICL_STRING *)(void *)
264
265 /*
266 ** Strings in FICL are stored in Pascal style - with a count
267 ** preceding the text. We'll also NULL-terminate them so that 
268 ** they work with the usual C lib string functions. (Belt &
269 ** suspenders? You decide.)
270 ** STRINGINFO hides the implementation with a couple of
271 ** macros for use in internal routines.
272 */
273
274 typedef unsigned char FICL_COUNT;
275 #define FICL_STRING_MAX UCHAR_MAX
276 typedef struct _ficl_string
277 {
278     FICL_COUNT count;
279     char text[1];
280 } FICL_STRING;
281
282 typedef struct 
283 {
284     FICL_UNS count;
285     char *cp;
286 } STRINGINFO;
287
288 #define SI_COUNT(si) (si.count)
289 #define SI_PTR(si)   (si.cp)
290 #define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len))
291 #define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
292 /* 
293 ** Init a STRINGINFO from a pointer to NULL-terminated string
294 */
295 #define SI_PSZ(si, psz) \
296             {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
297 /* 
298 ** Init a STRINGINFO from a pointer to FICL_STRING
299 */
300 #define SI_PFS(si, pfs) \
301             {si.cp = pfs->text; si.count = pfs->count;}
302
303 /*
304 ** Ficl uses a this little structure to hold the address of 
305 ** the block of text it's working on and an index to the next
306 ** unconsumed character in the string. Traditionally, this is
307 ** done by a Text Input Buffer, so I've called this struct TIB.
308 **
309 ** Since this structure also holds the size of the input buffer,
310 ** and since evaluate requires that, let's put the size here.
311 ** The size is stored as an end-pointer because that is what the
312 ** null-terminated string aware functions find most easy to deal
313 ** with.
314 ** Notice, though, that nobody really uses this except evaluate,
315 ** so it might just be moved to FICL_VM instead. (sobral)
316 */
317 typedef struct
318 {
319     FICL_INT index;
320     char *end;
321     char *cp;
322 } TIB;
323
324
325 /*
326 ** Stacks get heavy use in Ficl and Forth...
327 ** Each virtual machine implements two of them:
328 ** one holds parameters (data), and the other holds return
329 ** addresses and control flow information for the virtual
330 ** machine. (Note: C's automatic stack is implicitly used,
331 ** but not modeled because it doesn't need to be...)
332 ** Here's an abstract type for a stack
333 */
334 typedef struct _ficlStack
335 {
336     FICL_UNS nCells;    /* size of the stack */
337     CELL *pFrame;       /* link reg for stack frame */
338     CELL *sp;           /* stack pointer */
339     CELL base[1];       /* Bottom of the stack */
340 } FICL_STACK;
341
342 /*
343 ** Stack methods... many map closely to required Forth words.
344 */
345 FICL_STACK *stackCreate(unsigned nCells);
346 void        stackDelete(FICL_STACK *pStack);
347 int         stackDepth (FICL_STACK *pStack);
348 void        stackDrop  (FICL_STACK *pStack, int n);
349 CELL        stackFetch (FICL_STACK *pStack, int n);
350 CELL        stackGetTop(FICL_STACK *pStack);
351 void        stackLink  (FICL_STACK *pStack, int nCells);
352 void        stackPick  (FICL_STACK *pStack, int n);
353 CELL        stackPop   (FICL_STACK *pStack);
354 void       *stackPopPtr   (FICL_STACK *pStack);
355 FICL_UNS    stackPopUNS(FICL_STACK *pStack);
356 FICL_INT    stackPopINT(FICL_STACK *pStack);
357 void        stackPush  (FICL_STACK *pStack, CELL c);
358 void        stackPushPtr  (FICL_STACK *pStack, void *ptr);
359 void        stackPushUNS(FICL_STACK *pStack, FICL_UNS u);
360 void        stackPushINT(FICL_STACK *pStack, FICL_INT i);
361 void        stackReset (FICL_STACK *pStack);
362 void        stackRoll  (FICL_STACK *pStack, int n);
363 void        stackSetTop(FICL_STACK *pStack, CELL c);
364 void        stackStore (FICL_STACK *pStack, int n, CELL c);
365 void        stackUnlink(FICL_STACK *pStack);
366
367 /* 
368 ** The virtual machine (VM) contains the state for one interpreter.
369 ** Defined operations include:
370 ** Create & initialize
371 ** Delete
372 ** Execute a block of text
373 ** Parse a word out of the input stream
374 ** Call return, and branch 
375 ** Text output
376 ** Throw an exception
377 */
378
379 typedef struct ficl_word ** IPTYPE; /* the VM's instruction pointer */
380
381 /*
382 ** Each VM has a placeholder for an output function -
383 ** this makes it possible to have each VM do I/O
384 ** through a different device. If you specify no
385 ** OUTFUNC, it defaults to ficlTextOut.
386 */
387 typedef void (*OUTFUNC)(struct vm *pVM, char *text, int fNewline);
388
389 /*
390 ** Each VM operates in one of two non-error states: interpreting
391 ** or compiling. When interpreting, words are simply executed.
392 ** When compiling, most words in the input stream have their
393 ** addresses inserted into the word under construction. Some words
394 ** (known as IMMEDIATE) are executed in the compile state, too.
395 */
396 /* values of STATE */
397 #define INTERPRET 0
398 #define COMPILE   1
399
400 /*
401 ** The pad is a small scratch area for text manipulation. ANS Forth
402 ** requires it to hold at least 84 characters.
403 */
404 #if !defined nPAD
405 #define nPAD 256
406 #endif
407
408 /* 
409 ** ANS Forth requires that a word's name contain {1..31} characters.
410 */
411 #if !defined nFICLNAME
412 #define nFICLNAME               31
413 #endif
414
415 /*
416 ** OK - now we can really define the VM...
417 */
418 typedef struct vm
419 {
420     struct vm      *link;       /* Ficl keeps a VM list for simple teardown */
421     jmp_buf        *pState;     /* crude exception mechanism...     */
422     OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
423     void *          pExtend;    /* vm extension pointer             */
424     short           fRestart;   /* Set TRUE to restart runningWord  */
425     IPTYPE          ip;         /* instruction pointer              */
426     struct ficl_word 
427                    *runningWord;/* address of currently running word (often just *(ip-1) ) */
428     FICL_UNS        state;      /* compiling or interpreting        */
429     FICL_UNS        base;       /* number conversion base           */
430     FICL_STACK     *pStack;     /* param stack                      */
431     FICL_STACK     *rStack;     /* return stack                     */
432     CELL            sourceID;   /* -1 if string, 0 if normal input  */
433     TIB             tib;        /* address of incoming text string  */
434 #if FICL_WANT_USER
435     CELL            user[FICL_USER_CELLS];
436 #endif
437     char            pad[nPAD];  /* the scratch area (see above)     */
438 } FICL_VM;
439
440 /*
441 ** A FICL_CODE points to a function that gets called to help execute
442 ** a word in the dictionary. It always gets passed a pointer to the
443 ** running virtual machine, and from there it can get the address
444 ** of the parameter area of the word it's supposed to operate on.
445 ** For precompiled words, the code is all there is. For user defined
446 ** words, the code assumes that the word's parameter area is a list
447 ** of pointers to the code fields of other words to execute, and
448 ** may also contain inline data. The first parameter is always
449 ** a pointer to a code field.
450 */
451 typedef void (*FICL_CODE)(FICL_VM *pVm);
452
453 #if 0
454 #define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord)
455 #else
456 #define VM_ASSERT(pVM) 
457 #endif
458
459 /* 
460 ** Ficl models memory as a contiguous space divided into
461 ** words in a linked list called the dictionary.
462 ** A FICL_WORD starts each entry in the list.
463 ** Version 1.02: space for the name characters is allotted from
464 ** the dictionary ahead of the word struct - this saves about half 
465 ** the storage on average with very little runtime cost.
466 */
467 typedef struct ficl_word
468 {
469     struct ficl_word *link;     /* Previous word in the dictionary      */
470     UNS16 hash;
471     UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
472     FICL_COUNT nName;           /* Number of chars in word name         */
473     char *name;                 /* First nFICLNAME chars of word name   */
474     FICL_CODE code;             /* Native code to execute the word      */
475     CELL param[1];              /* First data cell of the word          */
476 } FICL_WORD;
477
478 /*
479 ** Worst-case size of a word header: nFICLNAME chars in name
480 */
481 #define CELLS_PER_WORD  \
482     ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
483                           / (sizeof (CELL)) )
484
485 int wordIsImmediate(FICL_WORD *pFW);
486 int wordIsCompileOnly(FICL_WORD *pFW);
487
488 /* flag values for word header */
489 #define FW_IMMEDIATE    1   /* execute me even if compiling */
490 #define FW_COMPILE      2   /* error if executed when not compiling */
491 #define FW_SMUDGE       4   /* definition in progress - hide me */
492 #define FW_CLASS        8   /* Word defines a class */
493
494 #define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
495 #define FW_DEFAULT      0
496
497
498 /*
499 ** Exit codes for vmThrow
500 */
501 #define VM_INNEREXIT -256   /* tell ficlExecXT to exit inner loop */
502 #define VM_OUTOFTEXT -257   /* hungry - normal exit */
503 #define VM_RESTART   -258   /* word needs more text to succeed - re-run it */
504 #define VM_USEREXIT  -259   /* user wants to quit */
505 #define VM_ERREXIT   -260   /* interp found an error */
506 #define VM_ABORT       -1   /* like errexit -- abort */
507 #define VM_ABORTQ      -2   /* like errexit -- abort" */
508 #define VM_QUIT       -56   /* like errexit, but leave pStack & base alone */
509
510
511 void        vmBranchRelative(FICL_VM *pVM, int offset);
512 FICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
513 void        vmDelete (FICL_VM *pVM);
514 void        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
515 char *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
516 STRINGINFO  vmGetWord(FICL_VM *pVM);
517 STRINGINFO  vmGetWord0(FICL_VM *pVM);
518 int         vmGetWordToPad(FICL_VM *pVM);
519 STRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
520 STRINGINFO  vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
521 CELL        vmPop(FICL_VM *pVM);
522 void        vmPush(FICL_VM *pVM, CELL c);
523 void        vmPopIP  (FICL_VM *pVM);
524 void        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
525 void        vmQuit   (FICL_VM *pVM);
526 void        vmReset  (FICL_VM *pVM);
527 void        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
528 #if FICL_WANT_DEBUGGER
529 void        vmStep(FICL_VM *pVM);
530 #endif
531 void        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
532 void        vmThrow  (FICL_VM *pVM, int except);
533 void        vmThrowErr(FICL_VM *pVM, char *fmt, ...);
534
535 #define vmGetRunningWord(pVM) ((pVM)->runningWord)
536
537
538 /*
539 ** The inner interpreter - coded as a macro (see note for 
540 ** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
541 */
542 #define M_VM_STEP(pVM) \
543         FICL_WORD *tempFW = *(pVM)->ip++; \
544         (pVM)->runningWord = tempFW; \
545         tempFW->code(pVM); \
546
547 #define M_INNER_LOOP(pVM) \
548     for (;;)  { M_VM_STEP(pVM) }
549
550
551 #if INLINE_INNER_LOOP != 0
552 #define     vmInnerLoop(pVM) M_INNER_LOOP(pVM)
553 #else
554 void        vmInnerLoop(FICL_VM *pVM);
555 #endif
556
557 /*
558 ** vmCheckStack needs a vm pointer because it might have to say
559 ** something if it finds a problem. Parms popCells and pushCells
560 ** correspond to the number of parameters on the left and right of 
561 ** a word's stack effect comment.
562 */
563 void        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
564
565 /*
566 ** TIB access routines...
567 ** ANS forth seems to require the input buffer to be represented 
568 ** as a pointer to the start of the buffer, and an index to the
569 ** next character to read.
570 ** PushTib points the VM to a new input string and optionally
571 **  returns a copy of the current state
572 ** PopTib restores the TIB state given a saved TIB from PushTib
573 ** GetInBuf returns a pointer to the next unused char of the TIB
574 */
575 void        vmPushTib(FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib);
576 void        vmPopTib(FICL_VM *pVM, TIB *pTib);
577 #define     vmGetInBuf(pVM) ((pVM)->tib.cp + (pVM)->tib.index)
578 #define     vmGetInBufLen(pVM) ((pVM)->tib.end - (pVM)->tib.cp)
579 #define     vmGetInBufEnd(pVM) ((pVM)->tib.end)
580 #define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
581 #define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp
582
583 /*
584 ** Generally useful string manipulators omitted by ANSI C...
585 ** ltoa complements strtol
586 */
587 #if defined(_WIN32) && !FICL_MAIN
588 /* #SHEESH
589 ** Why do Microsoft Meatballs insist on contaminating
590 ** my namespace with their string functions???
591 */
592 #pragma warning(disable: 4273)
593 #endif
594
595 int        isPowerOfTwo(FICL_UNS u);
596
597 char       *ltoa( FICL_INT value, char *string, int radix );
598 char       *ultoa(FICL_UNS value, char *string, int radix );
599 char        digit_to_char(int value);
600 char       *strrev( char *string );
601 char       *skipSpace(char *cp, char *end);
602 char       *caseFold(char *cp);
603 int         strincmp(char *cp1, char *cp2, FICL_COUNT count);
604
605 #if defined(_WIN32) && !FICL_MAIN
606 #pragma warning(default: 4273)
607 #endif
608
609 /*
610 ** Ficl hash table - variable size.
611 ** assert(size > 0)
612 ** If size is 1, the table degenerates into a linked list.
613 ** A WORDLIST (see the search order word set in DPANS) is
614 ** just a pointer to a FICL_HASH in this implementation.
615 */
616 #if !defined HASHSIZE /* Default size of hash table. For most uniform */
617 #define HASHSIZE 127  /*   performance, use a prime number!   */
618 #endif
619
620 typedef struct ficl_hash 
621 {
622     struct ficl_hash *link;  /* eventual inheritance support */
623     unsigned   size;
624     FICL_WORD *table[1];
625 } FICL_HASH;
626
627 void        hashForget(FICL_HASH *pHash, void *where);
628 UNS16       hashHashCode(STRINGINFO si);
629 void        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
630 FICL_WORD  *hashLookup(struct ficl_hash *pHash, 
631                        STRINGINFO si, 
632                        UNS16 hashCode);
633 void        hashReset(FICL_HASH *pHash);
634
635 /*
636 ** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
637 ** memory model. Description of fields:
638 **
639 ** here -- points to the next free byte in the dictionary. This
640 **      pointer is forced to be CELL-aligned before a definition is added.
641 **      Do not assume any specific alignment otherwise - Use dictAlign().
642 **
643 ** smudge -- pointer to word currently being defined (or last defined word)
644 **      If the definition completes successfully, the word will be
645 **      linked into the hash table. If unsuccessful, dictUnsmudge
646 **      uses this pointer to restore the previous state of the dictionary.
647 **      Smudge prevents unintentional recursion as a side-effect: the
648 **      dictionary search algo examines only completed definitions, so a 
649 **      word cannot invoke itself by name. See the ficl word "recurse".
650 **      NOTE: smudge always points to the last word defined. IMMEDIATE
651 **      makes use of this fact. Smudge is initially NULL.
652 **
653 ** pForthWords -- pointer to the default wordlist (FICL_HASH).
654 **      This is the initial compilation list, and contains all
655 **      ficl's precompiled words.
656 **
657 ** pCompile -- compilation wordlist - initially equal to pForthWords
658 ** pSearch  -- array of pointers to wordlists. Managed as a stack.
659 **      Highest index is the first list in the search order.
660 ** nLists   -- number of lists in pSearch. nLists-1 is the highest 
661 **      filled slot in pSearch, and points to the first wordlist
662 **      in the search order
663 ** size -- number of cells in the dictionary (total)
664 ** dict -- start of data area. Must be at the end of the struct.
665 */
666 typedef struct ficl_dict
667 {
668     CELL *here;
669     FICL_WORD *smudge;
670     FICL_HASH *pForthWords;
671     FICL_HASH *pCompile;
672     FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
673     int        nLists;
674     unsigned   size;    /* Number of cells in dict (total)*/
675     CELL       *dict;   /* Base of dictionary memory      */
676 } FICL_DICT;
677
678 void       *alignPtr(void *ptr);
679 void        dictAbortDefinition(FICL_DICT *pDict);
680 void        dictAlign(FICL_DICT *pDict);
681 int         dictAllot(FICL_DICT *pDict, int n);
682 int         dictAllotCells(FICL_DICT *pDict, int nCells);
683 void        dictAppendCell(FICL_DICT *pDict, CELL c);
684 void        dictAppendChar(FICL_DICT *pDict, char c);
685 FICL_WORD  *dictAppendWord(FICL_DICT *pDict, 
686                            char *name, 
687                            FICL_CODE pCode, 
688                            UNS8 flags);
689 FICL_WORD  *dictAppendWord2(FICL_DICT *pDict, 
690                            STRINGINFO si, 
691                            FICL_CODE pCode, 
692                            UNS8 flags);
693 void        dictAppendUNS(FICL_DICT *pDict, FICL_UNS u);
694 int         dictCellsAvail(FICL_DICT *pDict);
695 int         dictCellsUsed (FICL_DICT *pDict);
696 void        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
697 FICL_DICT  *dictCreate(unsigned nCELLS);
698 FICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
699 void        dictDelete(FICL_DICT *pDict);
700 void        dictEmpty(FICL_DICT *pDict, unsigned nHash);
701 int         dictIncludes(FICL_DICT *pDict, void *p);
702 FICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
703 #if FICL_WANT_LOCALS
704 FICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
705 #endif
706 void        dictResetSearchOrder(FICL_DICT *pDict);
707 void        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
708 void        dictSetImmediate(FICL_DICT *pDict);
709 void        dictUnsmudge(FICL_DICT *pDict);
710 CELL       *dictWhere(FICL_DICT *pDict);
711
712
713 /*
714 ** External interface to FICL...
715 */
716 /* 
717 ** f i c l I n i t S y s t e m
718 ** Binds a global dictionary to the interpreter system and initializes
719 ** the dict to contain the ANSI CORE wordset. 
720 ** You specify the address and size of the allocated area.
721 ** After that, ficl manages it.
722 ** First step is to set up the static pointers to the area.
723 ** Then write the "precompiled" portion of the dictionary in.
724 ** The dictionary needs to be at least large enough to hold the
725 ** precompiled part. Try 1K cells minimum. Use "words" to find
726 ** out how much of the dictionary is used at any time.
727 */
728 void       ficlInitSystem(int nDictCells);
729
730 /*
731 ** f i c l T e r m S y s t e m
732 ** Deletes the system dictionary and all virtual machines that
733 ** were created with ficlNewVM (see below). Call this function to
734 ** reclaim all memory used by the dictionary and VMs.
735 */
736 void       ficlTermSystem(void);
737
738 /*
739 ** f i c l E x e c
740 ** Evaluates a block of input text in the context of the
741 ** specified interpreter. Emits any requested output to the
742 ** interpreter's output function. If the input string is NULL
743 ** terminated, you can pass -1 as nChars rather than count it.
744 ** Execution returns when the text block has been executed,
745 ** or an error occurs.
746 ** Returns one of the VM_XXXX codes defined in ficl.h:
747 ** VM_OUTOFTEXT is the normal exit condition
748 ** VM_ERREXIT means that the interp encountered a syntax error
749 **      and the vm has been reset to recover (some or all
750 **      of the text block got ignored
751 ** VM_USEREXIT means that the user executed the "bye" command
752 **      to shut down the interpreter. This would be a good
753 **      time to delete the vm, etc -- or you can ignore this
754 **      signal.
755 ** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
756 **      commands.
757 ** Preconditions: successful execution of ficlInitSystem,
758 **      Successful creation and init of the VM by ficlNewVM (or equiv)
759 */
760 int        ficlExec (FICL_VM *pVM, char *pText);
761 int        ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars);
762 int        ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord);
763
764 /*
765 ** ficlExecFD(FICL_VM *pVM, int fd);
766  * Evaluates text from file passed in via fd.
767  * Execution returns when all of file has been executed or an
768  * error occurs.
769  */
770 int        ficlExecFD(FICL_VM *pVM, int fd);
771
772 /*
773 ** Create a new VM from the heap, and link it into the system VM list.
774 ** Initializes the VM and binds default sized stacks to it. Returns the
775 ** address of the VM, or NULL if an error occurs.
776 ** Precondition: successful execution of ficlInitSystem
777 */
778 FICL_VM   *ficlNewVM(void);
779
780 /*
781 ** Force deletion of a VM. You do not need to do this 
782 ** unless you're creating and discarding a lot of VMs.
783 ** For systems that use a constant pool of VMs for the life
784 ** of the system, ficltermSystem takes care of VM cleanup
785 ** automatically.
786 */
787 void ficlFreeVM(FICL_VM *pVM);
788
789
790 /*
791 ** Set the stack sizes (return and parameter) to be used for all
792 ** subsequently created VMs. Returns actual stack size to be used.
793 */
794 int ficlSetStackSize(int nStackCells);
795
796 /*
797 ** Returns the address of the most recently defined word in the system
798 ** dictionary with the given name, or NULL if no match.
799 ** Precondition: successful execution of ficlInitSystem
800 */
801 FICL_WORD *ficlLookup(char *name);
802
803 /*
804 ** f i c l G e t D i c t
805 ** Utility function - returns the address of the system dictionary.
806 ** Precondition: successful execution of ficlInitSystem
807 */
808 FICL_DICT *ficlGetDict(void);
809 FICL_DICT *ficlGetEnv(void);
810 void       ficlSetEnv(char *name, FICL_UNS value);
811 void       ficlSetEnvD(char *name, FICL_UNS hi, FICL_UNS lo);
812 #if FICL_WANT_LOCALS
813 FICL_DICT *ficlGetLoc(void);
814 #endif
815 /* 
816 ** f i c l B u i l d
817 ** Builds a word into the system default dictionary in a thread-safe way.
818 ** Preconditions: system must be initialized, and there must
819 ** be enough space for the new word's header! Operation is
820 ** controlled by ficlLockDictionary, so any initialization
821 ** required by your version of the function (if you "overrode"
822 ** it) must be complete at this point.
823 ** Parameters:
824 ** name  -- the name of the word to be built
825 ** code  -- code to execute when the word is invoked - must take a single param
826 **          pointer to a FICL_VM
827 ** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 
828 **          Most words can use FW_DEFAULT.
829 ** nAllot - number of extra cells to allocate in the parameter area (usually zero)
830 */
831 int        ficlBuild(char *name, FICL_CODE code, char flags);
832
833 /* 
834 ** f i c l C o m p i l e C o r e
835 ** Builds the ANS CORE wordset into the dictionary - called by
836 ** ficlInitSystem - no need to waste dict space by doing it again.
837 */
838 void       ficlCompileCore(FICL_DICT *dp);
839 void       ficlCompileSoftCore(FICL_VM *pVM);
840
841 /*
842 ** from words.c...
843 */
844 void       constantParen(FICL_VM *pVM);
845 void       twoConstParen(FICL_VM *pVM);
846
847 /*
848 ** Dictionary on-demand resizing
849 */
850 extern unsigned int dictThreshold;
851 extern unsigned int dictIncrease;
852
853 /*
854 ** So we can more easily debug...
855 */
856 #ifdef FICL_TRACE
857 extern int ficl_trace;
858 #endif
859
860 /*
861 ** Various FreeBSD goodies
862 */
863
864 #if defined(__i386__) && !defined(TESTMAIN)
865 extern void ficlOutb(FICL_VM *pVM);
866 extern void ficlInb(FICL_VM *pVM);
867 #endif
868
869 #if !defined(TESTMAIN)
870 extern void ficlSetenv(FICL_VM *pVM);
871 extern void ficlSetenvq(FICL_VM *pVM);
872 extern void ficlGetenv(FICL_VM *pVM);
873 extern void ficlUnsetenv(FICL_VM *pVM);
874 extern void ficlCopyin(FICL_VM *pVM);
875 extern void ficlCopyout(FICL_VM *pVM);
876 #endif
877
878 #ifdef __cplusplus
879 }
880 #endif
881
882 #endif /* __FICL_H__ */