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