ficl.h revision 61149
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: head/sys/boot/ficl/ficl.h 61149 2000-06-01 18:10:44Z dcs $ */
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
206extern "C" {
207#endif
208
209#include "sysdep.h"
210#include <limits.h> /* UCHAR_MAX */
211
212/*
213** Forward declarations... read on.
214*/
215struct ficl_word;
216struct vm;
217struct 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*/
242typedef 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
274typedef unsigned char FICL_COUNT;
275#define FICL_STRING_MAX UCHAR_MAX
276typedef struct _ficl_string
277{
278    FICL_COUNT count;
279    char text[1];
280} FICL_STRING;
281
282typedef struct
283{
284    UNS32 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 = (UNS32)(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*/
317typedef 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*/
334typedef 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*/
345FICL_STACK *stackCreate(unsigned nCells);
346void        stackDelete(FICL_STACK *pStack);
347int         stackDepth (FICL_STACK *pStack);
348void        stackDrop  (FICL_STACK *pStack, int n);
349CELL        stackFetch (FICL_STACK *pStack, int n);
350CELL        stackGetTop(FICL_STACK *pStack);
351void        stackLink  (FICL_STACK *pStack, int nCells);
352void        stackPick  (FICL_STACK *pStack, int n);
353CELL        stackPop   (FICL_STACK *pStack);
354void       *stackPopPtr   (FICL_STACK *pStack);
355FICL_UNS    stackPopUNS(FICL_STACK *pStack);
356FICL_INT    stackPopINT(FICL_STACK *pStack);
357void        stackPush  (FICL_STACK *pStack, CELL c);
358void        stackPushPtr  (FICL_STACK *pStack, void *ptr);
359void        stackPushUNS(FICL_STACK *pStack, FICL_UNS u);
360void        stackPushINT(FICL_STACK *pStack, FICL_INT i);
361void        stackReset (FICL_STACK *pStack);
362void        stackRoll  (FICL_STACK *pStack, int n);
363void        stackSetTop(FICL_STACK *pStack, CELL c);
364void        stackStore (FICL_STACK *pStack, int n, CELL c);
365void        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
379typedef 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*/
387typedef 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*/
418typedef 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    UNS32           state;      /* compiling or interpreting        */
429    UNS32           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*/
451typedef 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*/
467typedef 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
485int wordIsImmediate(FICL_WORD *pFW);
486int 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
511void        vmBranchRelative(FICL_VM *pVM, int offset);
512FICL_VM *   vmCreate (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
513void        vmDelete (FICL_VM *pVM);
514void        vmExecute(FICL_VM *pVM, FICL_WORD *pWord);
515char *      vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
516STRINGINFO  vmGetWord(FICL_VM *pVM);
517STRINGINFO  vmGetWord0(FICL_VM *pVM);
518int         vmGetWordToPad(FICL_VM *pVM);
519STRINGINFO  vmParseString(FICL_VM *pVM, char delimiter);
520STRINGINFO  vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
521CELL        vmPop(FICL_VM *pVM);
522void        vmPush(FICL_VM *pVM, CELL c);
523void        vmPopIP  (FICL_VM *pVM);
524void        vmPushIP (FICL_VM *pVM, IPTYPE newIP);
525void        vmQuit   (FICL_VM *pVM);
526void        vmReset  (FICL_VM *pVM);
527void        vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
528#if FICL_WANT_DEBUGGER
529void        vmStep(FICL_VM *pVM);
530#endif
531void        vmTextOut(FICL_VM *pVM, char *text, int fNewline);
532void        vmThrow  (FICL_VM *pVM, int except);
533void        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
554void        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*/
563void        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*/
575void        vmPushTib(FICL_VM *pVM, char *text, INT32 nChars, TIB *pSaveTib);
576void        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
595int        isPowerOfTwo(FICL_UNS u);
596
597char       *ltoa( FICL_INT value, char *string, int radix );
598char       *ultoa(FICL_UNS value, char *string, int radix );
599char        digit_to_char(int value);
600char       *strrev( char *string );
601char       *skipSpace(char *cp, char *end);
602char       *caseFold(char *cp);
603int         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
620typedef struct ficl_hash
621{
622    struct ficl_hash *link;  /* eventual inheritance support */
623    unsigned   size;
624    FICL_WORD *table[1];
625} FICL_HASH;
626
627void        hashForget(FICL_HASH *pHash, void *where);
628UNS16       hashHashCode(STRINGINFO si);
629void        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
630FICL_WORD  *hashLookup(struct ficl_hash *pHash,
631                       STRINGINFO si,
632                       UNS16 hashCode);
633void        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*/
666typedef 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
678void       *alignPtr(void *ptr);
679void        dictAbortDefinition(FICL_DICT *pDict);
680void        dictAlign(FICL_DICT *pDict);
681int         dictAllot(FICL_DICT *pDict, int n);
682int         dictAllotCells(FICL_DICT *pDict, int nCells);
683void        dictAppendCell(FICL_DICT *pDict, CELL c);
684void        dictAppendChar(FICL_DICT *pDict, char c);
685FICL_WORD  *dictAppendWord(FICL_DICT *pDict,
686                           char *name,
687                           FICL_CODE pCode,
688                           UNS8 flags);
689FICL_WORD  *dictAppendWord2(FICL_DICT *pDict,
690                           STRINGINFO si,
691                           FICL_CODE pCode,
692                           UNS8 flags);
693void        dictAppendUNS(FICL_DICT *pDict, FICL_UNS u);
694int         dictCellsAvail(FICL_DICT *pDict);
695int         dictCellsUsed (FICL_DICT *pDict);
696void        dictCheck(FICL_DICT *pDict, FICL_VM *pVM, int nCells);
697FICL_DICT  *dictCreate(unsigned nCELLS);
698FICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
699void        dictDelete(FICL_DICT *pDict);
700void        dictEmpty(FICL_DICT *pDict, unsigned nHash);
701int         dictIncludes(FICL_DICT *pDict, void *p);
702FICL_WORD  *dictLookup(FICL_DICT *pDict, STRINGINFO si);
703#if FICL_WANT_LOCALS
704FICL_WORD  *dictLookupLoc(FICL_DICT *pDict, STRINGINFO si);
705#endif
706void        dictResetSearchOrder(FICL_DICT *pDict);
707void        dictSetFlags(FICL_DICT *pDict, UNS8 set, UNS8 clr);
708void        dictSetImmediate(FICL_DICT *pDict);
709void        dictUnsmudge(FICL_DICT *pDict);
710CELL       *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*/
728void       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*/
736void       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*/
760int        ficlExec (FICL_VM *pVM, char *pText);
761int        ficlExecC(FICL_VM *pVM, char *pText, INT32 nChars);
762int        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 */
770int        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*/
778FICL_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*/
787void 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*/
794int 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*/
801FICL_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*/
808FICL_DICT *ficlGetDict(void);
809FICL_DICT *ficlGetEnv(void);
810void       ficlSetEnv(char *name, UNS32 value);
811void       ficlSetEnvD(char *name, UNS32 hi, UNS32 lo);
812#if FICL_WANT_LOCALS
813FICL_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*/
831int        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*/
838void       ficlCompileCore(FICL_DICT *dp);
839void       ficlCompileSoftCore(FICL_VM *pVM);
840
841/*
842** from words.c...
843*/
844void       constantParen(FICL_VM *pVM);
845void       twoConstParen(FICL_VM *pVM);
846
847/*
848** Dictionary on-demand resizing
849*/
850extern unsigned int dictThreshold;
851extern unsigned int dictIncrease;
852
853/*
854** So we can more easily debug...
855*/
856#ifdef FICL_TRACE
857extern int ficl_trace;
858#endif
859
860#if defined(__i386__) && !defined(TESTMAIN)
861extern void ficlOutb(FICL_VM *pVM);
862extern void ficlInb(FICL_VM *pVM);
863#endif
864
865#ifdef __cplusplus
866}
867#endif
868
869#endif /* __FICL_H__ */
870